use crate::{ALLOC_CALLS, perf_lock};
use spg_engine::{Engine, QueryResult};
use std::sync::atomic::Ordering;
const ROWS: usize = 4_000;
const GROUPS: usize = 200;
const BODY_BYTES: usize = 2 * 1024; const ALLOC_PER_ROW_BUDGET: usize = 12;
#[test]
fn ordered_aggregate_reads_sort_key_by_reference() {
let _g = perf_lock();
let mut eng = Engine::new();
eng.execute("CREATE TABLE t (g BIGINT, rank BIGINT, label TEXT, dim BIGINT, body TEXT)")
.unwrap();
eng.execute("CREATE TABLE d (id BIGINT, name TEXT)")
.unwrap();
eng.execute("INSERT INTO d VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d')")
.unwrap();
let body = "x".repeat(BODY_BYTES);
let mut i = 0usize;
while i < ROWS {
let mut stmt = String::with_capacity(40 * BODY_BYTES);
stmt.push_str("INSERT INTO t VALUES ");
for k in 0..40 {
let id = i + k;
if k > 0 {
stmt.push(',');
}
stmt.push_str(&format!(
"({}, {}, 'L{}', {}, '{body}')",
id % GROUPS,
id,
id % 7,
id % 4 + 1
));
}
eng.execute(&stmt).unwrap();
i += 40;
}
let sql = "SELECT t.g, array_agg(t.label ORDER BY t.rank DESC) \
FROM t JOIN d ON t.dim = d.id GROUP BY t.g";
eng.execute(sql).unwrap();
let a0 = ALLOC_CALLS.load(Ordering::Relaxed);
let r = eng.execute(sql).unwrap();
let allocs = ALLOC_CALLS.load(Ordering::Relaxed) - a0;
match r {
QueryResult::Rows { rows, .. } => assert_eq!(rows.len(), GROUPS),
other => panic!("unexpected result: {other:?}"),
}
let per_row = allocs as f64 / ROWS as f64;
assert!(
per_row <= ALLOC_PER_ROW_BUDGET as f64,
"ordered aggregate allocated {per_row:.1}/row ({allocs} for {ROWS} rows) — \
budget {ALLOC_PER_ROW_BUDGET}/row; the per-row full-row materialisation \
(cloning the untouched {BODY_BYTES}-byte body) regressed back in"
);
}