2.7 KiB
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ă
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):
Function is not supported on remote tables.— peALTER TABLEdirect pe cursorul original.- 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-unSELECT...INTO CURSOR). - Cu un alias scratch diferit ca țintă (
SELECT * FROM (cursor) INTO CURSOR (nume_final_diferit_de_sursa) READWRITE) → totInvalid operation for the cursor.peALTER 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 ...):
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().