use spg_engine::Engine;
const P: &str = "11111111-1111-4111-8111-111111111111";
const C: &str = "22222222-2222-4222-8222-222222222222";
fn scalar(eng: &mut Engine, sql: &str) -> String {
match eng.execute(sql) {
Ok(out) => {
let text = format!("{out:?}");
text.rsplit_once("Int(")
.and_then(|(_, r)| r.split(')').next())
.unwrap_or("?")
.to_string()
}
Err(e) => format!("ERROR {e:?}"),
}
}
fn build(key_ty: &str, p_val: &str, c_val: &str) -> Engine {
let mut eng = Engine::new();
eng.execute(&format!(
"CREATE TABLE p (id {key_ty} PRIMARY KEY, tag TEXT)"
))
.expect("create p");
eng.execute(&format!(
"CREATE TABLE c (id {key_ty} PRIMARY KEY, parent_id {key_ty}, note TEXT)"
))
.expect("create c");
eng.execute(&format!("INSERT INTO p VALUES ({p_val}, 'keep')"))
.expect("insert p");
eng.execute(&format!("INSERT INTO c VALUES ({c_val}, {p_val}, 'n')"))
.expect("insert c");
eng
}
fn main() {
let cases: [(&str, &str, &str); 3] = [
("int", "1", "2"),
("text", "'p-1'", "'c-2'"),
("uuid", &format!("'{P}'"), &format!("'{C}'")),
];
println!(
"{:<6} {:>9} {:>10} {:>11} {:>9}",
"key", "no WHERE", "left", "right", "swapped"
);
for (ty, p_val, c_val) in cases {
let mut e = build(ty, p_val, c_val);
let none = scalar(
&mut e,
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id",
);
let left = scalar(
&mut e,
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE c.note = 'n'",
);
let right = scalar(
&mut e,
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
);
let swapped = scalar(
&mut e,
"SELECT count(*) FROM p JOIN c ON c.parent_id = p.id WHERE p.tag = 'keep'",
);
println!("{ty:<6} {none:>9} {left:>10} {right:>11} {swapped:>9}");
}
println!("\nevery cell must be 1");
println!("\n== what the failing cell needs (uuid, WHERE on the right)");
let variants: [(&str, &str, &str); 7] = [
(
"as reported",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
),
(
"p.id not a PK",
"CREATE TABLE p (id uuid, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
),
(
"predicate IS NOT NULL",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag IS NOT NULL",
),
(
"predicate on both sides",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep' AND c.note = 'n'",
),
(
"select rows not count",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"SELECT count(*) FROM (SELECT c.id FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep') q",
),
(
"uuid index but not PK",
"CREATE TABLE p (id uuid, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
),
(
"ON reversed",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"SELECT count(*) FROM c JOIN p ON c.parent_id = p.id WHERE p.tag = 'keep'",
),
];
for (label, create_p, sql) in variants {
let mut e = Engine::new();
e.execute(create_p).expect("create p");
if label == "uuid index but not PK" {
e.execute("CREATE INDEX p_id_ix ON p (id)").expect("index");
}
e.execute("CREATE TABLE c (id uuid PRIMARY KEY, parent_id uuid, note TEXT)")
.expect("create c");
e.execute(&format!("INSERT INTO p VALUES ('{P}', 'keep')"))
.expect("insert p");
e.execute(&format!("INSERT INTO c VALUES ('{C}', '{P}', 'n')"))
.expect("insert c");
println!(" {label:<24} {}", scalar(&mut e, sql));
}
println!("\n== is the join key surviving the peer's projection?");
for (label, sql) in [
(
"count(*)",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
),
(
"select p.id",
"SELECT count(*) FROM (SELECT p.id FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep') q",
),
(
"p.id named in WHERE",
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep' AND p.id IS NOT NULL",
),
(
"select p.tag",
"SELECT count(*) FROM (SELECT p.tag FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep') q",
),
] {
let mut e = Engine::new();
e.execute("CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)")
.expect("create p");
e.execute("CREATE TABLE c (id uuid PRIMARY KEY, parent_id uuid, note TEXT)")
.expect("create c");
e.execute(&format!("INSERT INTO p VALUES ('{P}', 'keep')"))
.expect("insert p");
e.execute(&format!("INSERT INTO c VALUES ('{C}', '{P}', 'n')"))
.expect("insert c");
println!(" {label:<24} {}", scalar(&mut e, sql));
}
println!("\n== does the join column's POSITION in the table matter?");
for (label, create_p, ins) in [
(
"join col first",
"CREATE TABLE p (id uuid PRIMARY KEY, tag TEXT)",
"('{P}', 'keep')",
),
(
"join col second",
"CREATE TABLE p (tag TEXT, id uuid PRIMARY KEY)",
"('keep', '{P}')",
),
] {
let mut e = Engine::new();
e.execute(create_p).expect("create p");
e.execute("CREATE TABLE c (id uuid PRIMARY KEY, parent_id uuid, note TEXT)")
.expect("create c");
e.execute(&format!("INSERT INTO p VALUES {}", ins.replace("{P}", P)))
.expect("insert p");
e.execute(&format!("INSERT INTO c VALUES ('{C}', '{P}', 'n')"))
.expect("insert c");
let r = scalar(
&mut e,
"SELECT count(*) FROM c JOIN p ON p.id = c.parent_id WHERE p.tag = 'keep'",
);
println!(" {label:<24} {r}");
}
}