publicare scripturi de baza de date: script + documentatie

COMUN/utile/publicare_scripturi.ps1 face cei doi pasi ai publicarii (import in
UPD_DATABASE + arhiva lunara database[n]_*.zip in _UPDATE), cu configurarea citita
din settings.ini-ul lui tasks.exe si verificare octet cu octet a continutului.
This commit is contained in:
2026-08-03 23:14:47 +03:00
parent 72bf63cd04
commit 4666262c92
4 changed files with 775 additions and 1 deletions

View File

@@ -0,0 +1,83 @@
# Publicarea scripturilor de baza de date catre clienti
Scriptul: `COMUN\utile\publicare_scripturi.ps1`. Inlocuieste pasii manuali din `tasks.exe`
(`D:\PROIECTE\fox\tasks`, formularul din `clase\generare_script.vcx`), care raman varianta de rezerva.
Cum se scrie un script de migrare: `scripturi-migrare-db.md`.
```powershell
powershell -File COMUN\utile\publicare_scripturi.ps1 -DryRun # ce ar face pe luna curenta
powershell -File COMUN\utile\publicare_scripturi.ps1 # luna curenta, tot fluxul
powershell -File COMUN\utile\publicare_scripturi.ps1 -Luna 2026-08 # alta luna
powershell -File COMUN\utile\publicare_scripturi.ps1 -Fisier a.sql,b.sql # doar scripturile date
```
Alte optiuni: `-DoarImport` (fara arhiva), `-DoarArhiva` (doar regenerare arhiva), `-Toate`
(republica si scripturile identice), `-FaraVerificareZip`, `-Settings`, `-ZipPath`, `-DirScripturi`,
`-Alias`, `-User`, `-Password`, `-SqlPlus`.
## Configurarea
Se citeste din `settings.ini`-ul lui `tasks.exe` (`D:\PROIECTE\fox\tasks\settings.ini`, schimbabil
cu `-Settings`), aceleasi chei pe care le foloseste formularul; orice parametru dat explicit bate
ini-ul.
| din ini | ce devine |
|---|---|
| `[connection] host_database` | nume de **DSN ODBC** — aliasul TNS e cheia `ServerName` a DSN-ului din registri (`CENTRAL``ROA_CENTRAL`) |
| `[connection] username_database` / `password_database` | utilizatorul Oracle |
| `[folder] script_folder` | directorul scripturilor, cu `\SCRIPTURI\``\SCRIPTURI_CLAR\` (+ `\<an>\<luna>\`) |
| `[folder] roa_output` | + `_UPDATE\` = directorul arhivelor |
| `[folder] sqlplus_exe` | clientul Oracle (si `TNS_ADMIN` = directorul lui) |
| `[script]` | prefixele valide (`CO_`, `FF_`, `RF_`, `SYS_`, `JCS_`) — prefix necunoscut = avertisment |
`sqlplus_exe` arata spre `instantclient_19_18`; `instantclient_11_2_0_2` (valoarea de dinainte) are
un `tnsnames.ora` vechi, cu `ROA_CENTRAL` pe `10.0.20.122` in loc de `.121`, deci conexiunea expira.
`settings.ini` e local (ignorat de SVN).
## Cei doi pasi
**1. Import** — fiecare `.sql` intra ca un rand in `CONTAFIN_ORACLE.UPD_DATABASE` de pe `ROA_CENTRAL`,
cu `SCRIPT_ORDER = 0` (randul contine scriptul intreg, nu instructiuni parsate), `SCRIPT_NAME` cu
MAJUSCULE si `.SQL`, `SCRIPT_TYPE` = ce urmeaza dupa `NN_`, `SCRIPT_CONTENT` = fisierul in clar.
`ID` vine din trigger, `DATAORA` din `SYSDATE` implicit, `SCRIPT_APPVER`/`SCRIPT_EXTRA_FILE` raman
goale. Daca `SCRIPT_NAME` exista deja, se face **update pe acelasi `id`** — asa se republica un
script corectat, pentru ca clientul face `MERGE ... on (a.id = b.id)`.
**2. Arhiva lunara** — in `Y:\ROAUPDATE\_UPDATE\` se scriu `database_YYYYMMDD_YYYYMMDD.zip` **si**
`databasen_...zip` (identice azi: `database_` era varianta criptata cu `wrap.exe`, nu se mai
foloseste). Fiecare contine XML-ul cu acelasi nume ca zip-ul (format `VFPData`/`crsxml`,
Windows-1252, CRLF, tab-uri, `script_content` gol) plus cate un `<STEM_MAJUSCULE>.sql` per script.
Indexii `roa_database.xml` / `roa_databasen.xml` listeaza arhivele existente si se schimba doar
cand apare o luna noua.
Continutul din arhiva se citeste **inapoi din baza**, nu de pe disc — deci arhiva contine exact ce
va primi clientul.
## Verificari facute automat
- fisier cu sfarsituri de linie LF: **refuzat** (parsarea pe client se face pe `CHR(13)+CHR(10)`);
- dupa import, continutul e citit inapoi din CLOB si comparat octet cu octet cu fisierul; la
diferenta se opreste inainte de arhiva;
- scripturile deja publicate cu acelasi continut se sar (`-Toate` forteaza republicarea);
- arhiva generata se citeste inapoi cu cititorul clientului (`pack_utils.decodebase64` +
`zip_util_pkg.get_file`) si se compara lungime + MD5 per fisier — o arhiva facuta din PowerShell
este citita corect de `zip_util_pkg`;
- fisierele inlocuite din `_UPDATE` se copiaza intai in `_UPDATE\_backup\<data_ora>\`.
`Y:\ROAUPDATE\_UPDATE\` e **live**: clientii descarca de acolo imediat ce fisierul e pus.
## Ce face clientul
`PACK_UPDATE.UpdateScripts` (`COMUN\docs\PACK_UPDATE.pck`) descarca indexul, apoi arhivele care
acopera perioada neaplicata, extrage XML-ul cu `zip_util_pkg.get_file`, face `MERGE` in
`UPD_DATABASE` pe `id`, apoi pentru fiecare rand cu `script_extra_file` pune continutul fisierului
in `script_content` — pentru `.sql` text clar, fara base64 (base64 e doar pentru instructiunile
parsate, alta ramura). Actualizare blocata: `depanare-pack-update.md`.
## Detalii de implementare
Continutul circula **hexazecimal** in ambele sensuri (`utl_i18n.raw_to_char` / `string_to_raw` cu
`WE8MSWIN1252`), pe bucati de 900 de octeti, in blocuri PL/SQL de cate 15 bucati. Motivul: baza e
`AL32UTF8`, fisierele sunt CP1252, iar comanda trimisa lui `sqlplus` ramane ASCII pur — nu depinde
de `NLS_LANG` si nu poate strica octetii >= 0x80. Consecinta utila: comparatia dintre fisier si
CLOB e exacta, nu pe lungime.