# 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: ```sql SET AUTOPRINT OFF WHENEVER SQLERROR EXIT SQL.SQLCODE SPOOL D:\DMPDIR\script_master.log CONNECT CONTAFIN_ORACLE/@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: ```powershell 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`): ```powershell Remove-Item Env:TNS_ADMIN -ErrorAction SilentlyContinue "exit" | & "$oraHome\bin\sqlplus.exe" -L -S "CONTAFIN_ORACLE/@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: ```powershell $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 = )(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 ```sql -- 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: ```powershell # 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 ``` ```sql -- 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**: ```powershell # 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`