use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn setup() -> Engine {
let mut e = Engine::new();
e.execute("CREATE TABLE drv (id INT, sk INT)").unwrap();
e.execute("CREATE INDEX drv_sk ON drv(sk)").unwrap();
e.execute("CREATE TABLE peer (pid INT PRIMARY KEY, cat TEXT)")
.unwrap();
e.execute("INSERT INTO drv (id, sk) VALUES (1,5),(2,5),(3,5),(4,9)")
.unwrap();
e.execute("INSERT INTO peer (pid, cat) VALUES (1,'a'),(2,''),(3,'c'),(4,'d')")
.unwrap();
e
}
fn rows(e: &mut Engine, sql: &str) -> Vec<spg_storage::Row<'static>> {
match e.execute(sql).unwrap() {
QueryResult::Rows { rows, .. } => rows,
other => panic!("expected rows from {sql:?}, got {other:?}"),
}
}
#[test]
fn inner_join_peer_predicate_filters_matched_pairs() {
let mut e = setup();
let r = rows(
&mut e,
"SELECT drv.id, peer.cat FROM drv JOIN peer ON peer.pid = drv.id \
WHERE drv.sk = 5 AND peer.cat != '' ORDER BY drv.id",
);
let got: Vec<(i32, String)> = r
.iter()
.map(|row| {
let id = match row.values[0] {
Value::Int(n) => n,
ref o => panic!("{o:?}"),
};
let cat = match &row.values[1] {
Value::Text(s) => s.to_string(),
o => panic!("{o:?}"),
};
(id, cat)
})
.collect();
assert_eq!(got, vec![(1, "a".into()), (3, "c".into())]);
}
#[test]
fn peer_predicate_equals_no_predicate_minus_filtered() {
let mut e = setup();
let with_pred = rows(
&mut e,
"SELECT drv.id FROM drv JOIN peer ON peer.pid = drv.id \
WHERE drv.sk = 5 AND peer.cat != '' ORDER BY drv.id",
);
let no_pred = rows(
&mut e,
"SELECT drv.id FROM drv JOIN peer ON peer.pid = drv.id \
WHERE drv.sk = 5 ORDER BY drv.id",
);
assert_eq!(no_pred.len(), 3, "ids 1,2,3 seeked");
assert_eq!(with_pred.len(), 2, "id 2 (empty cat) dropped");
}
#[test]
fn peer_predicate_in_aggregate_over_thread_list() {
let mut e = Engine::new();
e.execute("CREATE TABLE m (id INT, thread INT)").unwrap();
e.execute("CREATE INDEX m_thread ON m(thread)").unwrap();
e.execute("CREATE TABLE ea (mid INT PRIMARY KEY, cat TEXT)")
.unwrap();
e.execute("INSERT INTO m (id, thread) VALUES (1,10),(2,10),(3,20),(4,20)")
.unwrap();
e.execute("INSERT INTO ea (mid, cat) VALUES (1,'x'),(2,''),(3,'y'),(4,'')")
.unwrap();
let r = rows(
&mut e,
"SELECT m.thread, COUNT(*) FROM m JOIN ea ON ea.mid = m.id \
WHERE m.thread IN (10,20) AND ea.cat != '' GROUP BY m.thread ORDER BY m.thread",
);
assert_eq!(r.len(), 2);
assert!(
matches!(r[0].values[1], Value::BigInt(1)),
"thread10 {:?}",
r[0].values[1]
);
assert!(
matches!(r[1].values[1], Value::BigInt(1)),
"thread20 {:?}",
r[1].values[1]
);
}