#![cfg(feature = "std")]
use std::process::Command;
fn sqlite3_available() -> bool {
Command::new("sqlite3").arg("--version").output().is_ok()
}
fn run(bin: &str, sql: &str) -> String {
let out = Command::new(bin).arg(":memory:").arg(sql).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout);
if !stdout.trim().is_empty() {
return stdout.trim_end().to_string();
}
String::from_utf8_lossy(&out.stderr)
.lines()
.find(|l| !l.trim_start().starts_with('^'))
.unwrap_or("")
.trim_start_matches("Error: in prepare, ")
.trim_start_matches("Error: stepping, ")
.trim_start_matches("Error: ")
.trim_start_matches("SQL error: ")
.trim_start_matches("error: ")
.trim_end()
.to_string()
}
const PLAN: &str = "QUERY PLAN\n|--CO-ROUTINE s\n| `--SCAN CONSTANT ROW\n`--SCAN s";
#[test]
fn aliased_constant_row_derived_table_is_a_coroutine() {
let g = env!("CARGO_BIN_EXE_graphitesql");
assert_eq!(
run(g, "EXPLAIN QUERY PLAN SELECT * FROM (SELECT 1) AS s"),
PLAN
);
assert_eq!(
run(
g,
"EXPLAIN QUERY PLAN SELECT * FROM (SELECT 1) AS s WHERE 1"
),
PLAN
);
assert_eq!(
run(
g,
"EXPLAIN QUERY PLAN SELECT 1 FROM (SELECT 1) AS s LIMIT 1 OFFSET 0"
),
PLAN
);
assert_eq!(
run(
g,
"EXPLAIN QUERY PLAN SELECT x FROM (SELECT 1 AS x, 2 AS y) AS s"
),
PLAN
);
}
#[test]
fn unrendered_derived_shapes_decline_without_crashing() {
let g = env!("CARGO_BIN_EXE_graphitesql");
for sql in [
"EXPLAIN QUERY PLAN SELECT * FROM (SELECT 1)", "EXPLAIN QUERY PLAN SELECT DISTINCT * FROM (SELECT 1) AS s", "EXPLAIN QUERY PLAN SELECT *,(SELECT 9) FROM (SELECT 1) AS s", "EXPLAIN QUERY PLAN SELECT * FROM (SELECT * FROM (SELECT 1)) AS s", ] {
let got = run(g, sql);
assert!(
!got.contains("no such table"),
"{sql} regressed to the malformed crash: {got:?}"
);
assert!(
got.contains("EXPLAIN QUERY PLAN for this query shape"),
"{sql} should decline as unsupported, got {got:?}"
);
}
}
#[test]
fn flattenable_wildcard_over_base_table_matches_sqlite() {
if !sqlite3_available() {
eprintln!("sqlite3 CLI not found; skipping");
return;
}
let g = env!("CARGO_BIN_EXE_graphitesql");
let base = "CREATE TABLE t(a,b); CREATE INDEX it ON t(a);";
for q in [
"SELECT * FROM (SELECT * FROM t) AS s",
"SELECT * FROM (SELECT * FROM t)",
"SELECT * FROM (SELECT a FROM t) AS s",
"SELECT * FROM (SELECT * FROM t WHERE a=5) AS s",
"SELECT * FROM (SELECT * FROM t WHERE a>5) AS s",
"SELECT * FROM (SELECT * FROM t WHERE b>0) AS s",
"SELECT * FROM (SELECT * FROM t ORDER BY b) AS s",
"SELECT * FROM (SELECT * FROM t) AS s LIMIT 5",
] {
let sql = format!("{base} EXPLAIN QUERY PLAN {q}");
assert_eq!(run("sqlite3", &sql), run(g, &sql), "for {q}");
}
}
#[test]
fn non_flattenable_outer_shapes_decline() {
let g = env!("CARGO_BIN_EXE_graphitesql");
let base = "CREATE TABLE t(a,b); CREATE INDEX it ON t(a); \
CREATE TABLE u(x,y); CREATE VIEW v AS SELECT * FROM t;";
for q in [
"SELECT a FROM (SELECT * FROM t) AS s", "SELECT * FROM (SELECT * FROM t) AS s WHERE a=5", "SELECT * FROM (SELECT * FROM t JOIN u ON t.a=u.x) AS s", "SELECT * FROM (SELECT DISTINCT a FROM t) AS s", "SELECT * FROM (SELECT count(*) FROM t) AS s", "SELECT * FROM (SELECT * FROM v) AS s", "SELECT * FROM (SELECT * FROM t LIMIT 5) AS s", ] {
let sql = format!("{base} EXPLAIN QUERY PLAN {q}");
let got = run(g, &sql);
assert!(
!got.contains("no such table"),
"{q} regressed to the malformed crash: {got:?}"
);
assert!(
got.contains("EXPLAIN QUERY PLAN for this query shape"),
"{q} should decline as unsupported, got {got:?}"
);
}
}
#[test]
fn derived_table_combined_with_a_join_declines() {
let g = env!("CARGO_BIN_EXE_graphitesql");
let base = "CREATE TABLE t(a,b); CREATE INDEX it ON t(a); CREATE TABLE u(x,y);";
for q in [
"SELECT * FROM (SELECT * FROM t) AS s, u",
"SELECT * FROM u, (SELECT * FROM t) AS s",
"SELECT * FROM (SELECT * FROM t) AS s JOIN u ON s.a=u.x",
"SELECT * FROM u JOIN (SELECT * FROM t) AS s ON s.a=u.x",
"SELECT * FROM u LEFT JOIN (SELECT * FROM t) AS s ON s.a=u.x",
"SELECT * FROM (SELECT 1) AS s, u",
"SELECT * FROM u, (SELECT 1) AS s",
] {
let sql = format!("{base} EXPLAIN QUERY PLAN {q}");
let got = run(g, &sql);
assert!(
!got.contains("no such table"),
"{q} regressed to the malformed crash: {got:?}"
);
assert!(
!got.contains("SCAN AS"),
"{q} emitted a malformed empty-named node: {got:?}"
);
assert!(
got.contains("EXPLAIN QUERY PLAN for this query shape"),
"{q} should decline as unsupported, got {got:?}"
);
}
}
#[test]
fn cte_reference_renders_like_a_derived_table() {
if !sqlite3_available() {
eprintln!("sqlite3 CLI not found; skipping");
return;
}
let g = env!("CARGO_BIN_EXE_graphitesql");
let base = "CREATE TABLE t(a,b); CREATE INDEX it ON t(a);";
for q in [
"WITH c AS (SELECT * FROM t) SELECT * FROM c",
"WITH c AS (SELECT 1) SELECT * FROM c",
"WITH c AS (SELECT 1, 2) SELECT * FROM c",
"WITH c AS (SELECT * FROM t WHERE a=5) SELECT * FROM c",
"WITH c AS (SELECT * FROM t ORDER BY b) SELECT * FROM c",
] {
let sql = format!("{base} EXPLAIN QUERY PLAN {q}");
assert_eq!(run("sqlite3", &sql), run(g, &sql), "for {q}");
}
}
#[test]
fn non_flattenable_cte_shapes_decline() {
let g = env!("CARGO_BIN_EXE_graphitesql");
let base = "CREATE TABLE t(a,b); CREATE INDEX it ON t(a); \
CREATE TABLE u(x,y); CREATE VIEW v AS SELECT * FROM t;";
for q in [
"WITH c AS (SELECT * FROM t) SELECT * FROM c, u",
"WITH c AS (SELECT * FROM t) SELECT a FROM c",
"WITH c AS (SELECT * FROM t) SELECT * FROM c WHERE a=5",
"WITH c AS (SELECT count(*) FROM t) SELECT * FROM c",
"WITH c AS (SELECT * FROM t), d AS (SELECT * FROM c) SELECT * FROM d",
"WITH c AS (SELECT * FROM v) SELECT * FROM c",
"WITH c AS (SELECT * FROM t) SELECT * FROM c AS x",
] {
let sql = format!("{base} EXPLAIN QUERY PLAN {q}");
let got = run(g, &sql);
assert!(
!got.contains("no such table"),
"{q} regressed to the malformed crash: {got:?}"
);
assert!(
got.contains("EXPLAIN QUERY PLAN for this query shape"),
"{q} should decline as unsupported, got {got:?}"
);
}
}
#[test]
fn matches_sqlite_cli() {
if !sqlite3_available() {
eprintln!("sqlite3 CLI not found; skipping");
return;
}
let g = env!("CARGO_BIN_EXE_graphitesql");
for sql in [
"EXPLAIN QUERY PLAN SELECT * FROM (SELECT 1) AS s",
"EXPLAIN QUERY PLAN SELECT * FROM (SELECT 1) AS s WHERE 1",
"EXPLAIN QUERY PLAN SELECT 1 FROM (SELECT 1) AS s LIMIT 1 OFFSET 0",
"EXPLAIN QUERY PLAN SELECT x FROM (SELECT 1 AS x, 2 AS y) AS s",
"EXPLAIN QUERY PLAN SELECT * FROM (SELECT 'a' || 'b') AS s",
] {
assert_eq!(run("sqlite3", sql), run(g, sql), "for {sql}");
}
}