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
233 lines
9.7 KiB
Markdown
233 lines
9.7 KiB
Markdown
# 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/<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:
|
|
|
|
```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/<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:
|
|
|
|
```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 = <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
|
|
|
|
```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`
|