Files
comun/docs/conventie_goexecutor_alter_table.md

66 lines
2.7 KiB
Markdown

# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
## Ce nu funcționează
```foxpro
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
...
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
```
Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL
ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO
`autopass_cursor_comenzi`/`autopass_cursor_operatii`):
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul
original.
2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR
(acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot
avea același nume într-un `SELECT...INTO CURSOR`).
3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR
(nume_final_diferit_de_sursa) READWRITE`) → tot `Invalid operation for the cursor.` pe
`ALTER TABLE`, chiar dacă acum cursorul final teoretic ar trebui să fie unul local
obișnuit.
Nu există niciun alt loc în codul ROA* care să facă `ALTER TABLE` imediat după
`goExecutor.oExecute()` — deci acest pattern nu avea niciun precedent testat înainte de
funcțiile AUTOPASS.
## Ce funcționează
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
```foxpro
lcCursorRaw = lcCursor + '_raw'
IF USED(lcCursorRaw)
USE IN (lcCursorRaw)
ENDIF
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
IF lnSucces < 0
* tratare eroare, RETURN
ENDIF
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
USE IN (lcCursorRaw)
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
```
După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează
normal pe el DUPĂ ACEEA (ex. dintr-o altă funcție care primește cursorul deja gata construit,
nu direct rezultatul unui `oExecute`), doar comanda imediat următoare unui `oExecute()` e
restricționată.
## Vezi și
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.