Squash al branch-ului de lucru plan13-s2. Clase: ofacturare (nucleul formularului unificat), ofacturare_comun, ferestre_cere_date, ocomenzi, caut_ora (lista de preturi in combo-urile de cautare), omodificari. Programe: ofacturare impartit - ofacturare_antet, ofacturare_rutare_scriere si ogrid_latimi sunt fisiere noi; oproceduri_facturare primeste discountul pe linie si cota standard de TVA cand articolul nu are cota pe politica. Documentatie: capcana SQLExec no_data_found, conventia de encoding, depanarea testelor VFP si regulile de lucru - conflictele cu modificarile venite din alte proiecte sunt rezolvate pastrand ambele parti. Loguri de rulare a testelor scoase din versionare; testele raman. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
2.2 KiB
Capcana: linii pierdute tacut intre VFP si Oracle
Simptomul
Un document se salveaza cu mai putine linii decat are pe ecran. Fara mesaj, fara eroare, fara nimic in log. Totalurile ies mai mici, dar consistente intre ele - deci nu arata a defect.
Mecanismul, in doi pasi
- Un
SELECT ... INTOfara handler intr-o procedura PL/SQL aruncaORA-01403(NO_DATA_FOUND) cand predicatul nu potriveste niciun rand. - ODBC il traduce ca
SQL_NO_DATA, siSQLExec()intoarce 1, adica succes. Bucla din VFP testeazaIf lnSucces < 0si nu vede nimic. Linia dispare fara urma.
Deci: eroare reala in Oracle -> succes raportat in VFP.
De ce nu potriveste predicatul (cauza uzuala)
Santinela pusa doar pe coloana, nu si pe parametru:
AND NVL(A.CONT, 'XXXX') = V_CONT
VFP trimite sir gol pentru campul necompletat, iar in Oracle sirul gol este NULL; 'XXXX' = NULL
da UNKNOWN, deci zero randuri. Corect e pe amandoua:
AND NVL(A.CONT, 'XXXX') = NVL(V_CONT, 'XXXX')
Pe ID_GESTIUNE acelasi tipar merge, fiindca acolo VFP chiar trimite santinela -1000.
Cauza inrudita, acelasi simptom: un camp lipsa din lista de insert a cursorului, pe o coloana
numerica fara NULL - ramane 0 tacit, nu NULL si nu eroare, si predicatul cade pe 0.
Ce se face, in ordinea asta
- Intai garda, apoi cauza. Infasoara
SELECT ... INTOinBEGIN ... EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20000, '... (FACT-0xx : ' || <cheia> || ')'). Fara ea, orice reparatie de cauza ramane neverificabila: mecanismul care ascunde defectul e inca acolo. CodulFACT-0xxse cauta liber inUSER_SOURCE, nu se presupune ca e liber. - Abia apoi simetrizeaza predicatul.
- Asertiune pe NUMARUL DE LINII in testul de flux. Exact piesa care lipsea: identitatea documentului si legaturile lui se pastrau corect, deci toate asertiunile existente treceau.
Cum se cauta preventiv
In USER_SOURCE: fiecare SELECT ... INTO fara EXCEPTION in ramura lui, si fiecare predicat de
forma NVL(<coloana>, <santinela>) = <parametru>.
Precedent: PACK_FACTURARE.adauga_articol_factura, ramura ntip = 4 (facturare din avize) - un
document reemis cu 2 linii din 4, nedetectat de doua sweep-uri la rand. Reparat 04.09.2026 cu
FACT-030.