Files
comun/docs/conventie_goexecutor_alter_table.md

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):

  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 ...):

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().