giovedì 8 ottobre 2026

Free PlyxSQL© - 1.0.0.111

PlyxSQL 111: il nuovo SQL Manager cross-database per sviluppatori professionisti

PlyxSQL v30 rappresenta una nuova importante evoluzione di un ambiente SQL progettato per lavorare con database differenti attraverso un'unica piattaforma.

La nuova versione introduce una revisione architetturale profonda che coinvolge gestione delle connessioni, SQL Builder, SQL Editor, Schema Designer, generazione DDL, capability SQL, versioni dei database e test di compatibilità.

L'obiettivo è ambizioso: offrire agli sviluppatori un ambiente nel quale la generazione SQL non dipenda semplicemente dal nome del database, ma dal contesto reale del server e dalle funzionalità effettivamente disponibili.


Un unico ambiente per database differenti

Uno dei problemi più complessi nello sviluppo di strumenti SQL multi-database è rappresentato dalle differenze tra i vari dialetti.

Una query valida su PostgreSQL potrebbe non essere valida su SQL Server.

Una sintassi disponibile su MySQL 8 potrebbe non essere disponibile su MySQL 5.7.

MariaDB e MySQL possono condividere molta sintassi, ma non sono sempre equivalenti.

DB2, Informix e Microsoft Access introducono inoltre numerose peculiarità specifiche.

PlyxSQL v30 affronta questo problema con una nuova architettura basata sul concetto di SQL Workspace.


SQL Workspace: il cuore della nuova architettura

Il nuovo TSQLWorkspaceContext raccoglie in un unico contesto tutte le informazioni necessarie alla gestione SQL.

Il Workspace comprende:

  • connessione;

  • dialetto SQL;

  • prodotto;

  • versione del server;

  • origine delle informazioni;

  • sessione SQL;

  • capability;

  • generazione del contesto.

Il vantaggio è importante: Builder, Editor, Designer e altre funzionalità possono lavorare sullo stesso contesto SQL.

L'architettura può essere rappresentata così:

Connessione
     │
     ▼
Tree Explorer
     │
     ▼
SQL Workspace Context
     │
 ┌───┼───────────────┐
 ▼   ▼               ▼
Builder Editor   Schema Designer
     │
     ▼
SQL / DDL

Questa struttura riduce drasticamente il rischio che componenti differenti utilizzino informazioni diverse sul database attivo.


Database, prodotto e versione: una distinzione fondamentale

PlyxSQLv30 introduce una gestione più precisa dell'identità del database.

Non viene considerato soltanto il semplice dialetto.

Il sistema distingue tra:

Dialect

Product

Server Version

Session

Capabilities

Questa distinzione è fondamentale per gestire correttamente database come MySQL e MariaDB.


MySQL e MariaDB finalmente distinti

MySQL e MariaDB condividono moltissima sintassi, ma non sono lo stesso prodotto.

La v30 introduce quindi una gestione esplicita del prodotto.

Questo permette al sistema di sapere che una connessione utilizza:

Dialect: MySQL
Product: MariaDB

quando questa è la rappresentazione sintattica più appropriata.

Il risultato è una base molto più solida per gestire le differenze specifiche dei due database.


AutoDetect più affidabile

La funzione di autodetection è stata migliorata per evitare che il rilevamento automatico sovrascriva arbitrariamente le impostazioni definite manualmente.

Il sistema può utilizzare informazioni provenienti da:

  • driver;

  • server;

  • progetto;

  • configurazione manuale.

La scelta manuale dell'utente viene quindi rispettata.

Questo rende il comportamento molto più prevedibile quando si lavora con configurazioni particolari o database legacy.


Capability Engine: sapere cosa può realmente fare il database

Una delle innovazioni architetturali più importanti della v30 è il nuovo sistema centralizzato delle SQL Capability.

Il progetto dispone ora di un Core che descrive le funzionalità supportate dai vari database.

Tra queste troviamo:

  • Foreign Key;

  • Check Constraint;

  • Views;

  • Triggers;

  • Routines;

  • Sequences;

  • Lateral;

  • Apply;

  • Returning;

  • Generated Columns;

  • JSON;

  • Pagination;

  • altre funzionalità specifiche.

Il Builder può quindi basare la generazione SQL sulle funzionalità disponibili invece di utilizzare esclusivamente controlli basati sul nome del database.


Perché le Capability sono così importanti?

Consideriamo un esempio.

Non è sufficiente sapere:

Database = SQL Server

Bisogna sapere anche:

SQL Server
+
versione
+
sessione
+
feature disponibili

Una funzionalità può infatti essere stata introdotta soltanto in una determinata versione.

Per questo PlyxSQL v30 considera la versione del server come parte integrante del contesto SQL.


Server Profile

Il SQL Builder utilizza un profilo server più completo attraverso il concetto di:

TSQLServerProfile

Il profilo combina:

  • dialetto;

  • prodotto;

  • versione;

  • capability;

  • sessione.

Questo permette al generatore SQL di prendere decisioni molto più precise.

Il risultato è un Builder più consapevole dell'ambiente nel quale sta operando.


SQL Builder più intelligente

Il Builder è stato profondamente migliorato nella gestione delle funzioni SQL.

In particolare sono stati introdotti contratti espliciti per le funzioni scalari.

Una funzione può essere:

  • nativa;

  • emulata;

  • non supportata;

  • dipendente dalla versione.

Questo è molto più sicuro rispetto a supporre che una funzione con lo stesso nome abbia necessariamente lo stesso comportamento su tutti i database.


Supporto specifico per DB2

DB2 presenta numerose particolarità sintattiche.

La v30 introduce un renderer specifico per le funzioni scalari DB2.

Questo consente di gestire in modo dedicato funzioni relative a:

  • stringhe;

  • lunghezza;

  • substring;

  • padding;

  • funzioni numeriche.

Il Builder non deve quindi trattare DB2 semplicemente come una variante generica dello standard SQL.


Supporto specifico per Informix

Anche Informix dispone di una gestione dedicata per le funzioni scalari.

Questa scelta consente di produrre SQL maggiormente aderente alle caratteristiche del database.

È un passaggio importante per un prodotto che vuole supportare realmente anche database meno diffusi rispetto ai classici MySQL, PostgreSQL e SQL Server.


Supporto specifico per Microsoft Access

Microsoft Access rappresenta un ambiente particolarmente diverso rispetto ai database server tradizionali.

La v30 introduce una gestione specifica delle sue funzioni SQL e delle sue peculiarità.

Questo permette di evitare di utilizzare automaticamente la sintassi dei database server-oriented.


Pagination cross-database

La gestione della paginazione SQL è stata resa più robusta.

Sono stati affrontati in particolare:

  • offset negativi;

  • overflow;

  • conversione dei valori;

  • differenze tra database;

  • sintassi specifiche dei vari dialetti.

La generazione della paginazione viene quindi effettuata tenendo conto delle caratteristiche del database.


Quoting degli identificatori

Il quoting è un'altra area particolarmente delicata in un ambiente SQL multi-database.

PlyxSQLv30 dispone di una gestione più strutturata del quoting.

Questo consente di tenere conto delle differenze tra:

  • SQL Server;

  • PostgreSQL;

  • MySQL;

  • MariaDB;

  • Firebird;

  • InterBase;

  • Access;

  • altri dialetti supportati.

Il quoting viene quindi trattato come una caratteristica del contesto SQL e non come una semplice operazione testuale.


DDL: una nuova architettura unificata

La gestione del DDL è stata completamente riorganizzata.

La v30 introduce una struttura composta da:

  • SQL DDL Service

  • DDL Generator

  • SQL DDL IR

L'utilizzo di un modello intermedio consente di separare la descrizione dell'oggetto dalla sintassi specifica del database.

Questo rende la generazione DDL più facilmente estendibile.


DDL coerente tra Tree e Designer

Una delle migliorie più importanti è la maggiore uniformità tra le operazioni effettuate dal Tree Explorer e quelle effettuate dallo Schema Designer.

La stessa architettura DDL viene utilizzata per le diverse modalità operative.

Questo riduce il rischio di avere:

SQL differente a seconda del punto dell'applicazione dal quale viene eseguita la stessa operazione.


Foreign Key, Index e Constraint

La gestione degli oggetti strutturali del database è stata migliorata.

Particolare attenzione è stata dedicata a:

  • Foreign Key;

  • Index;

  • Constraint;

  • Check Constraint;

  • quoting;

  • nomi degli oggetti;

  • riferimenti tra tabelle;

  • differenze DDL tra database.

La capability matrix permette inoltre di distinguere meglio ciò che un database può realmente eseguire.


Trigger più accurati

La gestione dei trigger è stata resa più precisa.

In particolare vengono considerate le differenze relative ai trigger:

INSTEAD OF

che non sono disponibili allo stesso modo in tutti i database.

Questo evita di trattare tutte le implementazioni dei trigger come equivalenti.


Routine e cataloghi database

La gestione delle routine è stata migliorata attraverso una classificazione più precisa degli oggetti restituiti dai cataloghi database.

Questo consente di distinguere meglio:

  • procedure;

  • funzioni;

  • routine;

  • differenti tipologie catalogate dai vari DBMS.

Il Tree Explorer può quindi rappresentare gli oggetti in modo più coerente.


SQLite e le sue particolarità DDL

SQLite non dispone dello stesso modello DDL dei database server tradizionali.

La v30 gestisce esplicitamente le limitazioni relative alle constraint e alle operazioni DDL.

In particolare vengono evitate operazioni che SQLite non può eseguire direttamente con la stessa modalità di altri database.


SQL Script Runner

La gestione degli script SQL è stata centralizzata attraverso il nuovo:

SQLScriptRunner

Il sistema gestisce:

  1. analisi;

  2. suddivisione;

  3. pianificazione;

  4. esecuzione;

  5. gestione degli errori.

Questo permette di avere una pipeline SQL più coerente.


SQL Script Splitter

La suddivisione degli script è stata migliorata per gestire correttamente le singole istruzioni.

Questo è particolarmente importante quando uno script contiene strutture SQL più complesse.

La separazione tra parsing dello script e sua esecuzione permette inoltre di migliorare progressivamente il motore senza dover modificare tutte le funzionalità che utilizzano SQL.


Esecuzione DDL asincrona

Le operazioni DDL possono essere eseguite attraverso un modello asincrono.

Questo è fondamentale per database:

  • remoti;

  • lenti;

  • con molti oggetti;

  • soggetti a lock;

  • con operazioni DDL lunghe.

L'interfaccia può quindi rimanere reattiva durante le operazioni più pesanti.


SQL Execution Matrix

Una delle funzionalità più interessanti della v30 è la:

SQL Execution Matrix

Non ci si limita a verificare che il Builder produca una stringa.

Le query possono essere eseguite realmente sul database.

La matrice verifica attualmente diverse categorie, tra cui:

  • funzioni scalari;

  • quoting;

  • pagination;

  • coerenza del dialetto.

Questo introduce un concetto molto importante:

testare SQL realmente eseguibile e non soltanto SQL apparentemente corretto.


Dal test statico al test reale

Un SQL Builder può produrre una query apparentemente perfetta:

SELECT ...

ma soltanto il database può confermare se quella query è realmente valida.

La SQL Execution Matrix introduce quindi una verifica concreta del comportamento del generatore.

È un passo fondamentale verso un ambiente SQL professionale.


Sincronizzazione Tree Explorer, Builder ed Editor

La v30 migliora il collegamento tra i tre componenti principali:

Tree Explorer

Gestisce le connessioni e il Workspace.

SQL Builder

Genera SQL sulla base del Workspace.

SQL Editor

Visualizza e modifica il codice SQL.

Il flusso diventa quindi:

CONNESSIONE
     ↓
TREE EXPLORER
     ↓
WORKSPACE
     ↓
BUILDER
     ↓
SQL
     ↓
EDITOR

Questo rende l'interazione tra i componenti molto più prevedibile.


SQLManagerMenu come orchestratore

SQLManagerMenu rimane il centro operativo dal quale vengono avviate numerose funzioni.

La nuova architettura, però, riduce progressivamente la quantità di logica duplicata all'interno del menu.

Il menu coordina le operazioni mentre il Workspace e i servizi specializzati gestiscono le informazioni SQL.

Questa separazione rende il progetto più facilmente manutenibile.


Cache e invalidazione del contesto

La gestione della cache è stata integrata con il concetto di generazione del Workspace.

Quando cambia il contesto della connessione, le informazioni precedenti possono essere invalidate.

Questo è particolarmente importante quando l'utente passa rapidamente tra database differenti.

Ad esempio:

PostgreSQL
   ↓
SQL Server
   ↓
Firebird
   ↓
MariaDB

senza riavviare l'applicazione.


Gestione delle versioni server

La versione del server è diventata una componente importante del modello SQL.

Questo consente di gestire meglio le differenze tra:

MySQL 5.7
MySQL 8.x

oppure:

SQL Server legacy
SQL Server moderno

e analogamente per gli altri DBMS.

Questa impostazione è fondamentale per evitare che il Builder consideri automaticamente tutte le versioni di un database equivalenti.


Una vera architettura Cross-Dialect

La v30 non si limita quindi a tradurre:

SQL standard → SQL database

L'approccio è più evoluto:

Workspace
    ↓
Dialect
    ↓
Product
    ↓
Version
    ↓
Session
    ↓
Capabilities
    ↓
Renderer
    ↓
SQL

Questo rappresenta un modello molto più vicino a un vero SQL compiler/generator cross-database.


Perché la v30 è importante

La vera innovazione della versione 30 non è una singola funzione.

È il modo in cui le diverse funzionalità sono state collegate.

La piattaforma dispone ora di una catena architetturale molto più coerente:

Connection → Workspace → Capability → Renderer → SQL → Execution

Questo permette di costruire in futuro funzionalità ancora più sofisticate senza dover duplicare continuamente la logica per ogni database.


I database supportati

L'architettura v30 è progettata per lavorare con numerosi DBMS, tra cui:

  • Firebird;

  • InterBase;

  • PostgreSQL;

  • MySQL;

  • MariaDB;

  • Microsoft SQL Server;

  • Oracle;

  • SQLite;

  • IBM Db2;

  • Informix;

  • Microsoft Access.

Il valore dell'architettura sta proprio nella capacità di gestire le differenze tra questi ambienti mantenendo un modello comune.


PlyxSQL v30 rappresenta una delle evoluzioni architetturali più importanti del progetto.

Il passaggio fondamentale è quello da una gestione SQL basata principalmente sul semplice dialetto a una gestione basata sul contesto completo:

Database + Product + Version + Session + Capability + Renderer

Questo approccio permette di affrontare in modo molto più professionale la complessità del mondo SQL.

Il Builder non deve più semplicemente chiedersi:

"Quale database sto utilizzando?"

ma deve poter rispondere a una domanda molto più precisa:

"Quale sintassi SQL è realmente disponibile in questo specifico ambiente?"

È questa filosofia che rende la v30 una piattaforma particolarmente interessante per lo sviluppo di applicazioni database multi-DBMS.


mercoledì 7 ottobre 2026

Free PlyxSQL© - 1.0.0.109 Bug fix

PlyxSQL 109 – Report dei bug risolti e miglioramenti implementati

Introduzione

Durante le ultime attività di sviluppo e revisione del progetto PlyxSQL, sono stati individuati e corretti numerosi problemi che riguardavano la gestione dei database, la compatibilità SQL tra diversi DBMS, l'esecuzione delle query, il Query Builder, l'Editor SQL, l'autenticazione e le operazioni asincrone.

L'obiettivo principale degli interventi è stato rendere l'applicazione più affidabile e coerente quando lavora con database differenti, evitando che una funzionalità corretta per un DBMS producesse comportamenti errati su un altro. Particolare attenzione è stata dedicata alla gestione dei dialetti SQL, alle informazioni sulla versione del server e alle differenze tra i vari database supportati.

Questo documento riassume i principali bug già risolti.


1. Corretto il problema del contesto SQL tra Editor, Core e Query Builder

Uno dei problemi più importanti riguardava la gestione del contesto SQL. In precedenza alcune funzionalità potevano utilizzare informazioni diverse sul database corrente a seconda del componente che le eseguiva.

Il problema è stato corretto introducendo una gestione più strutturata del contesto del server e del dialetto SQL. Il sistema ora distingue in modo più affidabile:

  • DBMS

  • versione del server

  • major/minor/patch

  • build

  • update

  • compatibilità

  • caratteristiche specifiche del database

  • impostazioni della sessione SQL

Questo permette all'Editor, al SQL Core e al Query Builder di lavorare con informazioni coerenti.


2. Corretto il problema del RETURNING

È stata corretta la gestione della clausola RETURNING. Il supporto non viene più trattato genericamente per tutte le operazioni DML. La gestione è stata separata per:

  • INSERT

  • UPDATE

  • DELETE

Questo evita di generare SQL non valido quando un particolare DBMS supporta RETURNING soltanto per alcune operazioni. La capability viene quindi valutata in funzione del dialetto e dell'operazione effettivamente richiesta.


3. Corretta la gestione di PostgreSQL LATERAL

È stato corretto il supporto a LATERAL per PostgreSQL. La gestione tiene conto della versione del database, evitando di generare SQL con funzionalità non disponibili sulle versioni più vecchie.

Questo è particolarmente importante per PostgreSQL 9.3 e versioni successive, dove la disponibilità della funzionalità deve essere verificata in relazione alla versione del server.


4. Migliorata la gestione del dialetto Firebird/InterBase

È stata rivista la gestione delle differenze tra Firebird e InterBase. Il sistema ora dispone di una gestione più specifica del dialetto SQL invece di trattare indistintamente tutti i database appartenenti alla stessa famiglia.

Questo ha permesso di migliorare:

  • quoting degli identificatori

  • generazione SQL

  • rilevamento del DBMS

  • gestione delle capability

  • gestione della versione

  • comportamento del Query Builder


5. Corretta la gestione delle impostazioni sql_mode

Per MySQL e MariaDB è stata aggiunta una gestione più accurata delle impostazioni di sessione. Vengono considerate impostazioni come:

  • ANSI_QUOTES

  • NO_BACKSLASH_ESCAPES

  • PIPES_AS_CONCAT

Queste impostazioni possono modificare concretamente il significato del codice SQL. La loro rilevazione permette quindi al motore SQL di evitare di interpretare sempre le stringhe e gli identificatori secondo un'unica sintassi.


6. Corretta la gestione della versione Oracle

È stata corretta la rilevazione della versione Oracle. Il sistema ora dispone di informazioni più precise sulla versione del server e può utilizzarle per determinare la disponibilità delle funzionalità SQL.

Questo evita che il generatore SQL utilizzi automaticamente funzionalità appartenenti a versioni più recenti del database.


7. Corretta la gestione dei BLOB/Base64

È stata migliorata la conversione dei dati BLOB in Base64. La gestione precedente poteva produrre risultati errati con determinati dati binari. La conversione è stata resa più robusta, evitando problemi nella rappresentazione e nell'esportazione dei dati binari.


8. Corretta la gestione dei numeri con separatori delle migliaia

È stato corretto il parsing dei valori numerici contenenti separatori delle migliaia. Il sistema distingue ora meglio tra:

  • separatore decimale

  • separatore delle migliaia

  • formato numerico specifico del database

Questo evita che un valore numerico venga interpretato come un numero differente oppure come una stringa.


9. Corretto il funzionamento asincrono dello Schema Compare

È stato corretto il funzionamento asincrono delle operazioni di Schema Compare. Le operazioni più pesanti non devono bloccare inutilmente l'interfaccia grafica.

Sono stati inoltre migliorati:

  • gestione dei task asincroni

  • aggiornamento dell'interfaccia

  • gestione della cancellazione

  • sincronizzazione dei risultati


10. Corretta la gestione degli errori durante l'introspezione

È stata migliorata la gestione degli errori durante le operazioni di introspezione del database. Gli errori non vengono più ignorati indiscriminatamente.

Questo permette di distinguere meglio tra:

  • oggetti realmente assenti

  • oggetti non supportati

  • errori SQL

  • errori di connessione

  • problemi di permessi

Il risultato è una diagnostica più affidabile.


11. Corretta la gestione dei nomi SQL non escapati

Sono stati corretti diversi casi in cui i nomi di database, schema, tabelle, colonne e oggetti SQL potevano essere utilizzati senza un corretto escaping.

La generazione SQL utilizza ora le regole di quoting appropriate per il dialetto. Questo è fondamentale quando un identificatore:

  • contiene spazi

  • contiene caratteri speciali

  • coincide con una parola riservata

  • utilizza maiuscole/minuscole significative


12. Corretta la gestione del tokenizer per le REST table

È stato corretto il tokenizer utilizzato nella gestione delle REST table. Il parser ora gestisce meglio le strutture SQL/API contenenti caratteri e delimitatori che precedentemente potevano essere interpretati in modo errato.

Questo riduce gli errori durante il parsing delle definizioni.


13. Corretto il calcolo dell'ultima pagina dei risultati

È stato corretto il problema relativo al calcolo di hasMore nell'ultima pagina dei risultati. In precedenza il sistema poteva indicare erroneamente la presenza di ulteriori record anche quando era già stata raggiunta l'ultima pagina.

La logica ora tiene conto correttamente del numero effettivo di record disponibili.


14. Corretta la gestione dei contatori a 64 bit

È stata migliorata la gestione dei contatori utilizzati per:

  • COUNT

  • offset

  • limit

  • paginazione

  • numero di record

I valori vengono gestiti con maggiore attenzione anche quando superano i limiti tipici degli interi a 32 bit. Questo evita overflow e conversioni errate durante le operazioni su grandi quantità di dati.


15. Corretta la gestione delle credenziali in modalità debug

Sono state rimosse/evitate situazioni in cui credenziali sensibili potevano essere esposte attraverso codice o configurazioni utilizzate durante il debugging.

L'obiettivo è impedire che username e password reali vengano accidentalmente inseriti nel codice sorgente o nei log di sviluppo.


16. Corretta la gestione del SessionKey

È stato corretto il problema relativo alla gestione del SessionKey. La sessione viene ora identificata in modo più coerente evitando collisioni o associazioni errate tra connessioni differenti.

Questo è particolarmente importante per le operazioni asincrone e per quelle che utilizzano più connessioni contemporaneamente.


17. Migliorata la rilevazione delle capability runtime di SQLite

È stata migliorata la gestione delle funzionalità disponibili a runtime in SQLite. In particolare vengono rilevate capability come:

  • JSON1

  • REGEXP

Questo permette di distinguere tra ciò che SQLite supporta teoricamente e ciò che è effettivamente disponibile nella build/runtime utilizzata.


18. Corretta la distinzione tra MySQL e MariaDB

È stata corretta la gestione della famiglia MySQL/MariaDB. Il sistema non si basa più esclusivamente sul nome del driver, ma considera anche le informazioni restituite dal server.

Questo permette di distinguere correttamente:

  • MySQL

  • MariaDB

La distinzione è importante perché i due DBMS possono avere differenze di sintassi e di capability nonostante la compatibilità generale.


19. Migliorata la gestione di DB2 e Informix nel Core e nell'Editor

È stata introdotta una gestione dedicata di DB2 e Informix nel SQL Core e nell'Editor. Questo evita che questi database vengano trattati semplicemente come SQL standard.

Il sistema dispone ora di regole specifiche per:

  • riconoscimento del dialetto

  • capability

  • quoting

  • paginazione

  • generazione SQL

Nel Query Builder il supporto rimane volutamente più limitato per le funzionalità che richiedono una conoscenza completa del dialetto.


20. Centralizzata la matrice delle capability SQL

È stata introdotta una matrice centralizzata per le capability dei vari DBMS. Il sistema dispone ora di regole che permettono di stabilire se una funzionalità è:

  • supportata

  • non supportata

  • supportata in modo condizionale

  • disponibile a partire da una determinata versione

Questo riduce la quantità di controlli sparsi nel codice e rende più coerente il comportamento dei vari componenti.


21. Distinta la generazione SQL nativa da quella emulata

È stata introdotta una distinzione più chiara tra:

  • funzionalità SQL native del database

  • funzionalità emulate dall'applicazione

Questo è importante perché il generatore SQL non deve presentare come nativa una funzionalità che in realtà viene ottenuta attraverso una trasformazione o un'emulazione.


22. Migliorata la gestione della paginazione dell'Editor

La paginazione dell'Editor è stata rivista utilizzando un approccio più strutturato. Il sistema distingue le strategie di paginazione in base al DBMS e cerca di utilizzare la sintassi corretta per ciascun database.

Sono state inoltre migliorate le operazioni di:

  • COUNT

  • OFFSET

  • LIMIT

  • gestione dell'ultima pagina

  • rilevamento della presenza di ulteriori record


23. Corretta la paginazione specifica di Firebird nel Query Builder

È stato corretto un problema nella generazione della paginazione Firebird quando veniva utilizzato SELECT DISTINCT. La posizione delle clausole SQL è stata corretta affinché la query generata rispettasse la sintassi prevista da Firebird.


24. Corretto il problema della paginazione DB2/Standard

È stato corretto un problema per cui la richiesta di una paginazione poteva essere ignorata e produrre SQL senza LIMIT/OFFSET o equivalente. La generazione è stata aggiornata per gestire correttamente le strategie supportate dal database.


25. Corretto un problema di invalidazione dei puntatori in DBTagCompare

È stato corretto un problema di gestione della memoria in DBTagCompare. Una struttura utilizzava riferimenti/puntatori verso elementi di un container che potevano essere invalidati quando il container veniva modificato.

Il codice è stato corretto evitando di mantenere riferimenti non più validi agli elementi. Questo elimina un potenziale comportamento indefinito e possibili crash.


26. Corretto un problema di gestione dell'utente corrente

È stato corretto un problema relativo a FCurrentUser nel sistema di autenticazione. La precedente implementazione poteva conservare un puntatore verso un elemento di una struttura dinamica dopo una modifica della struttura stessa.

La gestione è stata resa più sicura evitando riferimenti dangling.


27. Resa cancellabile l'importazione dello Schema Designer

L'importazione nello Schema Designer è stata resa:

  • asincrona

  • cancellabile

  • più sicura rispetto al blocco dell'interfaccia

Questo consente di interrompere operazioni lunghe senza lasciare l'applicazione in uno stato inconsistente.


28. Corretta la gestione degli errori di ReadStoredProcs

Gli errori durante la lettura delle stored procedure non vengono più semplicemente ignorati. Il sistema ora mantiene una maggiore visibilità sull'errore riscontrato durante l'introspezione.

Questo permette di distinguere meglio tra assenza di stored procedure e impossibilità di leggerle.


29. Migliorato il lint dell'Editor SQL

Il lint dell'Editor è stato aggiornato per considerare correttamente il contesto SQL. Questo evita falsi positivi generati quando il codice SQL veniva analizzato senza conoscere il database e il dialetto effettivamente utilizzato.


30. Corrette dichiarazioni mancanti nel sistema di autenticazione

Sono state corrette alcune dichiarazioni relative al sistema di autenticazione/header. Questo ha eliminato problemi di compilazione e di visibilità delle funzioni tra i diversi moduli.


Risultato complessivo

Gli interventi hanno portato a un miglioramento significativo dell'architettura del progetto. Le aree che hanno ricevuto i miglioramenti più importanti sono:

  • SQL Dialect Engine: il sistema è ora maggiormente consapevole del DBMS e della relativa versione.

  • SQL Core: le regole SQL sono state centralizzate e rese più coerenti tra i vari componenti.

  • Query Builder: la generazione SQL è stata migliorata per diversi DBMS, soprattutto per quanto riguarda capability e paginazione.

  • Editor SQL: sono stati corretti problemi relativi a paginazione, lint, conteggi e contesto SQL.

  • Schema Compare: sono state migliorate le operazioni asincrone, la gestione degli errori e l'introspezione.

  • Autenticazione: sono stati corretti problemi di lifetime e gestione delle informazioni di sessione.

  • SQLite: sono state aggiunte verifiche delle capability effettivamente disponibili a runtime.

  • MySQL/MariaDB: è stata migliorata la distinzione tra i due database e la gestione delle modalità SQL della sessione.

Il lavoro di revisione ha eliminato un numero significativo di bug e ha soprattutto migliorato la struttura interna del progetto. Il risultato più importante non è soltanto la correzione dei singoli errori, ma la costruzione di una base più solida per la gestione dei differenti DBMS.

La gestione del dialetto SQL è diventata progressivamente più centralizzata e consapevole del contesto del server, della versione e delle capability disponibili. Questo permette a SQL Manager di produrre SQL più affidabile e riduce il rischio che una funzionalità corretta su un database venga erroneamente applicata a un altro.

Restano naturalmente alcune aree di miglioramento, in particolare nella completa uniformità del contesto SQL tra tutti i componenti e nell'introspezione avanzata di alcuni DBMS. Tali aspetti appartengono però alla fase successiva di sviluppo e non fanno parte dell'elenco dei bug già risolti riportato in questo documento.

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

lunedì 5 ottobre 2026

Free PlyxSQL© - 1.0.0.108 Bug fix

il generatore SQL diventa più affidabile, consapevole e pronto per la produzione

Con la versione 108, PlyxSQL compie un importante passo avanti nella qualità del proprio generatore SQL. Non si tratta soltanto di una serie di correzioni puntuali: è un consolidamento strutturale che rende la generazione delle query più precisa, più sicura e più consapevole delle differenze reali tra i database supportati.

Un generatore che conosce il database

Generare SQL non significa soltanto comporre testo sintatticamente corretto. Ogni database ha regole proprie: nomi qualificati, quoting, JOIN, funzioni, locking, tipi di dato, RETURNING, MERGE, PIVOT e molte altre caratteristiche.

La versione 108 introduce un approccio più maturo: il generatore non si limita più a produrre una query, ma valuta se quella query è realmente supportata dal database di destinazione, con quale sintassi e con quali eventuali differenze semantiche.

SQL più corretto e strutturato

Sono stati corretti diversi aspetti fondamentali della generazione degli statement SQL:

  • Il terminatore ; viene ora aggiunto una sola volta, anche in presenza di UNION, CTE, INTERSECT, EXCEPT e commenti finali.
  • I JOIN sono generati tramite un JoinTree esplicito, con gestione corretta di JOIN multipli, annidati, CROSS JOIN, LATERAL e APPLY.
  • I cicli nelle relazioni non sono più considerati automaticamente un errore, perché possono essere perfettamente leciti in un modello dati.
  • La validazione è stata resa più chiara, distinguendo la validità della query dalla presenza effettiva di errori.

Identificatori, schemi e quoting

Una delle aree più delicate nella generazione SQL è la gestione dei nomi: tabelle, colonne, alias, schemi, cataloghi e oggetti DDL.

PlyxSQL 108 introduce un quoting centralizzato e un modello strutturato per i nomi qualificati. Il sistema riconosce ora correttamente forme come:

  • schema.table
  • database.schema.table
  • server.database.schema.table
  • identificatori già delimitati
  • Oracle database link

Inoltre, la qualificazione di catalogo e schema viene applicata solo quando è effettivamente supportata dal database di destinazione.

JOIN e capability per dialetto

Non tutti i database supportano gli stessi tipi di JOIN nello stesso modo. La nuova gestione delle capability distingue sintassi supportata, dipendente dalla versione e non supportata.

Sono stati migliorati in particolare INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, LATERAL e APPLY. È inoltre possibile associare predicati JOIN più articolati, utili per condizioni composte, intervalli di date e JOIN non equi.

Locking più consapevole

Il locking è un altro punto in cui le differenze tra database diventano decisive. La versione 108 introduce un rendering dedicato per i lock, con supporto a:

  • FOR UPDATE
  • FOR SHARE
  • SKIP LOCKED
  • SQL Server UPDLOCK, ROWLOCK e READPAST
  • Firebird WITH LOCK

Il sistema distingue ora tra traduzione esatta, approssimata e non disponibile. Questo evita di presentare come equivalenti meccanismi di locking che, in realtà, hanno semantiche diverse.

CTE, GROUP BY e funzioni avanzate

Sono state migliorate anche le aree più espressive del linguaggio SQL:

  • Corretto il posizionamento di RECURSIVE nelle CTE.
  • Aggiunte capability specifiche per GROUP BY, ROLLUP, CUBE e GROUPING SETS.
  • Migliorata la gestione di STRING_AGG con DISTINCT e ORDER BY.
  • Suddiviso il supporto JSON in funzioni distinte, invece di un’unica generica capability.
  • Introdotto il controllo delle capability runtime, utile ad esempio per REGEXP in SQLite.

Server Profile e versioni del database

Una novità importante è il Server Profile: il generatore può ora valutare le capability non solo in base al dialetto, ma anche in base alla versione effettiva del server.

Questo permette di scegliere la sintassi più appropriata per MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, Firebird, InterBase e SQLite, tenendo conto di versione, compatibility level e configurazione runtime.

MERGE, UPSERT, RETURNING e OUTPUT

La generazione DML è stata notevolmente rafforzata:

  • MERGE Oracle con sintassi e comportamenti specifici.
  • Distinzione chiara tra MERGE da valori e MERGE da tabella.
  • UPSERT corretto per tabelle con sole colonne chiave.
  • UPSERT version-aware per MySQL e MariaDB.
  • RETURNING e OUTPUT valutati separatamente per INSERT, UPDATE e DELETE.

Sicurezza nelle operazioni DML

La versione 108 introduce un vero DML Safety Engine. Le operazioni UPDATE e DELETE vengono classificate come:

  • Safe
  • Warning
  • Dangerous

Non si tratta di un semplice commento SQL: il rischio viene valutato e segnalato tramite un evento dedicato, aiutando a prevenire operazioni distruttive accidentali.

Metadati, tipi e colonne speciali

Il mapping dei tipi è stato migliorato con un percorso a tre fasi:

TIPO SORGENTE → TIPO CANONICO → TIPO DIALETTO

Sono inoltre stati migliorati il riconoscimento delle colonne identity, computed e read-only, la loro esclusione automatica da INSERT, UPDATE e MERGE quando non devono essere valorizzate, e la generazione di identificatori sicuri per PK, FK, indici, sequence e trigger.

Importazione, serializzazione e UI più stabili

Oltre al motore SQL, la versione 108 porta numerosi miglioramenti di robustezza:

  • Gestione più sicura del ciclo di vita del worker di importazione.
  • Migliore gestione di connessioni, filtri, encoding e diagnostica.
  • Deserializzazione JSON più atomica e resistente a dati incompleti o non validi.
  • Correzioni su drag & drop multiplo, paginazione, resize, doppio click, cambio tab e sincronizzazione dell’albero.
  • Rimozione di chiamate potenzialmente pericolose a ProcessMessages, riducendo rischi di reentrancy e stati UI incoerenti.

Regressione automatizzata

La versione 108 introduce anche una base importante per la qualità futura del prodotto: una suite di regressioni automatizzate con 34 casi per 7 dialetti, per un totale di 238 combinazioni SQL.

I test coprono SELECT, JOIN, CTE, UNION, window function, paginazione, RETURNING, MERGE, JSON, funzioni data e stringa, DDL, foreign key, PIVOT, UNPIVOT, tabelle temporanee, viste e locking.

PlyxSQL 108 non è solo una release di bug fix: è una release di consolidamento. Il generatore SQL diventa più preciso, più consapevole delle differenze tra database, più sicuro nelle operazioni DML e più stabile nell’interfaccia e nei processi di importazione.

Il risultato è un prodotto più adatto a scenari reali, dove la correttezza sintattica non basta: serve sapere che la query generata è realmente compatibile, semanticamente coerente e sicura per il database su cui verrà eseguita.

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

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