Files
comun/skills/roa-vfp-null-guards/SKILL.md
Marius Mutu d64124386c skills: 9 skill-uri de agent ROA (COMUN\skills) + legare si rutare
- leaga_skills.ps1: expune skill-urile in ~/.claude/skills prin symlink (citit si de Claude Code, si de opencode), fara copiere
- rutare zona->skill in reguli_lucru pct. 7, README, AGENTS.md; skill-ul devine proprietarul procedurii, docurile raman referinta conditionata
- rec_skills.md: decizia, inventarul si cum se adauga un skill nou
2026-09-16 11:54:37 +03:00

4.0 KiB

name: roa-vfp-null-guards description: Scrie si verifica garzile pe valorile NULL venite din Oracle in cod VFP (campuri de cursor, comparatii, Empty(), NVL, ISNULL). Foloseste-l OBLIGATORIU cand scrii sau revezi cod VFP care compara, valideaza sau concateneaza valori din Oracle; cand apare "valoare NULL din Oracle", "Empty() da rezultat gresit", "coloana poate fi null", "SQL statement parameter is required for non-prepared SQLEXEC() calls" sau rezultate gresite/erori inselatoare pe coloane care pot fi NULL. Se declanseaza si cand NU se rosteste cuvantul "NULL": daca doar compari, validezi sau construiesti text/SQL din campuri de cursor Oracle, regula se aplica. O singura regula, dar platita scump - fara garda rezultatul e gresit sau eroarea apare departe de cauza.

Garzi pe valorile NULL venite din Oracle

Un camp de cursor intors de Oracle poate fi .NULL.. In VFP EMPTY(.NULL.) intoarce .F., comparatia cu NULL nu e nici adevarata nici eroare, iar concatenarea cu + face tot sirul .NULL.. O garda gresita nu da eroare: da rezultat gresit, tacit.

Cand se foloseste

  • Scrii sau revezi cod VFP care citeste, compara sau valideaza campuri de cursor Oracle.
  • Folosesti Empty(), Nvl(), IsNull() sau Type() pe o valoare de cursor.
  • Construiesti text, SQL, mesaje sau chei prin + din campuri de cursor.
  • Adaugi o interogare sau o coloana noua si nu esti sigur daca poate fi NULL.
  • Simptom: rezultat gresit fara eroare, sau SQL statement parameter is required for non-prepared SQLEXEC() calls in OEXECUTOR.OEXECUTE.

Regula

Tipul se evalueaza PRIMUL, ca sa opreasca acolo, iar Nvl(...) se aplica INAUNTRUL lui Empty() sau al comparatiei - niciodata pe langa. Un singur camp NULL anuleaza tot sirul construit prin +, deci fiecare camp il primeste.

* GRESIT: Empty() singur nu prinde NULL; comparatia cu NULL e falsa; sirul devine .NULL.
If Empty(tcCont)
	Return
Endif
tcSql = 'Where cont = ' + tcCont

* CORECT: Type() opreste primul, Nvl(...) sta in interiorul lui Empty() / comparatiei
If Type('tcCont') # 'C' Or Empty(Nvl(tcCont, ''))
	Return
Endif
If Type('tdData') # 'D' Or Empty(Nvl(tdData, {}))
	Return
Endif
If Nvl(tcStare, '') == 'A'
	Return
Endif
tcSql = 'Where cont = ' + Nvl(tcCont, '')

Capcane

  • EMPTY(.NULL.) este .F., deci Empty() singur NU prinde NULL - nici pe text, nici pe data.
  • IsNull(x) Or Empty(x) e forma lunga si usor de uitat pe o ramura; Empty(Nvl(x, '')) e forma unica, greu de scris gresit.
  • TYPE() pe o variabila caracter cu NULL intoarce tot 'C' - nu tine loc de Nvl, doar prinzi tipul neasteptat cu el.
  • Concatenarea prin + cu un camp NULL anuleaza tot sirul; eroarea apare departe, la SQLEXEC, nu la linia care l-a construit.
  • NVL(col, '') in interogarea Oracle mascheaza NULL-ul in SELECT, dar nu repara codul care primeste deja cursorul - garda ramane in VFP.
  • Nvl(x, '') pe un camp numeric/date da conversie gresita: valoarea implicita trebuie sa aiba acelasi tip ({}, 0).

Criterii de acceptare si dovada

Fara dovada da/nu de mai jos, garda NU se raporteaza ca pusa. "Arata bine" nu e dovada.

  1. Dovada ca valoarea chiar poate fi NULL (nu doar goala), pe datele de test: SELECT SUM(CASE WHEN <coloana> IS NULL THEN 1 ELSE 0 END) FROM <tabel> -> rezultat > 0.
  2. Test headless pereche: pe cursorul cu NULL, garda corectata da exact acelasi rezultat ca pe valoarea goala. Dovada = ambele cazuri trecute, cod de iesire 0.
  3. Assert care cade fara fix: ruleaza testul si pe varianta fara Nvl - trebuie sa esueze; un test care trece in ambele variante nu dovedeste nimic.
  4. Garduri ramase neacoperite in functia atinsa: grep -n "Empty(" <fisier.prg> -> fiecare aparitie are Nvl( in interior; grep -n "' + " <fisier.prg> -> fiecare camp de cursor are Nvl( inainte de +.

Referinta (doar la nevoie)

  • D:\ROA\ROAFACTURARE\COMUN\docs\conventie_null_vfp.md - contextul complet si simptomul SQLEXEC, daca iti trebuie dupa ce ai aplicat regula.