martedì 29 settembre 2026

Free PlyxSQL© - 1.0.0.107 Super ETL

In breve. Il generatore SQL di TFireDACQueryBuilder, il query builder visuale per C++Builder e FireDAC, è stato rivisto a fondo. Abbiamo corretto dodici bug segnalati, dall'UNION scritta dopo il punto e virgola al DATEADD sbagliato per SQL Server. Nel farlo il componente ha cambiato impostazione: la query non viene più assemblata concatenando stringhe ma costruita a partire da un modello, e ogni dialetto ha una tabella di capability che dice cosa il database supporta davvero.

Un query builder visuale fa una promessa semplice: disegni tabelle e relazioni, ottieni SQL corretto. Il problema è che "corretto" dipende da tre cose: la semantica di ciò che hai disegnato, la sintassi del database di destinazione e la versione di quel database. Il vecchio generatore di TFireDACQueryBuilder gestiva bene i casi comuni, ma in parecchi scenari produceva SQL apparentemente valido che il database rifiutava o, peggio, eseguiva restituendo risultati diversi da quelli attesi.

In questo articolo ripercorriamo tutte le correzioni e le migliorie: cosa non andava, perché, e come è stato risolto.

Riepilogo delle correzioni

#ProblemaGravitàSoluzione
1UNION/INTERSECT/EXCEPT generati dopo il ;CriticaModello Query → SelectBlock → SetOperation, terminatore unico
2Ordine dei JOIN dipendente dall'ordine delle relazioniCriticaJoinTree esplicito, verso rispettato, OUTER JOIN annidati
3Un ciclo nel grafo trattato come erroreAltaNuove verifiche strutturali mirate
4Validate() con semantica invertitaAltatrue = valida, nuovo HasValidationErrors()
5IN ('1,2,3') invece di IN (1,2,3)AltaLista di valori tipizzati
6Identificatori quotati senza escapingAltaQuoteIdentifier(name, dialect) centralizzata
7Schema assente nei DMLAltaQualifiedTableName(T) ovunque
8NOLOCK/UPDLOCK mai generati davveroAltaHint applicati al nodo tabella, anche per singola tabella
9APPLY / LATERAL non validati per dialettoAltaCapability matrix dei JOIN + popup che disabilita
10DATEADD SQL Server con sintassi errataAltaDATEADD(datepart, number, date) e sintassi per ogni dialetto
11LPAD su SQL Server emulato con FORMAT()AltaEmulazione con REPLICATE e semantica esatta
12Funzioni non supportate dal dialetto generate comunqueAltaTDialectCapabilities con versione minima

Il cambio di impostazione: dal testo al modello

La causa comune dei primi tre bug era una sola: GenerateSQL() costruiva la query aggiungendo pezzi di stringa uno dopo l'altro, e ricavava l'ordine dei JOIN visitando il grafo delle relazioni ogni volta da capo. Così non c'era un punto in cui la struttura della query esistesse come dato.

Ora il diagramma viene tradotto una volta sola in un modello esplicito:

Query
 ├── SelectBlock            (tabelle + JoinTree esplicito)
 ├── SetOperation           (UNION / INTERSECT / EXCEPT)
 │    ├── SelectBlock
 │    └── SetOperation
 │         └── SelectBlock

Il modello viene prodotto da BuildQueryPlan() e ha due soli consumatori: GenerateSQL(), che lo trasforma in testo, e RunValidation(), che ne riporta la diagnostica. In questo modo quello che il validatore controlla è esattamente quello che il generatore scrive.

1. UNION dopo il punto e virgola

Il terminatore veniva aggiunto alla fine della SELECT principale, prima di generare le operazioni su insiemi:

Prima
SELECT ... FROM A
;
UNION
SELECT ... FROM B;

Il primo ; chiude lo statement e il resto diventa un frammento che inizia con UNION: sintassi non valida. Oggi il terminatore è unico e le set operation sono nodi del modello, anche annidati:

Dopo
SELECT "A"."id", "A"."name" FROM "A"
UNION
(
  SELECT "B"."id", "B"."name" FROM "B"
  INTERSECT
  SELECT "C"."id", "C"."name" FROM "C"
)
ORDER BY
  2 ASC
LIMIT 10;

Il modello si è portato dietro anche altre correzioni:

  • dopo una UNION l'ORDER BY usa la posizione della colonna o il suo alias, perché riferimenti come "A"."name" non sono più validi;
  • su SQL Server e Firebird il limite di righe va in fondo alla query: TOP/FIRST in testa limiterebbero solo il primo ramo;
  • su Oracle EXCEPT diventa MINUS;
  • le tabelle di un ramo della UNION non finiscono più anche tra le colonne del SELECT principale.

2. I JOIN seguono la semantica, non l'ordine di salvataggio

Questo era il bug più insidioso, perché non produceva errori: produceva risultati diversi. Prendiamo un diagramma con due relazioni:

A --LEFT--> B
C --INNER-> B

A seconda dell'ordine in cui le relazioni erano salvate, il vecchio generatore poteva scrivere:

Prima
FROM A
LEFT JOIN B ON A.b_id = B.id
INNER JOIN C ON B.id = C.b_id

L'INNER JOIN finale scarta tutte le righe di A senza corrispondenza in B: il LEFT JOIN diventa di fatto un INNER JOIN. Ora ogni SELECT ha un JoinTree esplicito, e un sottoalbero agganciato con un OUTER JOIN che contiene join non-LEFT viene reso annidato:

Dopo
FROM "A"
LEFT JOIN (
    "B"
    INNER JOIN "C"
      ON "B"."id" = "C"."b_id"
  )
  ON "A"."b_id" = "B"."id";

Abbiamo eseguito le due forme su SQLite con gli stessi dati: la vecchia restituiva 1 riga, la nuova 3, cioè tutte le righe di A come richiede il LEFT JOIN disegnato.

Altre regole del JoinTree:

  • Il verso viene rispettato. B LEFT A raggiunto partendo da A diventa A RIGHT JOIN B; prima veniva scritto LEFT JOIN, invertendo la semantica.
  • APPLY e LATERAL non si invertono mai, perché il lato destro dipende dal sinistro.
  • RIGHT e FULL vengono resi per ultimi fra le tabelle allo stesso livello, così il lato preservato resta tale.
  • Le relazioni che chiudono un ciclo non vengono più scartate in silenzio: la loro condizione finisce in AND nella clausola ON corretta.

3. Un ciclo non è un errore

HasCycle() segnalava come errore qualunque ciclo nel grafo delle relazioni. Ma A → B → C → A è un insieme di JOIN perfettamente legittimo:

FROM "A"
INNER JOIN "B" ON "A"."id" = "B"."a_id"
INNER JOIN "C" ON "B"."id" = "C"."b_id"
 AND "C"."id" = "A"."c_id";

Il controllo sui cicli è stato eliminato e sostituito da verifiche che individuano problemi reali:

  • JOIN duplicati, anche se dichiarati con tipi di join diversi;
  • JOIN impossibili: campo che non esiste più, tabella unita a se stessa (per un self-join serve aggiungere la tabella due volte con alias diversi), APPLY che andrebbe invertito;
  • tabelle scollegate, escluse dalla query con avviso;
  • conflitti di alias nello stesso SELECT;
  • set operation con numero di colonne diverso fra i rami.

4. Validate(): il nome ora dice la verità

Il vecchio Validate() restituiva true quando c'erano errori. Un chiamante che scriveva la cosa più naturale otteneva l'esatto contrario:

if(builder->Validate())
    ExecuteQuery();   // eseguita proprio quando la query NON è valida

Il contratto adesso è esplicito:

  • Validate() restituisce true se la query è valida;
  • HasValidationErrors() restituisce true se ci sono errori, cioè la vecchia semantica con un nome non ambiguo;
  • HasErrors() fa lo stesso controllo senza rieseguire la validazione.
Attenzione, cambio di comportamento. Se il vostro codice chiamava Validate() aspettandosi true in presenza di errori, quel controllo ora dà il risultato opposto. Sostituitelo con HasValidationErrors().

5. IN con più valori

Il valore di una condizione IN veniva trattato come un unico literal:

Prima
"A"."code" IN ('1,2,3')

Ora il valore diventa una lista in cui ogni elemento ha il proprio tipo (literal, parametro o subquery). Le virgole dentro gli apici vengono rispettate e il formato salvato nei progetti non cambia:

Dopo
1,2,3               →  IN (1, 2, 3)
A, B, C             →  IN ('A', 'B', 'C')
'A','B,C','O''Hara' →  IN ('A', 'B,C', 'O''Hara')
:p1, @p2            →  IN (:p1, :p2)
SELECT id FROM t    →  IN (SELECT id FROM t)
(lista vuota)       →  1 = 0

6. Escaping degli identificatori

QI() racchiudeva il nome tra delimitatori senza raddoppiare il delimitatore stesso: un campo chiamato Nome"Campo produceva SQL non valido. C'è ora un'unica funzione, QuoteIdentifier(name, dialect):

DialettoDelimitatoreEsempio
SQL Server[ ]a]b → [a]]b]
MySQL` `a`b → `a``b`
ANSI (PostgreSQL, Oracle, Firebird, SQLite…)" "Nome"Campo → "Nome""Campo"

La funzione è usata ovunque: DDL, DML, WHERE, alias, ORDER BY, subquery, PIVOT. Sono stati corretti anche i punti che quotavano a mano, come le tabelle temporanee, dove "T"_TMP è diventato "T_TMP".

7. Schema qualificato anche nei DML

La SELECT scriveva correttamente "dbo"."Customers", ma INSERT, UPDATE, DELETE e gli altri generatori usavano solo il nome della tabella. Con più schemi il rischio era di modificare la tabella sbagliata. Ora c'è QualifiedTableName(T), usata da SELECT, INSERT, UPDATE, DELETE, MERGE, TRUNCATE, DDL, VIEW e TEMP TABLE:

INSERT INTO [dbo].[Customers] ( [id], [name] ) VALUES ( @id, @name );
UPDATE [dbo].[Customers] SET [name] = @name WHERE [id] = @id;
TRUNCATE TABLE [dbo].[Customers];
  • Sequence e trigger di PostgreSQL e Oracle vengono creati nello schema della tabella.
  • Il nome di una vista si può scrivere come dbo.V_Clienti: le due parti vengono quotate separatamente.
  • Le tabelle temporanee sono qualificate solo dove il database lo permette: PostgreSQL, SQLite e SQL Server (#tmp) rifiutano un nome qualificato.
  • UPDATE e DELETE usavano l'alias della tabella nel WHERE senza dichiararlo nello statement: ora le colonne non sono qualificate.

8. Lock hint reali, anche per singola tabella

Selezionando NOLOCK il vecchio generatore aggiungeva soltanto un commento:

Prima
-- NOTE: use WITH (NOLOCK) in FROM clause for SQL Server

L'interfaccia diceva "lock hint attivo", ma la query non lo conteneva. Ora l'hint è applicato al nodo tabella:

Dopo
FROM [dbo].[Orders] [o] WITH (NOLOCK)
LEFT JOIN [dbo].[Cust] [c] WITH (NOLOCK)
  ON [o].[cust] = [c].[id];

In più, ogni tabella può avere un lock e un hint propri (dal menu contestuale Lock / hint tabella). Il generatore li traduce nella forma supportata dal database:

DatabaseResa
SQL ServerWITH (UPDLOCK), WITH (NOLOCK, INDEX(ix_prod)) sulla singola tabella
PostgreSQL, MySQL 8FOR UPDATE OF "o" + FOR SHARE OF "c", anche con SKIP LOCKED
OracleFOR UPDATE OF "o"."id", "c"."id" (una sola clausola ammessa)
Firebirdlock solo a livello di statement: FOR UPDATE WITH LOCK più un avviso

Quando un hint non si può applicare (ad esempio NOLOCK su PostgreSQL) non viene emesso, e lo segnalano sia una nota nell'SQL sia un warning di validazione. Su Firebird PLAN ora precede ORDER BY: in fondo alla query era sintatticamente errato.

9. APPLY e LATERAL validati per dialetto

Il builder permetteva CROSS APPLY, OUTER APPLY e JOIN LATERAL su qualunque database, e accettava perfino JOIN LATERAL <tabella>, che non è una lateral subquery. Ora ogni tipo di JOIN ha una riga nella capability matrix:

DialettoINNER/LEFTRIGHTFULLAPPLYLATERAL
SQL Server✓✓✓✓✓ come APPLY
PostgreSQL✓✓✓✓ come LATERAL✓
Oracle✓✓✓12c+12c+
MySQL✓✓—8.0.14+8.0.14+
Firebird✓✓✓4.0+4.0+
InterBase✓✓✓——
SQLite✓3.39+3.39+——

Dove esiste una forma equivalente il builder la usa: CROSS APPLY diventa CROSS JOIN LATERAL su PostgreSQL, MySQL e Firebird; OUTER APPLY diventa LEFT JOIN LATERAL … ON TRUE; LATERAL diventa CROSS APPLY su SQL Server e Oracle.

Anche l'interfaccia si adegua:

  • nel popup JOIN i tipi non supportati sono barrati, marcati "n/a" e non selezionabili;
  • quelli che richiedono una versione minima la mostrano accanto;
  • LATERAL è disabilitato se la tabella di destinazione non è una subquery;
  • le relazioni che diventano non supportate dopo un cambio di dialetto appaiono in rosso con ⚠.

10. DATEADD per SQL Server

Prima
DATEADD(1 DAY, MyDate)
Dopo
DATEADD(DAY, 1, MyDate)

L'argomento si scrive come prima (1 DAY, -3 months); è accettato anche l'ordine di SQL Server (DAY, 7). La sintassi era sbagliata anche in altri dialetti:

DialettoRisultato per "2 MONTH"
SQL ServerDATEADD(MONTH, 2, d)
MySQLDATE_ADD(d, INTERVAL 2 MONTH)
PostgreSQL(d + 2 * INTERVAL '1 month')
OracleADD_MONTHS(d, 2)
FirebirdDATEADD(MONTH, 2, d) (prima: d + 2 MONTH)
SQLiteDATETIME(d, (2) || ' months')

11. LPAD su SQL Server

FORMAT() non è un equivalente di LPAD(): funziona su numeri e date con stringhe di formato, non riempie una stringa con un carattere. La nuova emulazione converte il valore in NVARCHAR, così funziona con qualsiasi tipo, e riproduce anche il troncamento di LPAD quando il valore è più lungo di n:

CASE WHEN DATALENGTH(CAST(x AS NVARCHAR(4000))) / 2 >= 5
     THEN LEFT(CAST(x AS NVARCHAR(4000)), 5)
     ELSE RIGHT(REPLICATE('0', 5) + CAST(x AS NVARCHAR(4000)), 5)
END

È stato aggiunto RPAD, con la stessa emulazione anche per SQLite. Su PostgreSQL il valore viene convertito in testo, perché lì LPAD applicato a un numero dà errore.

12. TDialectCapabilities: niente più SQL ineseguibile

Il wizard offriva JSON_OBJECT, LPAD, DATE_TRUNC, STRING_AGG, REGEXP e altre funzioni senza verificare se il database le supportasse. Ora c'è una struttura dedicata:

struct TDialectCapabilities {
    TSQLDialect     Dialect;
    TDialectFeature SupportsJson;
    TDialectFeature SupportsWindowFunctions;
    TDialectFeature SupportsLateral;
    TDialectFeature SupportsStringAgg;
    TDialectFeature SupportsDateTrunc;
    TDialectFeature SupportsRegex;
    TDialectFeature SupportsReturning;
    TDialectFeature SupportsOffsetFetch;
    // ... FullJoin, IntersectExcept, LPad, Apply, SimilarTo
    static TDialectCapabilities For(TSQLDialect ADialect);
};

Ogni TDialectFeature indica se la funzionalità è supportata, disponibile da una versione minima (MinVersion, ad esempio "2017+") o non supportata. Alcuni esempi:

FunzionalitàSQL ServerPostgreSQLMySQLOracleFirebirdSQLite
JSON2016+9.4+5.7.8+12.2+—3.38+
Window functions✓✓8.0+✓3.0+3.25+
STRING_AGG2017+✓GROUP_CONCAT11gR2+LISTGROUP_CONCAT
REGEXP2025+✓✓✓—estensione
RETURNINGOUTPUT✓—INTO2.1+3.35+

Le capability sono usate in tre punti:

  • Validazione. Funzioni non supportate sono errori, quelle legate a una versione sono warning. Lo stesso vale per window function, IIF, REGEXP e SIMILAR TO nel WHERE, OFFSET/FETCH e RETURNING.
  • Wizard. Ogni funzione riporta "[n/a SQLite]" oppure "[2017+]"; l'anteprima mostra la disponibilità e gli errori negli argomenti, e "Applica" rifiuta una funzione non disponibile.
  • Generatore. Dove esiste un equivalente reale viene usato: DATE_TRUNC diventa TRUNC su Oracle e DATEADD/DATEDIFF su SQL Server, JSON_OBJECT su SQL Server diventa FOR JSON PATH. SIMILAR TO e REGEXP, invece, non vengono più convertiti in silenzio in LIKE, che ha un significato diverso.

Altre correzioni emerse durante la revisione

  • Il wizard delle funzioni scalari applicava sempre la prima funzione della categoria, qualunque fosse quella scelta.
  • SUBSTRING, LEFT e RIGHT generavano sintassi non valida su Oracle e SQLite.
  • YEAR() e MONTH() non esistono su PostgreSQL e Oracle: ora escono come EXTRACT.
  • Su MySQL CONVERT aveva gli argomenti invertiti e CAST AS INTEGER non è valido: ora SIGNED e CHAR(n).
  • Il path di JSON_VALUE usciva con doppi apici.
  • STRING_AGG su colonne numeriche falliva su PostgreSQL e SQL Server.
  • InterBase usava FIRST e OFFSET … FETCH, che sono sintassi Firebird: ora usa ROWS n e ROWS m TO n.
  • OUTPUT INSERTED.id, created_at di SQL Server metteva INSERTED. solo sulla prima colonna.
  • Con OFFSET attivo uscivano due LIMIT, oppure TOP e OFFSET insieme.
  • Il ; finale poteva finire dentro un commento -- sull'ultima riga.
  • TableHint veniva salvato nel progetto ma non era mai emesso nell'SQL.

Come sono state verificate le modifiche

Le funzioni che generano l'SQL sono state compilate con g++, affiancate da un piccolo strato che sostituisce String e le classi VCL, ed esercitate con 94 verifiche automatiche che coprono tutti i punti descritti. Per SQLite le espressioni generate sono state anche eseguite su un database reale (LPAD/RPAD emulati, DATE_TRUNC, DATE_ADD, JSON, JOIN annidati, UNION) confrontando i risultati con quelli attesi.

Cosa resta da fare. Le forme per SQL Server, PostgreSQL, Oracle, MySQL e Firebird sono state controllate come testo ma non eseguite su quei server, e l'interfaccia (popup, menu, wizard) va provata nell'IDE. Le versioni minime della matrice vanno confrontate con le versioni dei database effettivamente in uso.

Note per chi aggiorna

  • Validate() ora restituisce true quando la query è valida. Chi si affidava al vecchio comportamento deve passare a HasValidationErrors().
  • Nuove API pubbliche: QuoteIdentifier(), QualifiedTableName(), QualifiedName(), WhereValueList(), JoinCapability(), IsJoinSupported(), TDialectCapabilities::For(), DialectCapabilities(), ScalarFuncCapability(), IsScalarFuncSupported(), SetTableLockHint(), ClearTableLockHint(), SetTableHintText(), EffectiveLockHint().
  • Progetti salvati: i nuovi campi JSON (lockOv, lockHint, tblHint) sono opzionali, per cui i progetti esistenti si aprono con lo stesso SQL di prima.
  • SQL diverso da prima: in diversi casi l'SQL generato cambia, ed è voluto: JOIN annidati, schema nei DML, hint reali, sintassi di data corrette. Conviene rigenerare e rileggere le query salvate come testo.

#SQL #database #ETL #DataEngineering #plyxSQL #FireDAC #PGSOFT

lunedì 28 settembre 2026

Free PlyxSQL© - 1.0.0.106 Super ETL - TEST STRESS

 Free PlyxSQL© - 1.0.0.106 Super ETL

POSTED BY Giuliano pagnini, 28 SETT 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

Nuova finestra imposta fase:

Riorganizzata la finestra di impostazione fase di importazione e creato il programma di TEST STRESS con 15.000.000 record









#SQL #database #ETL #DataEngineering #plyxSQL #FireDAC #PGSOFT

Free PlyxSQL© - 1.0.0.105 Super ETL

Free PlyxSQL© - 1.0.0.105 Super ETL

POSTED BY Giuliano pagnini, 28 SETT 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml

ETL Engine: una nuova generazione di affidabilità, automazione e controllo dei processi dati


Nel mondo della gestione dei dati non è sufficiente trasferire informazioni da una sorgente a una destinazione. Un moderno motore ETL deve saper gestire grandi quantità di dati, errori, interruzioni, ripartenze, trasformazioni, lookup, deduplicazione, transazioni, pianificazioni e controlli di coerenza, mantenendo tracciabilità e affidabilità.

È proprio in questa direzione che si è evoluto il nostro ETL Engine, trasformandosi progressivamente da semplice strumento di importazione dati in una piattaforma completa per la progettazione e l'esecuzione di processi ETL professionali.

L'obiettivo è chiaro: rendere l'elaborazione dei dati più sicura, controllabile, ripristinabile e adatta anche a scenari enterprise.

Un ETL progettato per scenari reali

Un processo ETL reale non si limita al semplice schema:

SOURCE → TRANSFORM → DESTINATION

In produzione possono verificarsi:

  • interruzioni del processo;
  • perdita della connessione;
  • errori su singoli record;
  • duplicati;
  • dati non validi;
  • modifiche allo schema;
  • errori di rete;
  • timeout;
  • deadlock;
  • riavvio del computer;
  • necessità di riprendere un'elaborazione interrotta;
  • necessità di sapere esattamente cosa è successo.

Per questo motivo l'architettura è stata arricchita con numerosi meccanismi di controllo, monitoraggio e recupero dagli errori.

Checkpoint e Resume

Una delle funzionalità più importanti introdotte è il sistema di checkpoint e resume. Durante una lunga elaborazione l'ETL mantiene informazioni sul punto raggiunto.

In caso di interruzione non è quindi necessariamente necessario ricominciare dall'inizio. Il processo può riprendere dal checkpoint disponibile, riducendo i tempi di recupero e il carico sulle sorgenti e sulle destinazioni.

Il sistema tiene conto della corretta sequenza operativa:

READ
  ↓
TRANSFORM
  ↓
WRITE
  ↓
SUCCESS
  ↓
CHECKPOINT

Il checkpoint non viene avanzato semplicemente perché un record è stato letto. Questo evita uno degli errori più pericolosi nei sistemi ETL: considerare elaborato un record che in realtà non è stato correttamente scritto nella destinazione.

La gestione del checkpoint è stata inoltre separata dal semplice stato visuale dell'interfaccia, diventando parte effettiva del runtime di esecuzione.

Persistenza robusta

Il sistema dispone di una gestione dedicata della persistenza delle configurazioni e degli stati dell'ETL. La persistenza è stata progettata tenendo conto anche della possibilità di interruzione durante una scrittura.

Sono state introdotte strategie per:

  • salvataggio atomico;
  • gestione delle versioni;
  • verifica della consistenza;
  • backup e restore;
  • controllo della validità dei dati persistiti.

L'obiettivo è evitare che un'interruzione durante il salvataggio lasci il progetto in uno stato parzialmente scritto o inutilizzabile.

Transazioni reali

Un ETL professionale deve distinguere chiaramente tra record, batch, fase ed esecuzione. Il motore dispone di una gestione transazionale che consente di adottare strategie differenti in base allo scenario.

Particolare attenzione è stata dedicata alla modalità Transaction per Phase:

BEGIN
   ↓
operazioni ETL
   ↓
validazione
   ↓
COMMIT

In caso di errore:

BEGIN
   ↓
operazioni ETL
   ↓
ERRORE
   ↓
ROLLBACK

Questa modalità permette di ottenere una semantica più affidabile, mantenendo la fase come unità logica di elaborazione e controllo.

La gestione delle transazioni è stata separata dalle semplici operazioni di scrittura. In questo modo il runtime mantiene il controllo sul ciclo di vita della transazione.

Gestione del batch

L'elaborazione dei dati è stata progettata per lavorare a blocchi. Il concetto di batch consente di controllare meglio:

  • consumo di memoria;
  • frequenza dei commit;
  • checkpoint;
  • progressione;
  • gestione degli errori;
  • performance.
SOURCE
  ↓
BATCH
  ↓
TRANSFORM
  ↓
WRITE
  ↓
CHECKPOINT
  ↓
NEXT BATCH

Questa struttura è particolarmente importante quando si lavora con dataset di grandi dimensioni, importazioni massive o processi che devono mantenere un consumo di risorse prevedibile.

Lookup evoluti

Il motore dispone di un sistema Lookup dedicato, utilizzabile in diversi scenari operativi. È possibile utilizzare lookup:

  • precaricati;
  • on-demand;
  • con chiavi multiple;
  • con gestione dei duplicati;
  • con cache;
  • con query parametrizzate.

È stata inoltre introdotta una gestione esplicita delle politiche relative ai duplicati. Tra le modalità disponibili troviamo:

  • FIRST;
  • LAST;
  • ERROR.

Questo evita che la gestione dei duplicati sia lasciata a comportamenti impliciti. Il sistema dispone inoltre del concetto di LookupOrderBy, utile per controllare l'ordinamento quando necessario.

Deduplicazione e idempotenza

La deduplicazione è stata resa parte integrante del motore ETL. Il sistema può identificare record duplicati sulla base di chiavi e criteri configurabili.

SOURCE
  ↓
FILTER
  ↓
DEDUP
  ↓
TRANSFORM
  ↓
DESTINATION

In questo modo si riduce la necessità di implementare manualmente la logica di deduplicazione nei singoli progetti.

Un altro importante miglioramento riguarda l'idempotenza: l'obiettivo è evitare che la ripetizione della stessa elaborazione produca effetti indesiderati.

Sono stati introdotti concetti come:

  • Idempotency Key;
  • campi utilizzabili come chiave;
  • espressioni per la generazione della chiave;
  • verifica preventiva;
  • preload;
  • lookup on-demand;
  • gestione dei vincoli univoci.

L'idempotenza è particolarmente importante nei processi che utilizzano resume, retry, scheduler e REST, perché un processo interrotto potrebbe dover rieseguire una parte dei dati.

Dead Letter Queue

Gli errori sui singoli record non devono necessariamente compromettere l'intera elaborazione. Per questo è stata introdotta una Dead Letter Queue.

I record problematici possono essere isolati e registrati in una struttura dedicata, ad esempio:

.deadletter.jsonl

Il flusso può quindi essere rappresentato in questo modo:

PROCESSO
   │
   ├── Record OK
   │
   └── Record ERROR
             ↓
       DEAD LETTER

Il vantaggio è significativo: un errore circoscritto può essere analizzato senza perdere la visibilità sull'intera elaborazione.

Audit Trail e monitoraggio

Il motore dispone di un sistema di audit che permette di registrare le attività dell'elaborazione. L'obiettivo non è soltanto sapere che l'importazione è terminata, ma poter ricostruire:

  • quale esecuzione è partita;
  • quale fase era in esecuzione;
  • quali batch sono stati elaborati;
  • quali errori si sono verificati;
  • quando l'esecuzione è terminata.

L'Audit Trail costituisce quindi la base per una maggiore tracciabilità operativa e per una diagnosi più rapida dei problemi.

Il motore dispone inoltre di componenti dedicati a report e feedback dell'esecuzione:

START
 ↓
SOURCE
 ↓
TRANSFORM
 ↓
DESTINATION
 ↓
RESULT

La visibilità sull'avanzamento è particolarmente importante per importazioni lunghe, milioni di record, operazioni batch ed elaborazioni schedulate.

Expression Engine 2

Una delle evoluzioni più importanti del progetto è il nuovo Expression Engine 2. Il motore non si limita più alle semplici trasformazioni di campo, ma introduce una vera famiglia di funzioni logiche:

  • IF;
  • AND;
  • OR;
  • NOT;
  • EQ;
  • NE;
  • GT;
  • GE;
  • LT;
  • LE.

Per esempio:

IF(
    GT([IMPORTO], 1000),
    "ALTO",
    "NORMALE"
)

Oppure:

AND(
    GE([ETA], 18),
    LT([ETA], 65)
)

E ancora:

OR(
    EQ([STATO], "A"),
    EQ([STATO], "B")
)

Il vantaggio principale è la possibilità di costruire trasformazioni complesse mantenendo la logica all'interno del motore ETL, senza dover ricorrere continuamente a codice personalizzato.

Wizard per le espressioni

L'Expression Engine è stato accompagnato da strumenti visuali per la costruzione delle espressioni. Questo riduce la necessità di scrivere manualmente formule complesse.

Il progettista può costruire una trasformazione partendo dai campi disponibili e dalle funzioni supportate, con un approccio più vicino a un vero ambiente visuale di progettazione ETL.

Condizioni e trasformazioni

La gestione delle condizioni è stata integrata nell'architettura del motore. È quindi possibile realizzare scenari come:

IF condizione
    → destinazione A
ELSE
    → destinazione B

Le condizioni possono essere combinate con AND, OR e NOT, insieme ai confronti EQ, NE, GT, GE, LT e LE.

Schema Fingerprint e Type Compatibility

Lo schema di una tabella non è statico nel tempo. Possono cambiare colonne, tipi, lunghezze, proprietà nullable, struttura e metadati.

La gestione dello Schema Fingerprint consente di confrontare lo schema atteso con quello effettivamente disponibile.

ETL progettato ieri
        ↓
database modificato oggi
        ↓
schema differente
        ↓
rischio di errore

Il controllo dello schema diventa così una fase importante della validazione del processo.

Il sistema dispone inoltre di controlli di compatibilità tra i tipi, particolarmente importanti durante la generazione o l'esecuzione delle operazioni di mapping.

SOURCE TYPE
    ↓
non compatibile
    ↓
DESTINATION TYPE

Il motore può quindi individuare potenziali incompatibilità prima che il problema provochi un errore durante la scrittura.

Data Compare

È stato introdotto un sistema di confronto dei dati. Il Data Compare consente di confrontare sorgente e destinazione per individuare:

  • record mancanti;
  • record differenti;
  • record presenti da una sola parte;
  • differenze nei valori.

È stata inoltre introdotta una modalità di preview con limite controllato, evitando che una semplice operazione di analisi carichi quantità potenzialmente enormi di dati.

CSV, Fixed Layout e REST

Il motore dispone di funzionalità dedicate all'estrazione e all'importazione di dati da sorgenti non esclusivamente database.

Sono presenti componenti per:

  • file CSV;
  • file a layout fisso;
  • estrazione dati;
  • mapping dei campi.

È quindi possibile costruire flussi come:

CSV
 ↓
ETL
 ↓
DATABASE

Oppure:

DATABASE
 ↓
ETL
 ↓
FIXED LAYOUT

Il motore integra inoltre funzionalità REST per consentire lo scambio di dati con servizi esterni.

DATABASE
   ↓
ETL
   ↓
REST API

Oppure:

REST API
   ↓
ETL
   ↓
DATABASE

La gestione delle richieste è integrata nell'architettura del processo e può quindi essere utilizzata insieme a trasformazioni, mapping e gestione degli errori.

Scheduler ed esecuzione automatizzata

È stato sviluppato un sistema di pianificazione integrato. L'ETL può quindi essere utilizzato non soltanto manualmente, ma anche come processo automatizzato.

Sono stati introdotti elementi per:

  • gestione delle pianificazioni;
  • elenco degli scheduler;
  • dialog di configurazione;
  • gestione delle esecuzioni;
  • controllo delle attività pianificate.

L'architettura considera anche il problema della concorrenza attraverso meccanismi di Execution Gate e Distributed Locking. Questo evita che lo stesso job venga eseguito contemporaneamente quando non previsto.

Gestione della concorrenza

Un ETL moderno può avere contemporaneamente scheduler, REST, esecuzioni manuali, elaborazioni in background, lookup e operazioni sul database.

Il sistema dispone quindi di meccanismi per controllare l'accesso concorrente alle risorse e impedire che più esecuzioni entrino in conflitto.

Questo è fondamentale quando più processi utilizzano:

  • la stessa configurazione;
  • lo stesso database;
  • lo stesso checkpoint;
  • gli stessi file di persistenza.

L'Execution Gate può essere rappresentato in questo modo:

REQUEST EXECUTION
       ↓
   EXECUTION GATE
       ↓
   ┌───┴───┐
   │       │
  OK     BUSY
   │       │
 START  WAIT/STOP

Questo contribuisce a rendere il comportamento dell'ETL più prevedibile e controllabile.

Integrazione con l'intelligenza artificiale

Il progetto dispone inoltre di un componente dedicato all'integrazione AI. Questo apre la strada a scenari in cui l'intelligenza artificiale può assistere nella progettazione e nella gestione delle trasformazioni.

L'integrazione AI è stata mantenuta separata dal core del motore, evitando di rendere l'esecuzione ETL dipendente dall'intelligenza artificiale.

È un approccio importante: l'AI può assistere il progettista, ma il motore ETL deve rimanere deterministico, verificabile e prevedibile.

Connessioni e sicurezza SQL

La gestione delle connessioni è stata separata in componenti dedicati. Questo consente di gestire in maniera più ordinata:

  • apertura;
  • riutilizzo;
  • materializzazione;
  • chiusura;
  • gestione delle risorse.

L'obiettivo è evitare che il codice delle trasformazioni debba occuparsi direttamente di tutti gli aspetti infrastrutturali delle connessioni.

È presente anche un componente dedicato alla gestione sicura degli identificatori SQL. Questo è particolarmente importante quando nomi di tabelle, colonne, schemi o database devono essere utilizzati nella costruzione dinamica delle query.

La separazione della gestione degli identificatori dal resto del codice riduce il rischio di generare SQL non valido o ambiguo.

Test automatici e architettura modulare

Il progetto dispone di una base di test automatizzati, con test dedicati a componenti fondamentali come la gestione degli identificatori SQL e il Lookup.

Questa base costituisce il punto di partenza per verificare automaticamente le parti più delicate del motore e supportare le successive attività di hardening.

L'evoluzione del progetto ha portato alla separazione di numerosi componenti:

FDDataMapper
FDDataMapperExecute
FDDataMapperCheckpoint
FDDataMapperPersistence
FDDataMapperExpression
FDDataMapperExpression2
FDDataMapperLookup
FDDataMapperCondition
FDDataMapperSchemaFingerprint
FDDataMapperExtract
FDDataMapperSchedule
FDDataMapperAI
FDDataMapperReport
FDTreeExplorerDataCompare
FDTreeExplorerCompare

Questa organizzazione permette di mantenere separate responsabilità diverse. Il risultato è un'architettura molto più adatta all'evoluzione rispetto a un motore ETL monolitico.

Un ETL costruito per il recupero dagli errori

Uno degli aspetti più importanti dell'evoluzione del progetto è il cambio di filosofia. Un errore non viene più considerato necessariamente come:

ERROR → STOP EVERYTHING

Ma può diventare:

ERROR
  ↓
CLASSIFY
  ↓
LOG
  ↓
DEAD LETTER
  ↓
CONTINUE / ROLLBACK

Il comportamento dipende dalla politica configurata e dal tipo di errore. Questo è esattamente l'approccio necessario per sistemi destinati a processare grandi quantità di dati in contesti operativi reali.

Dalla semplice importazione all'ETL enterprise

Considerando tutte le funzionalità introdotte, l'architettura può essere rappresentata così:

                    ┌───────────────┐
                    │   Scheduler   │
                    └───────┬───────┘
                            │
                            ▼
                    ┌───────────────┐
                    │ Execution Gate│
                    └───────┬───────┘
                            │
                            ▼
┌───────────┐       ┌────────────────┐       ┌─────────────┐
│  SOURCE   │──────▶│   ETL ENGINE   │──────▶│ DESTINATION │
└───────────┘       └────────────────┘       └─────────────┘
                            │
             ┌──────────────┼──────────────┐
             ▼              ▼              ▼
        Expression       Lookup          Dedup
          Engine
             │              │              │
             └──────────────┼──────────────┘
                            ▼
                     ┌──────────────┐
                     │ Transaction  │
                     └──────┬───────┘
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
        Checkpoint      Audit Trail    Dead Letter
              │
              ▼
            Resume

Questa architettura consente di gestire processi molto più complessi rispetto al tradizionale modello:

SELECT → INSERT

Una piattaforma pensata per i dati critici

Le funzionalità introdotte hanno un obiettivo comune: ridurre il rischio operativo.

Quando un ETL gestisce dati amministrativi, finanziari, tributari o aziendali, non è sufficiente che funzioni nel caso ideale. Deve continuare a comportarsi correttamente anche quando:

  • una connessione cade;
  • un record è errato;
  • una fase fallisce;
  • il processo viene interrotto;
  • il database cambia struttura;
  • la destinazione contiene duplicati;
  • un job viene avviato due volte;
  • è necessario riprendere un'elaborazione.

È proprio in questi scenari che emergono le differenze tra un semplice importatore e un vero motore ETL.

Il risultato non è semplicemente un programma che sposta dati. È un motore ETL orientato all'affidabilità, progettato per gestire trasformazioni, controlli, errori, ripartenze, pianificazioni e grandi quantità di informazioni mantenendo il processo sotto controllo.

#SQL #database #ETL #DataEngineering #plyxSQL #FireDAC #PGSOFT

lunedì 21 settembre 2026

Free PlyxSQL© - 1.0.0.101 Super ETL

 Free PlyxSQL© - 1.0.0.101 Super ETL

POSTED BY Giuliano pagnini, 21 SETT 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml


Expression Engine 2: il nuovo motore che trasforma l’ETL in intelligenza operativa



Nel mondo dell’integrazione dati non basta più spostare informazioni da una tabella a un’altra. Oggi un processo ETL deve interpretare, normalizzare, validare e classificare i dati secondo regole di business sempre più articolate.

È da questa esigenza che nasce Expression Engine 2: il nuovo motore di espressioni progettato per portare l’ETL oltre il semplice mapping, trasformandolo in una piattaforma dichiarativa, estensibile e pronta per scenari professionali.

Dal mapping alle decisioni

Un mapping tradizionale risolve un’esigenza semplice:

SOURCE.COGNOME → DEST.COGNOME

Ma i dati reali raramente arrivano già pronti per essere utilizzati.

Un cognome può contenere spazi superflui, differenze di maiuscole e minuscole, formati non uniformi o valori mancanti. In questi casi non serve soltanto copiare un campo: serve applicare una trasformazione.

SOURCE.COGNOME
        ↓
      TRIM
        ↓
     PROPER
        ↓
DEST.COGNOME

Oppure può essere necessario assegnare una classificazione in base al contenuto di uno o più campi:

SOURCE.STATO
        ↓
      CASE
        ↓
DEST.DESCRIZIONE_STATO

Expression Engine 2 nasce proprio per questo: permettere di combinare funzioni, confronti, condizioni e regole direttamente nella configurazione ETL, senza dover scrivere codice specifico per ogni singolo caso.

Un vero motore di espressioni

La differenza principale rispetto a un sistema basato su funzioni isolate è l’architettura.

Expression Engine 2 segue un flusso concettuale chiaro:

Expression
    ↓
Lexer
    ↓
Parser
    ↓
AST
    ↓
Evaluator
    ↓
Result

L’espressione non viene più gestita come una semplice stringa da analizzare con controlli successivi. Viene interpretata, trasformata in una struttura interna e poi valutata in modo coerente.

Il cuore di questa evoluzione è l’AST, Abstract Syntax Tree: un albero che rappresenta la struttura logica dell’espressione.

Per esempio, una regola come:

{STATO} = "A" AND {IMPORTO} >= 1000

può essere rappresentata internamente così:

AND
├── EQ
│   ├── FIELD(STATO)
│   └── "A"
│
└── GE
    ├── FIELD(IMPORTO)
    └── 1000

Questo approccio rende il motore più robusto, più leggibile e soprattutto più semplice da estendere nel tempo. Nuove funzioni, operatori e controlli possono essere introdotti senza riscrivere continuamente il nucleo del parser.

La nuova logica ETL

Una delle novità più importanti di Expression Engine 2 è la famiglia di funzioni logiche:

IF
AND
OR
NOT
EQ
NE
GT
GE
LT
LE

Non si tratta di una semplice raccolta di comandi. È un vero sistema per costruire regole decisionali direttamente nei flussi di trasformazione.

Il modello è semplice ma potente:

DATI
↓
CONFRONTO
↓
TRUE / FALSE
↓
LOGICA
↓
IF / CASE
↓
RISULTATO

Le funzioni di confronto producono condizioni booleane. Le funzioni logiche combinano tali condizioni. IF e CASE trasformano il risultato in un valore concreto utilizzabile nella pipeline ETL.

IF: quando il dato diventa una decisione

La sintassi di base è:

IF(condizione; valore_se_vero; valore_se_falso)

Esempio:

IF(
   EQ({STATO};"A");
   "ATTIVO";
   "NON ATTIVO"
)

Il motore confronta il valore di STATO con "A".

  • Se il confronto è vero, restituisce ATTIVO
  • Se il confronto è falso, restituisce NON ATTIVO

Questa è la differenza tra una trasformazione meccanica e una trasformazione intelligente: il processo ETL non si limita a trasferire dati, ma applica una regola di business.

Confronti chiari e dichiarativi

FunzioneSignificatoEsempio
EQUguale aEQ({STATO};"A")
NEDiverso daNE({STATO};"A")
GTMaggiore diGT({IMPORTO};1000)
GEMaggiore o ugualeGE({ETA};18)
LTMinore diLT({IMPORTO};1000)
LEMinore o ugualeLE({ETA};18)

Un esempio immediato:

IF(
   GE({ETA};18);
   "MAGGIORENNE";
   "MINORENNE"
)

Oppure:

IF(
   GT({IMPORTO};1000);
   "IMPORTO ALTO";
   "IMPORTO NORMALE"
)

Queste espressioni consentono di trasformare soglie, regole e classificazioni in configurazioni riutilizzabili, anziché in logica C++ dispersa nel codice applicativo.

Regole complesse senza codice dedicato

Il vero valore non è nella singola funzione, ma nella possibilità di combinarle.

Immaginiamo una regola operativa: se il record è attivo e l’importo è almeno 1.000, classificalo come prioritario. In tutti gli altri casi, classificalo come normale.

IF(
   AND(
      EQ({STATO};"A");
      GE({IMPORTO};1000)
   );
   "PRIORITARIO";
   "NORMALE"
)

Oppure, quando il numero di scenari cresce, con CASE:

CASE(
   AND(
      EQ({STATO};"A");
      GE({IMPORTO};10000)
   );
   "PRIORITARIO";

   AND(
      EQ({STATO};"A");
      GE({IMPORTO};1000)
   );
   "NORMALE";

   EQ({TIPO};"URGENTE");
   "URGENTE";

   "STANDARD"
)

Questa espressione rappresenta una vera regola di business:

  • Attivo con importo pari o superiore a 10.000: PRIORITARIO
  • Attivo con importo pari o superiore a 1.000: NORMALE
  • Tipo urgente: URGENTE
  • Tutti gli altri casi: STANDARD

Il vantaggio è enorme: la regola può essere letta, modificata, testata e configurata senza creare codice speciale per ogni flusso.

Normalizzazione, NULL e Data Quality

Nei progetti ETL più complessi, il problema non è soltanto capire quale valore sia presente. È capire se il valore è davvero utilizzabile.

Expression Engine 2 integra il ragionamento logico con funzioni dedicate ai valori mancanti e alla normalizzazione:

ISNULL
ISEMPTY
ISBLANK
COALESCE
TRIM
UPPER
LENGTH

Esempio: assegnare un CAP predefinito quando il valore è assente, vuoto o composto solo da spazi.

IF(
   ISBLANK({CAP});
   "00000";
   {CAP}
)

Oppure scegliere il primo identificativo disponibile:

COALESCE(
   {CODICE_FISCALE};
   {PARTITA_IVA};
   {CODICE};
   "N/D"
)

Le funzioni possono anche essere composte per ottenere confronti affidabili:

EQ(
   UPPER(TRIM({COMUNE}));
   "RICCIONE"
)

In questo modo valori come riccione, RICCIONE e Riccione vengono normalizzati prima del confronto, riducendo errori e anomalie nei dati in ingresso.

La base per un Data Quality Engine

La logica introdotta da Expression Engine 2 apre la strada a una vera gestione della qualità del dato.

Per esempio, è possibile verificare che un codice sia presente e abbia una lunghezza precisa:

AND(
   NOT(ISBLANK({CODICE}));
   EQ(LENGTH({CODICE});16)
)

Oppure controllare in modo dichiarativo la presenza e la validità di un indirizzo email:

AND(
   NOT(ISBLANK({EMAIL}));
   REGEXMATCH({EMAIL};"...")
)

Il risultato di queste espressioni può essere utilizzato per:

  • Validare un record prima dell’importazione
  • Assegnare uno stato di qualità
  • Generare warning o segnalazioni
  • Inviare record incompleti in un flusso alternativo
  • Separare dati validi, incompleti e da verificare
  • Preparare processi di deduplicazione e normalizzazione
SOURCE
↓
TRANSFORM
↓
NORMALIZE
↓
VALIDATE
↓
DATA QUALITY
↓
LOOKUP
↓
DEDUP
↓
DESTINATION

Expression Engine 2 non è quindi solo un componente di trasformazione: può diventare il livello decisionale dell’intera pipeline dati.

Sintassi per persone, wizard e AI

L’architettura è stata progettata per supportare sia una sintassi funzionale esplicita sia, in prospettiva, una sintassi più naturale basata su operatori.

La forma funzionale:

AND(
   EQ({STATO};"A");
   GE({IMPORTO};1000)
)

è ideale per generatori automatici, wizard visuali, configurazioni strutturate, sistemi AI che producono regole e validazioni automatiche delle espressioni.

La forma espressiva:

{STATO} = "A" AND {IMPORTO} >= 1000

può invece risultare più immediata per utenti tecnici, analisti e sviluppatori.

L’obiettivo è fare in modo che le due sintassi confluiscano nello stesso AST interno. In questo modo il motore può offrire semplicità a chi configura e solidità a chi sviluppa.

Prestazioni e crescita futura

Una vera struttura logica permette anche di introdurre meccanismi evoluti come lo short-circuit evaluation.

In una condizione AND, se una parte della regola è già falsa, il motore può evitare calcoli non necessari. In una condizione OR, se una condizione è già vera, le altre potrebbero non essere valutate.

Su grandi quantità di record, questo può fare la differenza.

L’architettura di Expression Engine 2 prepara inoltre il terreno per funzionalità future:

  • Operatori matematici e relazionali
  • Precedenza degli operatori e parentesi
  • Funzioni definite dall’utente
  • Diagnostica dettagliata degli errori
  • Validazione semantica delle formule
  • Autocompletamento e Expression Wizard
  • Preview delle trasformazioni
  • Test automatici delle regole
  • Data Lineage
  • Funzioni dedicate ai dati italiani
  • Generazione di espressioni mediante AI

Non si tratta quindi soltanto di aggiungere funzioni. Si tratta di costruire un linguaggio dichiarativo specializzato per l’ETL, capace di evolvere insieme alle esigenze applicative.

Expression Engine 2 segna il passaggio da un sistema di mapping a una piattaforma capace di rappresentare vere regole di business.

Con funzioni come IF, AND, OR, NOT, EQ, NE, GT, GE, LT e LE, un processo ETL può analizzare i dati, prendere decisioni e produrre risultati coerenti direttamente nella configurazione della trasformazione.

DATI
↓
NORMALIZZAZIONE
↓
CONFRONTO
↓
CONDIZIONE
↓
LOGICA
↓
DECISIONE
↓
TRASFORMAZIONE
↓
DESTINAZIONE

Expression Engine 2 non è semplicemente una nuova versione di un motore esistente.

È la base per portare nell’ETL regole di business, Data Quality, validazione, automazione e intelligenza configurabile — direttamente dove i dati vengono trasformati.

#SQL #database #ETL #DataEngineering #plyxSQL #FireDAC #PGSOFT

venerdì 18 settembre 2026

Free PlyxSQL© Beta - 1.0.0.99 Super ETL

Free PlyxSQL© Beta - 1.0.0.99 Super ETL

POSTED BY Giuliano pagnini, 18 SETT 2026

Free DOWNLOAD Clicca qui Info https://pgsoft.it/plyxhtml


SUPER ETL con PLYXSQL: il motore di mapping diventa ancora più potente

Trasformare dati non significa soltanto spostarli da una tabella a un’altra. Significa riconoscere formati diversi, pulire testi, classificare valori, intercettare anomalie, rispettare le dimensioni dei campi e garantire che una singola riga problematica non blocchi un’intera importazione.

Con gli ultimi aggiornamenti, PlyxSQL evolve in modo deciso: il suo motore ETL diventa più espressivo, più guidato e più resistente agli errori reali che si incontrano ogni giorno tra CSV, Excel, archivi legacy, gestionali esterni e basi dati di destinazione.

Il risultato è un sistema di mapping ancora più completo, capace di gestire logiche condizionali articolate senza scrivere codice e di rendere più sicure anche le importazioni più complesse.

CASE: la logica condizionale entra nel mapping

Una delle novità più importanti è la funzione CASE, disponibile nell’Assistente Espressione.

Fino a poco tempo fa, per realizzare una logica del tipo “se il valore è questo fai una cosa, se è un altro fai un’altra cosa, altrimenti usa un valore predefinito”, era necessario combinare più regole:

  • Una regola con valore costante.
  • Una condizione “Esegui regola solo se”.
  • Un ramo alternativo.
  • Ulteriori annidamenti per coprire più casi.

Era un approccio funzionale, ma quando le condizioni diventavano tre, quattro o dieci, la configurazione rischiava di diventare difficile da leggere, verificare e mantenere.

Ora tutta la logica può essere espressa in una sola formula:

CASE(Permanenti;2;Temporanei;3;1)

Il significato è immediato:

Valore in ingresso Risultato
Permanenti 2
Temporanei 3
Qualsiasi altro valore 1

L’ultimo parametro rappresenta il valore di default: ciò che PlyxSQL deve usare quando nessuna delle condizioni precedenti è soddisfatta.

Questa funzione è particolarmente utile nei mapping di anagrafiche, classificazioni, stati, tipologie contrattuali, codici di provenienza, ruoli, categorie tributarie e valori provenienti da archivi non standardizzati.

Confronti diretti e regex

Ogni condizione di CASE può essere scritta come confronto testuale diretto. Il confronto è case-insensitive, quindi non distingue tra maiuscole e minuscole.

CASE(Residente;R;Non Residente;N;Da verificare)

In questo caso, Residente, RESIDENTE e residente vengono gestiti nello stesso modo.

Quando serve maggiore flessibilità, è possibile usare un pattern regex anteponendo il carattere ~.

CASE(~mq5;1;6)

Questa espressione assegna:

  • 1 a tutti i valori che contengono mq5.
  • 6 a tutti gli altri valori.
Codice sorgente Risultato
mq5 1
abc_mq5_01 1
MQ5 1
mq6 6
altro_codice 6

La funzione CASE consente quindi di concentrare una logica di classificazione completa direttamente nella trasformazione del singolo campo, evitando la proliferazione di regole separate.

Compositore CASE: tutta la potenza, senza sintassi da imparare


Scrivere espressioni manualmente è utile per chi conosce bene regex e logiche di trasformazione. Tuttavia, un motore ETL efficace deve essere accessibile anche a chi vuole configurare mapping complessi senza ricordare sintassi, parentesi, separatori o caratteri speciali.

Per questo PlyxSQL  introduce il Compositore CASE.

Il funzionamento è guidato passo per passo:

  1. Si sceglie il tipo di confronto da un menu.
  2. Si inserisce il valore da cercare.
  3. Si definisce il risultato da restituire.
  4. Si preme “Aggiungi caso”.
  5. Si ripete l’operazione per tutte le condizioni necessarie.
  6. Si definisce il valore finale di default.

I tipi di confronto disponibili rendono immediata la costruzione delle regole più comuni:

  • Inizia con.
  • Contiene.
  • Finisce con.
  • Uguale a.
  • Vuoto.
  • Non vuoto.

Mentre l’utente compone i casi, PlyxSQL  genera in tempo reale l’espressione CASE(...) corrispondente.

L’anteprima live permette di capire subito quale formula verrà applicata al campo, senza dover scrivere manualmente la funzione e senza il rischio di errori formali.

Una logica che prima richiedeva esperienza tecnica può ora essere configurata con pochi click, rimanendo comunque trasparente, verificabile e modificabile in qualsiasi momento.

Tre nuove funzioni per pulire i dati

I dati provenienti da Excel, CSV, esportazioni gestionali e archivi storici raramente sono già pronti per essere scritti nella base dati di destinazione. Nomi in minuscolo, codici incompleti, descrizioni non uniformi e caratteri da sostituire sono problemi ricorrenti.

Per affrontarli direttamente nel mapping, PLYXSQL aggiunge tre nuove funzioni di trasformazione testo.

PROPER: nomi e descrizioni più ordinati

La funzione PROPER trasforma la prima lettera di ogni parola in maiuscola.

PROPER(mario rossi)

Risultato:

Mario Rossi

È ideale per normalizzare campi come nominativi, ragioni sociali, città, indirizzi, descrizioni, titoli e denominazioni.

Valore sorgente Espressione Risultato
mario rossi PROPER(...) Mario Rossi
comune di bologna PROPER(...) Comune Di Bologna
via giuseppe garibaldi PROPER(...) Via Giuseppe Garibaldi

Per nomi con particelle, acronimi o convenzioni particolari, il risultato può essere ulteriormente raffinato con regole dedicate. Per la normalizzazione iniziale dei dati importati, però, PROPER elimina rapidamente una delle anomalie più comuni.

REPLACE: sostituzioni semplici, senza regex

La funzione REPLACE(testo;sostituto) esegue una sostituzione letterale di tutte le occorrenze di un testo.

REPLACE(-;/)

Può essere usata, ad esempio, per uniformare separatori, eliminare prefissi, correggere abbreviazioni o sostituire caratteri non desiderati.

A differenza delle espressioni regolari, REPLACE non interpreta i caratteri come operatori speciali. Questo la rende particolarmente comoda quando serve una sostituzione diretta e prevedibile, senza dover effettuare escape di parentesi, punti, barre, trattini o altri simboli.

Valore sorgente Trasformazione Risultato
BO-2026-00125 Sostituisce - con / BO/2026/00125
Via Roma n. 12 Sostituisce n. con numero Via Roma numero 12
Cod. Fisc. Sostituisce Cod. con Codice Codice Fisc.

PAD: codici sempre della lunghezza corretta

La funzione PAD(n;carattere) completa il valore a sinistra fino a raggiungere una lunghezza fissa.

PAD(5;0)

Applicata al valore 123, produce:

00123

Questa funzione è essenziale quando un sistema sorgente esporta codici numerici perdendo gli zeri iniziali, mentre il sistema di destinazione richiede una lunghezza precisa.

Gli utilizzi tipici comprendono CAP, matricole, codici cliente, codici prodotto, numeri protocollo, identificativi territoriali e codici di classificazione a lunghezza fissa.

Valore sorgente Regola Risultato
123 PAD(5;0) 00123
45 PAD(4;0) 0045
7 PAD(3;0) 007

Stop agli overflow: PlyxSQL  protegge l’importazione

Uno degli errori più frustranti nelle operazioni ETL è il classico:

Variable length column overflow

Accade quando un valore proveniente dalla sorgente supera la lunghezza massima del campo testuale nella tabella di destinazione.

In un’importazione tradizionale, anche una singola descrizione troppo lunga, una ragione sociale estesa o un indirizzo anomalo possono interrompere l’intera elaborazione. Il risultato è tempo perso, importazioni incomplete e necessità di analizzare manualmente record che spesso sono pochi rispetto al volume totale.

Con il nuovo comportamento di PLYXSQL, il motore controlla automaticamente la dimensione delle colonne testuali di destinazione.

Se il valore generato dalla regola supera la lunghezza prevista:

  1. Il valore viene troncato automaticamente.
  2. L’importazione prosegue senza blocchi.
  3. Al termine, PLYXSQL produce un riepilogo.
  4. Il riepilogo indica quanti valori sono stati troncati.
  5. Il riepilogo mostra su quali campi è avvenuto il troncamento.

Questo approccio rispecchia una filosofia precisa: un dato anomalo deve essere segnalato, non deve bloccare il lavoro.

La qualità del dato rimane sotto controllo grazie al log finale, ma il processo ETL non viene fermato da un’unica eccezione. È un vantaggio particolarmente rilevante nelle importazioni massive, nei caricamenti periodici e nelle migrazioni da archivi storici.

Nuova condizione: “Contiene una data valida”

Le date sono tra i campi più delicati in assoluto. Possono essere assenti, scritte in modo incompleto, invertite, esportate come testo oppure contaminate da valori non validi.

PLYXSQL aggiunge una nuova condizione per “Esegui regola solo se”:

Contiene una data valida

L’utente indica il formato atteso, per esempio:

dd/mm/yyyy

La condizione verifica che il valore del campo sia realmente interpretabile come una data valida nel formato indicato.

Questo permette di separare due operazioni che spesso vengono confuse:

  • Verificare che il valore sia una data corretta.
  • Convertire quel valore nel formato richiesto dalla destinazione.

La validazione viene applicata prima della trasformazione vera e propria. Solo se il campo supera il controllo, è possibile eseguire una regola come:

DATE(dd/mm/yyyy)
Valore sorgente Condizione “data valida” Conversione DATE Esito
15/09/2026 Superata Eseguita Data importata
31/02/2026 Non superata Non eseguita Riga gestita separatamente
abc Non superata Non eseguita Nessuna conversione errata
Valore vuoto Non superata Non eseguita Campo vuoto o valore predefinito

Regex anche nelle condizioni

PLYXSQL dispone già di un catalogo di pattern pronti all’uso per funzioni come:

REGEXMATCH
REGEXEXTRACT
REGEXREPLACE

Con questo aggiornamento, il catalogo è disponibile anche direttamente nel pannello delle condizioni quando si seleziona:

Corrisponde al pattern regolare

Questo rende più semplice costruire controlli robusti senza dover ricordare o riscrivere ogni volta le espressioni regolari.

Tra i pattern disponibili rientrano controlli per:

  • CAP.
  • Città.
  • Codici fiscali.
  • IBAN.
  • Date.
  • Numeri.
  • Indirizzi con civico.
  • Indirizzi con interno.
  • Indirizzi con scala.
  • Strutture testuali ricorrenti.

Le regex non sono più uno strumento riservato a chi conosce nel dettaglio la sintassi dei pattern. Diventano una risorsa configurabile dall’interfaccia, utile per validare e classificare i dati prima di eseguire il mapping.

Deduplica completamente localizzata

Anche gli interventi apparentemente meno visibili contribuiscono alla qualità complessiva dell’esperienza.

La finestra di configurazione della funzione Elimina Duplicati e i relativi messaggi di log, che in precedenza contenevano alcune parti hardcoded, sono stati completamente riportati nel sistema di traduzione dell’applicazione.

Il risultato è un’interfaccia più coerente con il resto di PLYXSQL e pronta per supportare future localizzazioni senza dover intervenire sulla logica della funzione.

Per chi utilizza il prodotto in contesti internazionali, distribuisce procedure a più operatori o realizza soluzioni verticali multilingua, questa è una base importante: non una semplice traduzione di etichette, ma una gestione più ordinata e scalabile dell’interfaccia.

Un piccolo fix che elimina un grande fastidio

L’ultimo miglioramento riguarda l’albero di selezione dei campi.

In alcune situazioni, facendo click su un nodo, poteva accadere che una checkbox già selezionata venisse deselezionata accidentalmente. Il problema dipendeva da un’area sensibile al click troppo ampia attorno alla casella di selezione.

È uno di quei difetti piccoli sulla carta, ma fastidiosi nel lavoro reale: soprattutto quando si configurano mapping con molti campi, una selezione modificata involontariamente può causare errori difficili da individuare.

Ora l’area di rilevamento del click si adatta dinamicamente al testo effettivo del nodo. Il comportamento è quindi più preciso, affidabile e coerente con ciò che l’utente vede nell’interfaccia.

Un motore ETL progettato per il lavoro reale

Esigenza operativa Nuova soluzione PLYXSQL
Classificare più valori con logica “se/altrimenti” Funzione CASE
Creare CASE senza ricordare sintassi o regex Compositore CASE guidato
Normalizzare nomi e descrizioni PROPER
Sostituire testo senza complessità regex REPLACE
Ripristinare zeri iniziali e lunghezze fisse PAD
Evitare blocchi per campi troppo lunghi Troncamento automatico con riepilogo finale
Validare date prima della conversione Condizione “Contiene una data valida”
Usare pattern pronti nelle condizioni Assistente regex
Preparare l’interfaccia a più lingue Localizzazione completa della deduplica
Ridurre errori di selezione nell’interfaccia Correzione dell’area click delle checkbox


Con queste evoluzioni, PlyxSQL consolida il proprio ruolo di motore per l’integrazione e la trasformazione dei dati: una soluzione pensata per chi deve configurare importazioni, conversioni e mapping complessi in modo visuale, controllato e senza dover sviluppare script dedicati per ogni eccezione.

La funzione CASE elimina gran parte degli annidamenti necessari per le classificazioni multiple. Il Compositore CASE rende questa potenza disponibile anche a chi non vuole scrivere espressioni a mano. Le nuove funzioni PROPER, REPLACE e PAD affrontano operazioni quotidiane di pulizia e normalizzazione.

I controlli automatici sulle dimensioni dei campi evitano interruzioni inutili, mentre la validazione delle date e il supporto regex nelle condizioni rendono il mapping più solido già in fase di configurazione.

In una parola: SUPER ETL.

Perché un processo di importazione affidabile non deve solo trasferire dati. Deve saperli interpretare, correggere, validare e accompagnare fino alla destinazione, anche quando la sorgente non è perfetta.

#SQL #database #ETL #DataEngineering #plyxSQL #FireDAC #PGSOFT

Server REST in C++Builder per VueLityx

Server REST in C++Builder per VueLityx© 

POSTED BY GIULIANO PAGNINI, 18 SETT 2026 




Server REST in C++Builder: una libreria professionale per creare API robuste, sicure e performanti

Trasformare C++Builder in un vero server REST

Realizzare un server REST moderno con C++Builder non significa necessariamente partire da zero.

La libreria REST Server nasce proprio con questo obiettivo: fornire agli sviluppatori C++Builder una base solida e riutilizzabile per realizzare API REST professionali, integrate direttamente con FireDAC e progettate per lavorare con database relazionali e applicazioni web moderne.

L'idea è semplice:

C++Builder + FireDAC + REST API + Connection Pooling = backend completo e performante.

La libreria è pensata per applicazioni gestionali, software per enti pubblici, sistemi ERP, applicazioni web, servizi desktop e architetture in cui un frontend Vue, Nuxt o qualsiasi altro client deve comunicare con un backend centralizzato.


Un'architettura pensata per la produzione

Uno dei principali vantaggi della libreria è la separazione delle responsabilità.

Il server è organizzato in componenti specializzati per:

  • gestione delle richieste REST;

  • autenticazione;

  • autorizzazione;

  • gestione utenti;

  • query database;

  • configurazione;

  • crittografia;

  • connection pooling;

  • logging;

  • gestione degli errori;

  • CORS e security headers.

Questo permette di evitare il classico problema dei server REST sviluppati rapidamente all'interno di un'unica unità di codice.

Ogni componente ha un compito preciso e può essere evoluto indipendentemente.


FireDAC come motore database

La libreria sfrutta direttamente FireDAC, evitando livelli di astrazione inutili e mantenendo tutte le potenzialità dell'ambiente C++Builder.

Questo significa poter utilizzare database come:

  • Firebird;

  • InterBase;

  • Oracle;

  • Microsoft SQL Server;

  • PostgreSQL;

  • MySQL;

  • SQLite.

La possibilità di utilizzare FireDAC direttamente è particolarmente importante nelle applicazioni gestionali dove query, transazioni e caratteristiche specifiche del database hanno un ruolo centrale.


Connection Pooling: il cuore delle prestazioni

Uno degli elementi più importanti della libreria è il connection pool.

Creare e distruggere continuamente connessioni database durante le richieste HTTP può diventare costoso, soprattutto quando il numero di richieste aumenta.

Il connection pool mantiene invece un insieme di connessioni pronte per essere utilizzate.

Ad esempio, con:

PoolSize = 8

il server può gestire contemporaneamente più richieste utilizzando un numero controllato di connessioni database.

Il meccanismo comprende:

  • checkout della connessione;

  • timeout di acquisizione;

  • riconsegna automatica;

  • rollback delle transazioni non concluse;

  • invalidazione delle connessioni problematiche;

  • ricostruzione automatica delle connessioni;

  • gestione dello shutdown;

  • protezione da accessi concorrenti.

Il risultato è un backend molto più adatto a scenari con numerose richieste simultanee.


Una connessione per richiesta

Un principio importante dell'architettura è il concetto di lease della connessione.

Una richiesta acquisisce una connessione dal pool e la mantiene per tutta la durata dell'operazione.

Al termine:

  • la connessione viene restituita al pool;

  • oppure viene invalidata se si è verificato un problema;

  • eventuali transazioni rimaste aperte vengono gestite correttamente.

Questo approccio rende più semplice mantenere una corretta gestione delle transazioni e riduce il rischio di lasciare connessioni in stati inconsistenti.


Transazioni Firebird e database relazionali

Le API REST non devono limitarsi a eseguire semplici SELECT.

In una vera applicazione gestionale è spesso necessario eseguire operazioni atomiche:

  1. inserimento di un documento;

  2. aggiornamento di più tabelle;

  3. registrazione di un movimento;

  4. aggiornamento di una situazione contabile;

  5. commit dell'intera operazione.

La libreria permette quindi di utilizzare le normali transazioni FireDAC.

Un esempio concettuale è:

Connection->StartTransaction();

try
{
    // INSERT
    // UPDATE
    // DELETE

    Connection->Commit();
}
catch (...)
{
    Connection->Rollback();
    throw;
}

In questo modo l'API può mantenere la stessa affidabilità delle applicazioni desktop tradizionali.


API REST per frontend moderni

Il backend può essere utilizzato come motore per applicazioni realizzate con:

  • Vue.js;

  • Nuxt;

  • React;

  • Angular;

  • applicazioni mobile;

  • Electron;

  • software desktop;

  • altri client HTTP.

Il frontend non deve conoscere la struttura interna del database.

Comunica semplicemente attraverso endpoint REST.

Un'architettura tipica può quindi essere:

                 ┌──────────────────┐
                 │   Vue / Nuxt     │
                 │    Frontend      │
                 └────────┬─────────┘
                          │ HTTPS
                          ▼
                 ┌──────────────────┐
                 │    REST API      │
                 │   C++Builder     │
                 └────────┬─────────┘
                          │
                   Connection Pool
                          │
                          ▼
                 ┌──────────────────┐
                 │     FireDAC      │
                 └────────┬─────────┘
                          │
                          ▼
                 ┌──────────────────┐
                 │ Firebird/Oracle  │
                 │   SQL Server...  │
                 └──────────────────┘

È una soluzione particolarmente interessante per trasformare applicazioni gestionali tradizionali in piattaforme web moderne.


Sicurezza integrata nell'architettura

Un server REST destinato alla produzione deve considerare la sicurezza fin dall'inizio.

La libreria è progettata per gestire diversi livelli di protezione:

  • autenticazione;

  • token JWT;

  • API Key;

  • gestione utenti;

  • autorizzazione;

  • CORS;

  • security headers;

  • request ID;

  • logging controllato;

  • protezione delle informazioni sensibili.

Un altro principio importante è evitare di inserire nei log informazioni che non dovrebbero essere registrate, come password, token o interi payload sensibili.


HTTPS e Reverse Proxy

In un'installazione professionale il server C++Builder può essere collocato dietro un reverse proxy.

L'architettura può quindi essere:

Internet
   │
   │ HTTPS
   ▼
Reverse Proxy
   │
   │ HTTP interno
   ▼
C++Builder REST Server
   │
   ▼
FireDAC / Database

Il reverse proxy può occuparsi della terminazione TLS, mentre il server REST rimane focalizzato sulla gestione delle API e del database.

Questa configurazione è particolarmente adatta a server Windows e infrastrutture aziendali.


Timeout e protezione dalla saturazione

Un problema frequente nei server database è la saturazione delle risorse.

La libreria utilizza timeout specifici per evitare che una richiesta possa rimanere indefinitamente in attesa.

Tra i parametri più importanti troviamo:

CheckoutTimeoutMs

Definisce per quanto tempo una richiesta può attendere una connessione libera dal pool.

CommandTimeoutSec

Limita il tempo concesso alle operazioni database.

DestroyTimeoutMs

Permette di controllare la fase di chiusura del pool durante lo shutdown.

Questi parametri diventano particolarmente importanti sotto carico elevato.


Progettata pensando alla concorrenza

Una API REST deve essere progettata per gestire richieste contemporanee.

La libreria utilizza meccanismi di sincronizzazione per proteggere le strutture condivise del connection pool e permettere a più richieste di lavorare contemporaneamente.

Un server configurato con:

PoolSize = 8

può essere sottoposto a test con:

20 richieste concorrenti
50 richieste concorrenti
100 richieste concorrenti
200 richieste concorrenti

Questi test permettono di verificare concretamente:

  • saturazione del pool;

  • timeout di checkout;

  • tempi medi di risposta;

  • percentili P50/P90/P95/P99;

  • errori database;

  • invalidazione delle connessioni;

  • comportamento delle transazioni;

  • capacità di recupero dopo un errore.

Non basta quindi dire che un server è "veloce": è necessario misurarne il comportamento sotto carico.


Connection invalidation e autoriparazione

In ambiente reale una connessione database può diventare inutilizzabile.

Può accadere, ad esempio, dopo:

  • una disconnessione di rete;

  • un restart del database;

  • un errore del server;

  • una connessione rimasta in uno stato non valido.

Invece di lasciare che una connessione guasta rimanga nel pool, la libreria permette di invalidarla.

Il pool può quindi creare una nuova connessione e, quando configurato per farlo, utilizzare un meccanismo di auto-healing.

Questo rende il server più resiliente agli errori temporanei.


Non solo CRUD

Una libreria REST professionale non deve essere limitata alle classiche operazioni CRUD.

Può diventare il livello applicativo attraverso cui esporre funzionalità molto più complesse:

GET     /api/comuni
GET     /api/tributi/2026
POST    /api/tributi
PUT     /api/tributi/123
DELETE  /api/tributi/123
POST    /api/login
POST    /api/token/refresh

Il database rimane dietro il server.

Il client vede esclusivamente le API definite dall'applicazione.

Questo permette di evolvere il database senza dover modificare necessariamente tutti i client.


Una base ideale per software gestionali

Uno degli scenari più interessanti è la trasformazione di un'applicazione gestionale C++Builder esistente in una piattaforma ibrida.

Il database Firebird può continuare a rappresentare il cuore del sistema mentre il nuovo backend REST diventa il punto di accesso per:

  • applicazioni web;

  • portali;

  • dashboard;

  • applicazioni mobile;

  • integrazioni con software esterni;

  • servizi automatici;

  • import/export;

  • sistemi di autenticazione centralizzati.

In questo modo non è necessario riscrivere immediatamente tutta l'applicazione esistente.


C++Builder diventa anche un backend moderno

Per molti anni C++Builder è stato associato principalmente allo sviluppo desktop Windows.

L'utilizzo di FireDAC, WebBroker e di una moderna architettura REST dimostra invece come sia possibile utilizzare C++Builder anche per costruire backend server moderni e ad alte prestazioni.

Il vantaggio principale è poter riutilizzare competenze, codice e infrastrutture già presenti nell'ecosistema C++Builder.

Non è quindi necessario introdurre un nuovo linguaggio esclusivamente per realizzare il backend.


Una libreria pensata per chi vuole controllo

La filosofia della libreria è diversa da quella dei framework che nascondono completamente il funzionamento del database e del server.

Qui lo sviluppatore mantiene il controllo su:

  • connessioni;

  • transazioni;

  • SQL;

  • timeout;

  • autenticazione;

  • pool;

  • gestione degli errori;

  • configurazione;

  • logging.

È un approccio particolarmente adatto a software gestionali e applicazioni professionali dove il database rappresenta una componente fondamentale dell'architettura.


Dal desktop al cloud senza riscrivere tutto

Uno dei vantaggi più interessanti è la possibilità di costruire gradualmente una nuova architettura.

Un'applicazione esistente può continuare a funzionare mentre il server REST espone progressivamente nuove funzionalità.

Ad esempio:

                 APPLICAZIONE DESKTOP
                         │
                         ▼
                    FIREBIRD
                         ▲
                         │
                  REST SERVER
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
        WEB            MOBILE        INTEGRATION
      Vue/Nuxt          App             API

Questo consente una migrazione progressiva verso il web senza dover affrontare una riscrittura completa del software.



La libreria REST Server per C++Builder nasce con un obiettivo preciso: offrire una base professionale per sviluppare API REST direttamente nell'ecosistema C++Builder, sfruttando FireDAC e mantenendo un controllo completo sull'accesso ai database.

Connection pooling, gestione delle transazioni, timeout, autenticazione, invalidazione delle connessioni e supporto alla concorrenza sono elementi fondamentali per trasformare un semplice endpoint HTTP in un vero backend applicativo.

#REST #CBUILER #VUELITIX