#![cfg(feature = "std")]
use graphitesql::{Connection, Value};
fn setup() -> Connection {
let mut c = Connection::open_memory().unwrap();
c.execute("CREATE TABLE a(k INTEGER PRIMARY KEY, x)")
.unwrap();
c.execute("INSERT INTO a VALUES(1,'a1'),(2,'a2'),(3,'a3')")
.unwrap();
c.execute("CREATE TABLE b(p, y)").unwrap();
c.execute("INSERT INTO b VALUES(1,'b1'),(2,'b2'),(9,'b9')")
.unwrap();
c
}
fn both(c: &Connection, sql: &str, expected: Vec<Vec<Value>>) {
let v = c
.query_vdbe(sql)
.expect("must run on the VDBE (no fallback)");
assert_eq!(v.rows, expected, "VDBE mismatch for `{sql}`");
c.set_use_vdbe(false);
let tw = c.query(sql).unwrap();
c.set_use_vdbe(true);
assert_eq!(tw.rows, expected, "tree-walker mismatch for `{sql}`");
}
fn i(n: i64) -> Value {
Value::Integer(n)
}
fn t(s: &str) -> Value {
Value::Text(s.into())
}
#[test]
fn right_join_seek_matches_expected() {
let c = setup();
both(
&c,
"SELECT a.x, b.y FROM a RIGHT JOIN b ON a.k = b.p ORDER BY b.p",
vec![
vec![t("a1"), t("b1")],
vec![t("a2"), t("b2")],
vec![Value::Null, t("b9")],
],
);
both(
&c,
"SELECT b.y, a.x, a.k FROM a RIGHT JOIN b ON a.k = b.p ORDER BY b.p",
vec![
vec![t("b1"), t("a1"), i(1)],
vec![t("b2"), t("a2"), i(2)],
vec![t("b9"), Value::Null, Value::Null],
],
);
both(
&c,
"SELECT a.x FROM a RIGHT JOIN b ON a.k = b.p WHERE a.x IS NOT NULL ORDER BY b.p",
vec![vec![t("a1")], vec![t("a2")]],
);
}
#[test]
fn right_join_wildcard_runs_on_vdbe_with_correct_order() {
let c = setup();
let q = "SELECT * FROM a RIGHT JOIN b ON a.k = b.p ORDER BY b.p";
let v = c
.query_vdbe(q)
.expect("SELECT * RIGHT join runs on the VDBE");
assert_eq!(v.columns, vec!["k", "x", "p", "y"]);
let expected = vec![
vec![i(1), t("a1"), i(1), t("b1")],
vec![i(2), t("a2"), i(2), t("b2")],
vec![Value::Null, Value::Null, i(9), t("b9")],
];
assert_eq!(v.rows, expected, "VDBE mismatch");
c.set_use_vdbe(false);
let tw = c.query(q).unwrap();
c.set_use_vdbe(true);
assert_eq!(tw.rows, expected, "tree-walker mismatch");
}
#[test]
fn full_join_seek_matches_expected() {
let c = setup();
both(
&c,
"SELECT a.x, b.y FROM a FULL JOIN b ON a.k = b.p",
vec![
vec![t("a1"), t("b1")],
vec![t("a2"), t("b2")],
vec![t("a3"), Value::Null],
vec![Value::Null, t("b9")],
],
);
both(
&c,
"SELECT a.k, a.x, b.p, b.y FROM a FULL JOIN b ON a.k = b.p ORDER BY b.p, a.k",
vec![
vec![i(3), t("a3"), Value::Null, Value::Null],
vec![i(1), t("a1"), i(1), t("b1")],
vec![i(2), t("a2"), i(2), t("b2")],
vec![Value::Null, Value::Null, i(9), t("b9")],
],
);
both(
&c,
"SELECT coalesce(a.x,'none'), b.y FROM a FULL JOIN b ON a.k = b.p ORDER BY b.p",
vec![
vec![t("a3"), Value::Null],
vec![t("a1"), t("b1")],
vec![t("a2"), t("b2")],
vec![t("none"), t("b9")],
],
);
both(
&c,
"SELECT a.x, b.y FROM a FULL JOIN b ON a.k = b.p WHERE b.y IS NOT NULL ORDER BY b.p",
vec![
vec![t("a1"), t("b1")],
vec![t("a2"), t("b2")],
vec![Value::Null, t("b9")],
],
);
}
#[test]
fn full_join_wildcard_falls_back_correctly() {
let c = setup();
let q = "SELECT * FROM a FULL JOIN b ON a.k = b.p ORDER BY b.p, a.k";
c.set_use_vdbe(false);
let tw = c.query(q).unwrap();
c.set_use_vdbe(true);
let got = c.query(q).unwrap();
assert_eq!(got.rows, tw.rows);
assert_eq!(
got.rows,
vec![
vec![i(3), t("a3"), Value::Null, Value::Null],
vec![i(1), t("a1"), i(1), t("b1")],
vec![i(2), t("a2"), i(2), t("b2")],
vec![Value::Null, Value::Null, i(9), t("b9")],
],
);
}