# Lecții — conectarea clienților vechi (Instant Client 10/11) la Oracle 21c Scris pe 2026-08-25, după migrarea VADECO pe server nou. Toate lucrurile de mai jos au fost **observate direct**, nu deduse din documentație, iar fiecare a fost verificat pe serverul clientului (`WIN-16COB435C1E`, `192.168.101.111`, Oracle XE 21.3, CDB `XE` + PDB `XEPDB1`). Numitorul comun al tuturor: **niciuna dintre erori nu arată spre cauza ei.** `ORA-01017` pare parolă greșită, `ORA-12514` pare baza oprită, `ORA-28040` pare o problemă de client. De aceea au ajuns aici, într-un fișier separat. --- ## 1. `TNS_ADMIN` de mașină bate Oracle Home — și pentru instanță, nu doar pentru clienți ROAClient își pune `TNS_ADMIN` de mașină pe folderul propriului Instant Client (la VADECO: `d:\roa\instantclient_11_2_0_2`). Variabila nu e citită doar de `sqlplus`-ul din folderul acela: **serviciul Oracle o moștenește la pornire**, iar procesele bazei citesc de acolo și `sqlnet.ora`, și `tnsnames.ora`. Capcana e de timp, nu de conținut. O instanță pornită **înainte** ca `TNS_ADMIN` să existe nu o vede, deci continuă să citească din Oracle Home și totul pare în regulă. Efectul apare **abia la primul restart al serviciului** — adică la primul reboot al serverului, de obicei după ce am plecat de la client. ### 1a. Fără `sqlnet.ora` acolo → `ORA-28040` la toți clienții vechi `SQLNET.ALLOWED_LOGON_VERSION_SERVER=8` scris frumos în `ORACLE_BASE_HOME\network\admin\sqlnet.ora` devine irelevant: instanța citește din `TNS_ADMIN`, nu găsește nimic, cade pe implicitul 21c (`12`) și refuză orice client pre-12c. ### 1b. Fără `tnsnames.ora` acolo → `ORA-12514` la **toți** clienții Asta e cea gravă, și e cea pe care am prins-o efectiv. La Oracle XE, `LOCAL_LISTENER` e implicit **aliasul** `LISTENER_XE`, definit numai în `tnsnames.ora` din Oracle Home. După restart, instanța încearcă să rezolve aliasul din `TNS_ADMIN`-ul nou, nu-l găsește, **nu se mai înregistrează la listener** — și atunci: - baza e sus (`v$instance` = `OPEN`, `v$pdbs` = `READ WRITE`); - serviciul Windows e `Running`; - listenerul e `Running` și ascultă pe `0.0.0.0:1521`; - `lsnrctl status` arată **doar** `CLRExtProc`; - **absolut orice** client primește `ORA-12514`. Adică: server aparent perfect, aplicație complet moartă. Exact ce s-ar fi întâmplat la VADECO la primul reboot. ### Reparația Trei lucruri, toate făcute acum de `01-setup-database.ps1`: 1. `sqlnet.ora` scris **și** în `TNS_ADMIN`, identic cu cel din Oracle Home; 2. `tnsnames.ora` scris în `TNS_ADMIN`, cu aliasul `ROA` (pentru ROAClient) **și** `LISTENER_XE` (pentru instanță); 3. `LOCAL_LISTENER` fixat pe **adresă literală**, ca să nu mai depindă de niciun fișier de rețea: ```sql ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.101.111)(PORT=1521))' SCOPE=BOTH; ALTER SYSTEM REGISTER; ``` Punctul 3 e singurul care rezistă și dacă ROAClient se instalează **după** kit, sau dacă cineva mută folderul Instant Client. Punctele 1 și 2 rămân necesare pentru `sqlnet.ora` și pentru aliasul `ROA`, dar au aceeași fragilitate: sunt corecte doar față de valoarea lui `TNS_ADMIN` din momentul rulării. De asta pasul 07 le reverifică. ### Diagnostic rapid ```powershell [Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine') Test-Path "$([Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine'))\sqlnet.ora" & "$env:ORACLE_HOME\bin\lsnrctl.exe" status | Select-String 'Service "' ``` Dacă `lsnrctl status` nu listează serviciul PDB-ului dar baza e `OPEN`, e exact cazul 1b. Confirmarea: ```sql SELECT value FROM v$parameter WHERE name = 'local_listener'; ``` Un alias (`LISTENER_XE`) în loc de un `(ADDRESS=...)` = bombă cu ceas. --- ## 2. `ALLOWED_LOGON_VERSION_SERVER=8` cere verificator **10G**, altfel `ORA-01017` Cu setarea asta, serverul autentifică orice client pre-12c pe baza verificatorului **10G**. Un cont care nu are `10G` în `PASSWORD_VERSIONS` nu se mai poate conecta din Instant Client 10/11 — și eroarea **nu** e `ORA-28040`, e: ``` ORA-01017: invalid username/password; logon denied ``` Adică fix eroarea care te trimite să verifici parola. Parola e corectă: același cont, aceeași parolă, se conectează perfect din `sqlplus`-ul 21c de pe server. După o instalare curată de 21c, `SYSTEM` are doar `11G 12C`. `CONTAFIN_ORACLE` are `10G 11G 12C` **doar pentru că** pasul 01 îi rescrie parola *după* ce a scris `sqlnet.ora` — verificatoarele se generează după setarea activă în momentul `CREATE`/`ALTER USER`, nu retroactiv. ### Reparația Rescrierea **aceleiași** parole. Nu se schimbă nimic pentru nimeni, doar se regenerează verificatoarele: ```sql -- utilizator local (schemele de firmă, CONTAFIN_ORACLE) — din PDB ALTER USER CONTAFIN_ORACLE IDENTIFIED BY "ROMFASTSOFT"; -- utilizator comun (SYSTEM) — obligatoriu din CDB$ROOT ALTER USER SYSTEM IDENTIFIED BY "romfastsoft" CONTAINER=ALL; ``` Pasul 01 face acum ambele. ### Sub-capcană: `PASSWORD_VERSIONS` minte pentru utilizatorii comuni Interogat **din PDB**, `DBA_USERS.PASSWORD_VERSIONS` pentru `SYSTEM` rămâne `11G 12C` și după `ALTER USER ... CONTAINER=ALL` din root. Rândul local nu se împrospătează, dar autentificarea folosește definiția din root — și funcționează. Măsurat la VADECO, în aceeași secundă: | | `PASSWORD_VERSIONS` | |---|---| | `CDB$ROOT` | `10G 11G 12C` | | `XEPDB1` | `11G 12C` | | conectare reală din Instant Client 11.2 | **merge** | Concluzie: pentru utilizatorii comuni, coloana nu e o dovadă. Singura verificare validă e o conectare adevărată. De asta pasul 07 nu se mai uită la coloană pentru `SYSTEM`, ci îl probează. --- ## 3. `listener.ora` legat de un nume care depinde de Tailscale Instalarea de Oracle a pus în `listener.ora` și `tnsnames.ora`: ``` (ADDRESS = (PROTOCOL = TCP)(HOST = vadeco-server.tailf7372d.ts.net)(PORT = 1521)) ``` Adică numele MagicDNS al mașinii în tailnet. Ascultarea în sine e corectă (listenerul se leagă tot pe `0.0.0.0:1521`, deci LAN-ul e servit), dar **pornirea listenerului ajunge să depindă de Tailscale**: la boot, dacă `tailscaled` nu a ridicat încă resolverul, numele nu se rezolvă. Înlocuit cu numele mașinii, care se rezolvă local întotdeauna: ``` (ADDRESS = (PROTOCOL = TCP)(HOST = WIN-16COB435C1E)(PORT = 1521)) ``` Verificat după restartul listenerului: tot `0.0.0.0:1521`, toate serviciile înregistrate, clienții se conectează. **Regulă:** pe serverele la care intrăm prin Tailscale, niciun fișier de configurare Oracle nu are voie să conțină un nume `*.ts.net` sau o adresă `100.64.0.0/10`. Din același motiv, `Get-ServerLanIPv4` (în `scripts/lib/oracle-functions.ps1`) sare peste intervalul Tailscale când alege IP-ul pentru `tnsnames.ora` și `LOCAL_LISTENER` — un `tnsnames.ora` cu `100.x` copiat pe o stație nu duce nicăieri, stația nu e în tailnet. --- ## 4. Proba de conectare cu clientul vechi e obligatorie Toate cele trei probleme de mai sus trec de verificările „pe hârtie": fișierul există, parametrul e setat, contul e `OPEN`, obiectele sunt valide. Singurul lucru care le prinde pe toate e o conectare adevărată, cu **clientul vechi**, nu cu `sqlplus`-ul 21c de pe server. ```powershell $ic = 'D:\ROA\instantclient_11_2_0_2' 'select ''PROBA_OK '' || user from dual;' , 'exit' | Set-Content -Encoding ascii C:\Windows\Temp\t.sql # prin aliasul din tnsnames.ora — asa se conecteaza ROAClient & "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@ROA" '@C:\Windows\Temp\t.sql' # prin EZConnect, pe IP-ul din LAN — ocoleste tnsnames.ora, izoleaza cauza & "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@//192.168.101.111:1521/XEPDB1" '@C:\Windows\Temp\t.sql' ``` `-L` (o singură încercare) nu e opțional: fără el, la o parolă refuzată `sqlplus` cere parola de la tastatură și **agață** o sesiune neinteractivă până la timeout. Diferența dintre cele două forme e utilă la diagnostic: dacă EZConnect merge și aliasul nu, problema e în `tnsnames.ora`; dacă niciuna nu merge, problema e la server (verificator de parolă, `sqlnet.ora` sau înregistrarea la listener). --- ## 5. Ce verifică acum pasul 07 `07-verify-installation.ps1` a primit secțiunea **„Conectivitate client vechi (Instant Client)"**, care acoperă toate lecțiile de mai sus: | Verificare | Prinde | |---|---| | `ALLOWED_LOGON_VERSION_SERVER` din `sqlnet.ora` de Oracle Home | valoare > 11 | | `sqlnet.ora` există în `TNS_ADMIN` de mașină | 1a — `ORA-28040` la primul reboot | | `tnsnames.ora` din `TNS_ADMIN`: alias `ROA`, `LISTENER_XE`, urme de șablon (`SERVER_ROA`) | 1b — `ORA-12514` la primul reboot; stații care nu găsesc baza | | `LOCAL_LISTENER` e adresă literală, nu alias | 1b, cazul de fond | | `PASSWORD_VERSIONS` conține `10G` pentru `CONTAFIN_ORACLE` și schemele de firmă | 2 — `ORA-01017` | | conectare reală cu Instant Client-ul găsit pe mașină: `CONTAFIN_ORACLE` prin alias și prin EZConnect, `SYSTEM` prin EZConnect | tot ce a scăpat | La eșec, raportul spune și unde să te uiți: `ORA-01017` → verificatorul 10G, `ORA-28040` → `TNS_ADMIN`, `ORA-12514` → `LOCAL_LISTENER`. Parametri noi: `-ContafinPassword` (implicit `ROMFASTSOFT`) și `-InstantClientDir` (implicit: din `TNS_ADMIN`, altfel căutat sub `D:\ROA`, `C:\ROA`, `D:\`, `C:\`). Dacă nu există Instant Client pe server, proba se raportează ca sărită, nu ca eșec. --- ## 6. Capcane de mediu, plătite deja - **`powershell -Command -` prin SSH trunchiază scriptul.** Un script cu blocuri pe mai multe linii trimis pe stdin se execută parțial: comenzile de după primul bloc multi-linie pur și simplu nu rulează, fără nicio eroare. Se pierde timp crezând că o comandă a eșuat. Soluția: `scp` fișierul `.ps1` și `ssh ... powershell -NoProfile -ExecutionPolicy Bypass -File C:\Windows\Temp\x.ps1`. - **`sqlplus / as sysdba` nu merge într-o sesiune SSH** pe serverul ăsta (`ORA-01017`) — autentificarea pe sistem de operare nu primește token-ul de grup. Se folosește `sys/@//localhost:1521/XE as sysdba`, sau bequeath cu `ORACLE_SID` setat și parolă explicită. - **Un `Restart-Service OracleServiceXE` durează 2–4 minute** (oprire + pornire + înregistrare). Comenzile de la distanță au nevoie de timeout pe măsură; altfel timeout-ul taie sesiunea în mijlocul unui restart. --- ## Legături - Kit și flux complet: `proxmox/lxc108-oracle/roa-windows-setup/README.md` - Migrarea VADECO: `docs/handoff_vadeco-migrare.md` (nu intră în git) - Capcana cu discul `C:` de pe același server: aceeași migrare, secțiune separată în handoff — procesul Oracle nu ajunge la nicio cale de pe `C:`