
Test automatizzati per trovare bug logici e di performance nei sistemi di database.

SQLancer è uno strumento per testare automaticamente i sistemi di gestione di database (DBMS) al fine di trovare bug nella loro implementazione. Cioè, individua bug nel codice dell'implementazione del DBMS, non nelle query scritte dall'utente. SQLancer ha trovato centinaia di bug in DBMS maturi e ampiamente conosciuti.
SQLancer affronta due sfide essenziali nel test automatico dei DBMS:
Community. Abbiamo uno Slack workspace per discutere di SQLancer e del test dei DBMS in generale. In precedenza, SQLancer aveva un account su Twitter/X @sqlancer_dbms, che non è più mantenuto. Abbiamo un blog, che, al momento, contiene solo post dei contributori del progetto Google Summer of Code.
Requisiti minimi:
I seguenti comandi clonano SQLancer, creano un JAR e avviano SQLancer per testare SQLite utilizzando Non-optimizing Reference Engine Construction (NoREC):``` git clone https://github.com/sqlancer/sqlancer cd sqlancer mvn package -DskipTests cd target java -jar sqlancer-*.jar --num-threads 4 sqlite3 --oracle NoREC
**Esecuzione e terminazione.** Se l'esecuzione stampa informazioni di avanzamento ogni cinque secondi, allora lo strumento funziona come previsto. La scorciatoia CTRL+C può essere utilizzata per terminare SQLancer manualmente. Se SQLancer non trova alcun bug, viene eseguito all'infinito. L'opzione `--num-tries` può essere utilizzata per controllare dopo quanti bug SQLancer termina. In alternativa, l'opzione `--timeout-seconds` può essere utilizzata per specificare la durata massima di esecuzione consentita a SQLancer.
**Parametri.** Se si avvia SQLancer senza parametri, vengono visualizzate le opzioni e i comandi disponibili. Nota che le opzioni generali supportate da tutte le implementazioni di test DBMS (ad es. `--num-threads`) devono precedere il nome del DBMS da testare (ad es. `sqlite3`). Le opzioni supportate solo per uno specifico DBMS (ad es. `--test-rtree` per SQLite3), o le opzioni per cui ogni implementazione di test fornisce valori diversi (ad es. `--oracle NoREC`) devono andare dopo il nome del DBMS.
**DBMS.** Per eseguire SQLancer su SQLite, non è stato necessario installare e configurare un DBMS. Il motivo è che i DBMS embedded vengono eseguiti nello stesso processo dell'applicazione e quindi non richiedono installazione o configurazione separata. I DBMS embedded supportati da SQLancer includono DuckDB, H2 e SQLite. I loro binari sono inclusi come [dipendenze JAR](https://github.com/sqlancer/sqlancer/blob/main/pom.xml). Nota che eventuali crash in questi sistemi causeranno anche un crash nella JVM su cui SQLancer è in esecuzione.
# Utilizzo di SQLancer
**Log.** SQLancer memorizza i log nella sottodirectory `target/logs`. Per impostazione predefinita, l'opzione `--log-each-select` è abilitata, con il risultato che ogni istruzione SQL inviata al DBMS viene registrata. I nomi dei file corrispondenti hanno il suffisso `-cur.log`. Inoltre, se SQLancer rileva un bug logico, crea un file con estensione `.log`, in cui vengono registrate le istruzioni per riprodurre il bug, incluse solo l'ultima query eseguita insieme alle altre istruzioni per impostare lo stato del database.
**Riduzione dei bug.** Dopo aver trovato un input di test che induce un bug, l'input tipicamente deve essere ridotto per essere ulteriormente analizzato, poiché potrebbe contenere molte istruzioni SQL ridondanti per riprodurre il bug. Un'opzione è farlo manualmente, rimuovendo un'istruzione o una caratteristica alla volta, rieseguendo le istruzioni che inducono il bug e applicando l'oracolo di test (ad esempio, per oracoli di test come TLP o NoREC, ciò richiederebbe di verificare che entrambe le query producano ancora un risultato diverso). Questo processo può essere automatizzato utilizzando un cosiddetto [approccio di delta-debugging](https://www.debuggingbook.org/html/DeltaDebugger.html). SQLancer include un'implementazione sperimentale di un approccio di delta-debugging, che può essere abilitata usando `--use-reducer`. In passato, abbiamo utilizzato con successo [C-Reduce](https://embed.cs.utah.edu/creduce/), che richiede di specificare l'oracolo di test in uno script eseguibile da C-Reduce.
**Test della versione più recente del DBMS.** Per la maggior parte dei DBMS, SQLancer supporta solo una precedente versione *release*. Pertanto, potenziali bug trovati da SQLancer potrebbero essere già stati risolti nell'ultima versione *di sviluppo* del DBMS. Se non sei uno sviluppatore del DBMS che stai testando, ti invitiamo a verificare che il bug sia ancora riproducibile prima di segnalarlo. Apprezzeremmo se potessi menzionare SQLancer quando segnali bug trovati da esso. Saremmo anche entusiasti di conoscere la tua esperienza nell'uso di SQLancer o casi d'uso o estensioni correlati.
**Opzioni.** SQLancer fornisce molte opzioni che puoi utilizzare per personalizzare il suo comportamento. Eseguendo `java -jar sqlancer-*.jar --help` verranno elencate e dovrebbe stampare un output come il seguente:```
Usage: SQLancer [options] [command] [command options]
Options:
--ast-reducer-max-steps
EXPERIMENTAL Maximum steps the AST-based reducer will do
Default: -1
--ast-reducer-max-time
EXPERIMENTAL Maximum time duration (secs) the statement reducer will do
Default: -1
--canonicalize-sql-strings
Should canonicalize query string (add ';' at the end
Default: true
--constant-cache-size
Specifies the size of the constant cache. This option only takes effect
when constant caching is enabled
Default: 100
...
Quale versione di SQLancer usare. Il modo consigliato per utilizzare SQLancer è di usare la sua ultima versione sorgente su GitHub. Rilasci ufficiali infrequenti e irregolari sono disponibili anche sulle seguenti piattaforme:
Comprendere la generazione SQL. Per analizzare le istruzioni che inducono bug, è utile comprendere le caratteristiche di SQLancer. Innanzitutto, ci si aspetta che SQLancer generi sempre istruzioni SQL sintatticamente valide per il DBMS in test. Pertanto, non si dovrebbero mai osservare errori di sintassi. Secondo, SQLancer potrebbe generare istruzioni semanticamente non valide. Ad esempio, SQLancer potrebbe tentare di inserire valori duplicati in una colonna con un vincolo UNIQUE, poiché evitare completamente tali errori semantici è difficile. Terzo, ogni bug segnalato da SQLancer dovrebbe essere un bug reale, tranne quelli segnalati da CERT (poiché i problemi di performance non sono definiti in modo chiaro come altri tipi di bug). Se si osservano bug indicati da SQLancer che non si considerano tali, probabilmente c'è qualcosa di sbagliato nella propria configurazione. Infine, in relazione al punto precedente, SQLancer è specifico per una versione del DBMS, e puoi trovare la versione contro cui siamo testati nel nostro workflow di GitHub Actions. Se si testa un'altra versione, si potrebbero osservare vari falsi allarmi (ad esempio, causati da errori di sintassi). Anche se vorremmo sempre che SQLancer fosse aggiornato all'ultima versione di sviluppo di ciascun DBMS, non abbiamo le risorse per raggiungere questo obiettivo.
DBMS supportati. SQLancer richiede codice specifico per ogni DBMS che supporta. A partire da gennaio 2025, fornisce supporto per Citus, ClickHouse, CockroachDB, Databend, (Apache) DataFusion, (Apache) Doris, DuckDB, H2, HSQLDB, MariaDB, Materialize, MySQL, OceanBase, PostgreSQL, Presto, QuestDB, SQLite3, TiDB e YugabyteDB. Il grado di supporto per i singoli DBMS differisce.
SQLancer ha introdotto e include molteplici approcci per il testing dei DBMS, come riportato di seguito in ordine cronologico.
Si prega di trovare le voci .bib qui.
Sto eseguendo SQLancer sull'ultima versione di un DBMS supportato. Ci si aspetta che SQLancer stampi molti AssertionError? In molti casi, SQLancer non supporta l'ultima versione di un DBMS. Puoi controllare il file .github/workflows/main.yml per determinare quale versione usiamo nei nostri test CI, che corrisponde alla versione attualmente supportata di quel DBMS. SQLancer dovrebbe stampare solo un AssertionError e produrre un file di log corrispondente, se ha identificato un bug. Per aggiornare SQLancer a supportare una nuova versione del DBMS, due opzioni sono consigliabili: (1) i generatori possono essere aggiornati per non generare più determinati pattern che potrebbero causare errori (ad esempio, può accadere se una parola chiave o un'opzione non è più supportata) o (2) gli errori che appaiono di recente possono essere aggiunti come errori attesi in modo che SQLancer li ignori quando si presentano (ad esempio, questo è utile se alcuni pattern che inducono errori non possono essere facilmente evitati).
Un altro motivo per molti fallimenti su una versione supportata potrebbe essere che i messaggi di errore vengono stampati in una lingua diversa dall'inglese (che sarebbe visibile nello stack trace). In tal caso, prova a impostare la lingua del DBMS sull'inglese (ad esempio, vedi la homepage di PostgreSQL).
Quando avvio SQLancer, ricevo un errore come "database 'test' does not exist". Come posso eseguire SQLancer senza questo errore? Per alcuni DBMS, SQLancer si aspetta che esista un database "test", che poi usa come database iniziale per connettersi. Se non hai ancora creato un tale database, puoi usare un comando come CREATE DATABASE test per creare questo database (ad esempio, vedi la documentazione di PostgreSQL).
Documentazione e risorse:
Video:
Strumenti strettamente correlati:
| Tecnica | Sede | Link | Descrizione |
|---|
| Pivoted Query Synthesis (PQS) | OSDI 2020 | Paper Video | PQS è la prima tecnica che abbiamo progettato e implementato. Seleziona casualmente una riga, chiamata riga pivot, per la quale viene generata una query che deve recuperare quella riga. Se la riga non è contenuta nel risultato, è stato rilevato un bug. È completamente descritta qui. PQS rileva efficacemente i bug, ma richiede uno sforzo di implementazione maggiore rispetto ad altri approcci di testing che seguono una metodologia di metamorphic testing o differential testing. Pertanto, attualmente non è mantenuto. |
| Non-optimizing Reference Engine Construction (NoREC) | ESEC/FSE 2020 | Paper Video | NoREC mira a trovare bug di ottimizzazione. Traduce una query che potrebbe essere ottimizzata dal DBMS in una per cui difficilmente sono applicabili ottimizzazioni, e confronta i due risultati. Una differenza tra i risultati indica un bug nel DBMS. L'approccio si applica principalmente a query semplici con un predicato di filtro. |
| Ternary Logic Partitioning (TLP) | OOPSLA 2020 | Paper Video | TLP partiziona una query in tre query di partizionamento, i cui risultati vengono composti e confrontati con il risultato della query originale. Una differenza nei risultati indica un bug nel DBMS. A differenza di NoREC e PQS, può rilevare bug in funzionalità avanzate come le funzioni aggregate. È tra le tecniche di testing più adottate. |
| Differential Query Execution (DQE) | ICSE 2023 | Paper Code | Differential Query Execution (DQE) è un approccio nuovo e generale per rilevare bug logici nelle query SELECT, UPDATE e DELETE. DQE risolve il problema dell'oracolo di test eseguendo query SELECT, UPDATE e DELETE con lo stesso predicato φ e osservando incoerenze tra i loro risultati di esecuzione. Ad esempio, se una riga che viene aggiornata da una query UPDATE con predicato φ non appare nel risultato di una query SELECT con lo stesso predicato φ, viene rilevato un bug logico nel DBMS target. Aggiungiamo due colonne extra a ogni tabella di un database per identificare univocamente ogni riga e tenere traccia se una riga è stata modificata. Riscriviamo inoltre le query SELECT e UPDATE per identificare le righe a cui accedono. DQE supporta MySQL. |
| Query Plan Guidance (QPG) | ICSE 2023 | Paper Video Code | QPG è un approccio di generazione di casi di test guidato dal feedback. Si basa sull'intuizione che i piani di esecuzione catturano se un comportamento interessante viene esercitato all'interno del DBMS. Funziona mutando lo stato del database quando non sono stati osservati nuovi piani di esecuzione dopo l'esecuzione di un certo numero di query, aspettandosi che il nuovo stato consenta l'attivazione di nuovi piani di esecuzione. Questo approccio è abilitato dall'opzione --qpg-enable e supporta gli oracoli TLP e NoREC per SQLite, CockroachDB, TiDB e Materialize. È l'unico approccio che affronta specificamente il problema della generazione di input di test. |
| Cardinality Estimation Restriction Testing (CERT) | ICSE 2024 | Paper Code | CERT mira a trovare problemi di performance attraverso cardinalità stimate inaspettate, che rappresentano il numero stimato di righe restituite. Da una query di input data, deriva una query più restrittiva, la cui cardinalità stimata non dovrebbe essere maggiore di quella della query originale. Una violazione indica un potenziale problema di performance. CERT supporta TiDB, CockroachDB e MySQL. CERT è l'unico oracolo di test che fa parte di SQLancer progettato per trovare problemi di performance. |
| Differential Query Plans (DQP) | SIGMOD 2024 | Paper Video Code | DQP mira a trovare bug logici controllando l'esecuzione di diversi piani di esecuzione per una data query e verificando che producano un risultato coerente. DQP supporta MySQL, MariaDB e TiDB. |
| Constant Optimization Driven Database System Testing (CODDTest) | SIGMOD 2025 | Code | CODDTest trova bug logici nei DBMS, incluse funzionalità avanzate come le sottoquery. Si basa sull'intuizione che possiamo assumere che lo stato del database sia costante per una sessione di database, il che ci consente di sostituire parti di una query con i loro risultati, corrispondendo essenzialmente a constant folding e constant propagation, che sono due ottimizzazioni tradizionali dei compilatori. |