Files
ROMFASTSQL/docs/lectii-actualizare-roa-alias-tns.md
Marius 91e822eb53 fix(export): aliasul TNS lipsa facea exportul zilnic sa esueze tacut
La VADECO, backupora.exe rula in fiecare noapte, se termina cu cod 0 si scria
"DONE" pentru fiecare schema - dar directorul zilei ramanea gol. Intre 25 si
28.08.2026 nu a existat niciun export.

Cauza: schema.txt cere "@XEPDB1", iar 01-setup-database.ps1 scria in tnsnames.ora
doar aliasul ROA. expdp cadea instant cu ORA-12154, iar backupora.exe nu-i
verifica codul de iesire. Doua scripturi din acelasi kit nu erau de acord asupra
numelui bazei, si nimic nu tipa.

Indiciul din log, daca reapare: fiecare schema dura exact 16 secunde, indiferent
de marime. Timp uniform = expdp moare la conectare, nu exporta.

Reparatii, ca sa nu se repete la alt client:

- 01-setup-database.ps1 scrie acum doua aliasuri, ROA si numele serviciului,
  in ambele tnsnames.ora. Curatarea dinaintea rescrierii parcurge fiecare alias
  gestionat de noi, altfel al doilea s-ar dubla la fiecare rulare. Aliasurile
  generate de Oracle (XE, LISTENER_XE, ORACLR_CONNECTION_DATA) raman neatinse.

- 11-setup-backup-export.ps1 face tnsping inainte de a scrie schema.txt si
  opreste instalarea daca aliasul nu se rezolva. Mai bine o instalare care se
  plange decat un backup care nu exista.

- lectii-actualizare-roa-alias-tns.md capata sectiunea despre a doua victima a
  aceleiasi cauze. Lectia generala: unde un script lanseaza un proces extern
  Oracle, verifica efectul, nu raportul procesului care l-a lansat.

Include si blocul NTS din config/sqlnet.ora, ramas necomis: autentificarea OS
cere si apartenenta la ORA_OraDB21Home1_DBA, si setarea din sqlnet.ora.

Nota: CLAUDE.md apare ca modificat integral - blob-ul din git avea CRLF, iar
core.autocrlf=true il normalizeaza la LF. Modificarea reala e o singura linie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9Sa54oFKpE2XhD6A7NTch
2026-08-28 17:12:41 +03:00

9.7 KiB

Actualizarea ROA eșuează tăcut fără aliasul TNS pe server

Constatat la VADECO, 2026-08-28. Pe serverul acela actualizarea ROA nu aplicase niciodată un script, deși jobul raporta succes de la instalare. Aceeași defecțiune apare la orice client instalat cu kitul înainte de corecția din 01-setup-database.ps1.

Simptomul

DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATEROA_ZILNIC') se termină în ~5-7 secunde și dba_scheduler_job_run_details arată SUCCEEDED, error#=0. Dar:

  • nicio schemă nu primește scripturi noi;
  • CONTAFIN_ORACLE.UPD_ISTORIC rămâne cu un rând stare=2 deschis (fără dataora_end), care blochează rularea următoare;
  • SCHEMA.versiune nu capătă rânduri noi.

De ce jobul minte

PACK_UPDATE nu aplică el scripturile. El generează D:\DMPDIR\script_master.sql și lansează un sqlplus.exe extern, apoi se termină. Jobul raportează starea lansării, nu a actualizării. Scriptul generat începe așa:

SET AUTOPRINT OFF
WHENEVER SQLERROR EXIT SQL.SQLCODE
SPOOL D:\DMPDIR\script_master.log
CONNECT CONTAFIN_ORACLE/<parola>@ROA

Aliasul (ROA) vine din CONTAFIN_ORACLE.NOM_FIRME.NUME_SERVER. Cu WHENEVER SQLERROR EXIT, dacă aliasul nu se rezolvă scriptul iese la prima linie și nu face absolut nimic — tăcut, pentru că singura urmă e în spool.

Eșecul e mascat dublu: jobul zice SUCCEEDED, iar raportarea pe email e oricum nefuncțională (ORA-29279: 503 AUTH command used when not advertised — vezi docs/handoff_vadeco-update-roa.md).

De ce nu se rezolvă aliasul

sqlplus-ul lansat de bază moștenește mediul serviciului Oracle, nu pe al utilizatorului conectat. Lanțul, la o instalare nouă:

  1. Instalarea pornește instanța. În acel moment TNS_ADMIN nu există încă la nivel de mașină.
  2. 01-setup-database.ps1 scrie apoi TNS_ADMIN (spre D:\ROA\instantclient_11_2_0_2) și pune aliasul ROA acolo.
  3. Serviciul Oracle rulează în continuare cu mediul de la pasul 1 — fără TNS_ADMIN. Efectul variabilei apare abia la primul restart al serviciului.
  4. Deci sqlplus-ul lansat de bază caută tnsnames.ora în Oracle Home.
  5. Oracle 21c XE folosește read-only Oracle Home: fișierul real e în ...\product\21c\homes\OraDB21Home1\network\admin\, nu în dbhomeXE\network\admin\ (acolo e doar sqlnet.ora.rooh).
  6. Fișierul acela e generat de Oracle și conține XE, LISTENER_XE, ORACLR_CONNECTION_DATA — dar nu ROA. → ORA-12154.

Capcana perfidă: tnsping ROA reușește dintr-o sesiune interactivă, pentru că sesiunea ta are TNS_ADMIN. Nimic nu pare greșit până nu te uiți în spool.

Diagnostic în 30 de secunde

Citește spool-ul — el are adevărul, nu jobul:

Get-Content D:\DMPDIR\script_master.log

Un eșec arată exact așa (fișier de ~100 de octeți):

28/08/2026 14:26:59
ERROR:
ORA-12154: TNS:could not resolve the connect identifier specified

Reproducere deterministă, în mediul în care rulează baza (fără TNS_ADMIN):

Remove-Item Env:TNS_ADMIN -ErrorAction SilentlyContinue
"exit" | & "$oraHome\bin\sqlplus.exe" -L -S "CONTAFIN_ORACLE/<parola>@ROA"

ORA-12154 ⇒ actualizarea ROA nu a funcționat niciodată pe serverul acela.

Reparația

Aliasul trebuie să existe și în tnsnames.ora al Oracle Home-ului, nu doar în cel din TNS_ADMIN. Din 2026-08-28, 01-setup-database.ps1 îl scrie în ambele locuri, cu același IP din LAN.

Manual, pe un server deja instalat:

$f = 'D:\app\Administrator\product\21c\homes\OraDB21Home1\network\admin\tnsnames.ora'
Copy-Item $f "$f.bak_$(Get-Date -Format yyyyMMdd_HHmmss)"
Add-Content -Path $f -Encoding ASCII -Value @"

ROA =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = <IP_LAN_SERVER>)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XEPDB1)
    )
  )
"@

Nu rescrie fișierul întreg: ORACLR_CONNECTION_DATA e folosit de extproc, iar LISTENER_XE de înregistrarea instanței la listener. Adaugă doar aliasul.

Nu e nevoie de restart — următorul sqlplus lansat de bază citește fișierul la conectare.

După reparație

-- 1. Deblochează rularea rămasă agățată, daca e cazul
exec CONTAFIN_ORACLE.PACK_UPDATE.IncheiereActualizare;
commit;

-- 2. Rulează
exec DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATEROA_ZILNIC',  use_current_session => FALSE);
exec DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATERTVAI_ZILNIC', use_current_session => FALSE);

Cum verifici că actualizarea chiar s-a aplicat

Nu te uita la statusul jobului. Dovada reală e în două locuri:

# Spool-ul trebuie sa aiba zeci de linii si zero ORA-
(Select-String -Path D:\DMPDIR\script_master.log -Pattern 'ORA-|ERROR' | Measure-Object).Count
-- Fiecare schema de firma trebuie sa aiba scriptul zilei
select max(data_script) from VADECO.versiune;
select count(*) from VADECO.versiune where script_final like '%2026_08_28%';

-- Si nicio rulare agatata
select count(*) from CONTAFIN_ORACLE.UPD_ISTORIC where stare = 2;   -- trebuie 0

Atenție la o iluzie: rândurile din SCHEMA.versiune vin cu dump-ul la un import. O schemă proaspăt importată pare „la zi" fără ca actualizarea să fi rulat vreodată local. Compară cu data scriptului efectiv aplicat azi, nu cu max(data_script) în absolut.

Capcane conexe, plătite deja

  • UPD_ISTORIC are coloanele DATAORA_START / DATAORA_END, nu DATA_START.
  • VERSIUNE are SCRIPT_FINAL / DATA_SCRIPT, nu NUME_SCRIPT.
  • UPD_LOG.EXPLICATIE e CLOB și sparge to_char() cu ORA-22835 peste 4000 de caractere. Folosește dbms_lob.substr(explicatie, 180, 1).
  • Un stare=2 rămas deschis blochează rularea următoare — de aceea IncheiereActualizare e primul pas după orice eșec.

A doua victimă a aceleiași cauze: exportul zilnic backupora.exe

Constatat tot la VADECO, 2026-08-28, la câteva ore după cazul de mai sus. Aceeași cauză — un alias TNS care nu se rezolvă — dar alt consumator, alt simptom și, din nou, eșec complet tăcut.

Simptomul

Task-ul ROA Export Oracle rulează, se termină cu cod 0, își creează directorul zilei (D:\BACKUP_ORACLE_FILES\AAAALLZZ\) și scrie în log câte un DONE pentru fiecare schemă. Directorul rămâne gol. Singura urmă e o linie discretă între RUN și DONE:

RUN d:\...\bin\expdp.exe CONTAFIN_ORACLE/******@XEPDB1 directory=dmpdir dumpfile=CONTAFIN_ORACLE_54325.dmp
Copiere DATAPUMPFILE d:\dmpdir\CONTAFIN_ORACLE_54325.dmp in d:\backup_oracle_files\20260828\...
Eroare la copiere DATAPUMPFILE: File 'd:\dmpdir\contafin_oracle_54325.dmp' does not exist.
DONE d:\backup_oracle_files\20260828\CONTAFIN_ORACLE_54325.dmp

backupora.exe nu verifică codul de ieșire al lui expdp și scrie DONE chiar și după ce eroarea de copiere a fost logată. Deci exportul „reușește" în fiecare zi, la ora lui, fără să producă nimic.

Cauza

schema.txt conține linii SCHEMA;PAROLA@XEPDB1. Aliasul XEPDB1 nu exista în tnsnames.ora: 01-setup-database.ps1 scria doar aliasul ROA (plus LISTENER_XE), iar 11-setup-backup-export.ps1 are -ServiceName implicit XEPDB1. Cele două scripturi din același kit nu erau de acord asupra numelui.

Rulat manual, expdp spune limpede ce nu merge:

UDE-12154: operation generated ORACLE error 12154
ORA-12154: TNS:could not resolve the connect identifier specified

Indiciul din log care trădează cazul: fiecare schemă durează exact același timp, ~16 secunde, indiferent de mărime. O bază de 775 MB și una de 45 MB nu se exportă în același timp. Timp uniform = expdp nu exportă, ci moare la conectare.

Reparația

Aliasul cu numele serviciului trebuie să existe, pe lângă ROA, în ambele tnsnames.ora (cel din TNS_ADMIN și cel din Oracle Home — vezi mai sus de ce contează amândouă). În kit:

  • 01-setup-database.ps1 scrie acum două aliasuri: ROA și unul numit ca $ServiceName, ambele către același SERVICE_NAME. Nu atinge aliasurile generate de Oracle (XE, LISTENER_XE, ORACLR_CONNECTION_DATA).
  • 11-setup-backup-export.ps1 face tnsping $ServiceName înainte de a scrie schema.txt și oprește instalarea dacă aliasul nu se rezolvă. Mai bine o instalare care se plânge decât un backup care nu există.

Verificarea, la orice client

Nu te uita la codul de ieșire al task-ului și nici la DONE din log. Uită-te la fișiere:

# Directorul zilei trebuie sa contina cate un .dmp de dimensiune plauzibila
Get-ChildItem "D:\BACKUP_ORACLE_FILES\$(Get-Date -Format 'yyyyMMdd')" |
    Select-Object Name, @{n='MB';e={[math]::Round($_.Length/1MB,1)}}

# Si logul zilei sa nu contina esecuri de copiere
Select-String -Path "D:\ROA\EXPORT_ORADMP\LOG\$(Get-Date -Format 'yyyyMMdd').log" -Pattern 'Eroare'

Un .dmp de 0 octeți sau lipsa lui înseamnă export inexistent, oricât de verde ar fi task-ul.

Lecția generală

De două ori în aceeași zi, pe același server, aceeași formă: un alias TNS lipsă nu dă eroare vizibilă, pentru că procesul care cade e lansat de altcineva, iar cel care raportează nu-i verifică rezultatul. Peste tot unde un script lansează un proces extern Oracle, verifică efectul (fișier scris, rând apărut), nu raportul procesului care l-a lansat.

Legături

  • Lecții de conectare a clienților vechi (ORA-28040 / ORA-01017 / ORA-12514): docs/lectii-conectare-client-oracle.md
  • Instalarea și configurarea: proxmox/lxc108-oracle/roa-windows-setup/README.md
  • SMTP-ul nefuncțional care maschează erorile: docs/handoff_vadeco-update-roa.md