use stoolap::Database;
fn setup_db(name: &str) -> Database {
Database::open(&format!("memory://{}", name)).expect("Failed to create database")
}
#[test]
fn test_bug_01_having_with_aggregates() {
let db = setup_db("bug01");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, category TEXT, price FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO orders VALUES (1, 'A', 50.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (2, 'A', 75.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (3, 'B', 30.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT category, SUM(price) as total FROM orders GROUP BY category HAVING SUM(price) > 100",
(),
)
.expect("Query should succeed - HAVING with aggregate");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only category A has sum > 100");
let row = rows[0].as_ref().expect("Row should exist");
let category: String = row.get(0).unwrap();
assert_eq!(category, "A");
}
#[test]
fn test_bug_02_join_on_with_and_conditions() {
let db = setup_db("bug02");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, category TEXT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 'Apple', 'Fruit')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 'Banana', 'Fruit')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 'Carrot', 'Veg')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (4, 'Broccoli', 'Veg')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (5, 'Orange', 'Fruit')", ())
.expect("Insert failed");
let result = db
.query(
"SELECT a.id, a.name, b.id, b.name FROM t a INNER JOIN t b ON a.id < b.id AND a.category = b.category",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
4,
"Should have 4 pairs matching both conditions"
);
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let a_id: i64 = row.get(0).unwrap();
let b_id: i64 = row.get(2).unwrap();
assert!(a_id < b_id, "a.id ({}) should be < b.id ({})", a_id, b_id);
}
}
#[test]
fn test_bug_03_update_with_scalar_subquery() {
let db = setup_db("bug03");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert failed");
db.execute(
"UPDATE t SET val = (SELECT MAX(val) FROM t) WHERE id = 1",
(),
)
.expect("Update should succeed");
let result = db
.query("SELECT val FROM t WHERE id = 1", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().expect("Row should exist");
let val: i64 = row.get(0).unwrap();
assert_eq!(val, 30, "id=1 should have val=30 (MAX of all vals)");
}
#[test]
fn test_bug_04_multiple_column_aliases() {
let db = setup_db("bug04");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
let result = db
.query("SELECT id AS a, val AS b FROM t", ())
.expect("Query should succeed");
let column_names = result.columns();
assert_eq!(
column_names[0], "a",
"First column should be aliased as 'a'"
);
assert_eq!(
column_names[1], "b",
"Second column should be aliased as 'b'"
);
}
#[test]
fn test_bug_05_aggregate_window_functions() {
let db = setup_db("bug05");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, category TEXT, val INTEGER)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 'A', 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 'A', 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 'B', 30)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT id, val, SUM(val) OVER (PARTITION BY category ORDER BY id) as running_sum FROM t",
(),
)
.expect("Query should succeed - SUM as window function");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should have 3 rows");
let mut found_running_sums = Vec::new();
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let running_sum: i64 = row.get(2).unwrap();
found_running_sums.push(running_sum);
}
assert!(
found_running_sums.contains(&10),
"Should have running sum 10"
);
assert!(
found_running_sums.contains(&30),
"Should have running sum 30 (either A total or B)"
);
}
#[test]
fn test_bug_06_order_by_arithmetic_expression() {
let db = setup_db("bug06");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, amount FLOAT)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 1.50)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 0.75)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 0.50)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (4, 1.25)", ())
.expect("Insert failed");
let result = db
.query("SELECT id, amount FROM t ORDER BY amount * -1", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
let expected_order = [1, 4, 2, 3];
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref().expect("Row should exist");
let id: i64 = row.get(0).unwrap();
assert_eq!(
id, expected_order[i],
"Row {} should have id {}",
i, expected_order[i]
);
}
}
#[test]
fn test_bug_07_order_by_aggregate_expression() {
let db = setup_db("bug07");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, customer TEXT, amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO orders VALUES (1, 'Alice', 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (2, 'Bob', 200.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (3, 'Alice', 150.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (4, 'Bob', 100.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT customer, SUM(amount) as total FROM orders GROUP BY customer ORDER BY SUM(amount) DESC",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
let first_row = rows[0].as_ref().expect("Row should exist");
let first_customer: String = first_row.get(0).unwrap();
assert_eq!(
first_customer, "Bob",
"Bob (300) should be first when ORDER BY SUM DESC"
);
}
#[test]
fn test_bug_08_nulls_first() {
let db = setup_db("bug08");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, NULL)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 5)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, NULL)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (4, 10)", ())
.expect("Insert failed");
let result = db
.query("SELECT id, val FROM t ORDER BY val NULLS FIRST", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4, "Should have 4 rows");
let first_row = rows[0].as_ref().expect("Row should exist");
let first_val: Option<i64> = first_row.get(1).ok();
assert!(
first_val.is_none(),
"First row should have NULL with NULLS FIRST"
);
let second_row = rows[1].as_ref().expect("Row should exist");
let second_val: Option<i64> = second_row.get(1).ok();
assert!(
second_val.is_none(),
"Second row should have NULL with NULLS FIRST"
);
}
#[test]
fn test_bug_09_cte_join_with_expression() {
let db = setup_db("bug09");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t1 VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t1 VALUES (2, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t2 VALUES (2, 100)", ())
.expect("Insert failed");
db.execute("INSERT INTO t2 VALUES (3, 200)", ())
.expect("Insert failed");
let result = db
.query("SELECT * FROM t1 INNER JOIN t2 ON t1.id + 1 = t2.id", ())
.expect("Regular table join should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Regular table join should return 2 rows");
let result = db
.query(
"WITH cte1 AS (SELECT * FROM t1), cte2 AS (SELECT * FROM t2)
SELECT * FROM cte1 INNER JOIN cte2 ON cte1.id + 1 = cte2.id",
(),
)
.expect("CTE join should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"CTE join with expression should return same as regular join"
);
}
#[test]
fn test_bug_10_group_by_with_column_alias() {
let db = setup_db("bug10");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, product TEXT, qty INTEGER)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO orders VALUES (1, 'Apple', 5)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (2, 'Banana', 3)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (3, 'Apple', 2)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT product, qty * 10 as qty_10 FROM orders GROUP BY product, qty * 10",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let qty_10: i64 = row.get(1).expect("qty_10 should not be NULL");
assert!(qty_10 > 0, "qty_10 should be a positive value");
}
}
#[test]
fn test_bug_11_current_date_time_timestamp() {
let db = setup_db("bug11");
let result = db
.query("SELECT CURRENT_DATE", ())
.expect("CURRENT_DATE query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let date: String = row.get(0).expect("CURRENT_DATE should not be NULL");
assert!(!date.is_empty(), "CURRENT_DATE should return a value");
let result = db
.query("SELECT CURRENT_TIMESTAMP", ())
.expect("CURRENT_TIMESTAMP query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let ts: String = row.get(0).expect("CURRENT_TIMESTAMP should not be NULL");
assert!(!ts.is_empty(), "CURRENT_TIMESTAMP should return a value");
}
#[test]
fn test_bug_12_three_table_join() {
let db = setup_db("bug12");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute(
"CREATE TABLE t2 (id INTEGER PRIMARY KEY, t1_id INTEGER, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE TABLE t3 (id INTEGER PRIMARY KEY, t2_id INTEGER, descr TEXT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO t1 VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t1 VALUES (2, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t1 VALUES (3, 30)", ())
.expect("Insert failed");
db.execute("INSERT INTO t2 VALUES (1, 1, 'A')", ())
.expect("Insert failed");
db.execute("INSERT INTO t2 VALUES (2, 1, 'B')", ())
.expect("Insert failed");
db.execute("INSERT INTO t2 VALUES (3, 2, 'C')", ())
.expect("Insert failed");
db.execute("INSERT INTO t3 VALUES (1, 1, 'Desc1')", ())
.expect("Insert failed");
db.execute("INSERT INTO t3 VALUES (2, 2, 'Desc2')", ())
.expect("Insert failed");
let result = db
.query(
"SELECT t1.id, t2.id as t2_id, t2.name, t3.t2_id, t3.descr
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
INNER JOIN t3 ON t2.id = t3.t2_id",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 matching rows");
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let t2_id: i64 = row.get(1).unwrap();
let t3_t2_id: i64 = row.get(3).unwrap();
assert_eq!(
t2_id, t3_t2_id,
"t2.id ({}) should equal t3.t2_id ({})",
t2_id, t3_t2_id
);
}
}
#[test]
fn test_bug_13_derived_table_where() {
let db = setup_db("bug13");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT * FROM (SELECT id, val * 2 as doubled FROM t) as sub WHERE doubled > 30",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"Should have 2 rows where doubled > 30 (40 and 60)"
);
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let doubled: i64 = row.get(1).unwrap();
assert!(doubled > 30, "All doubled values should be > 30");
}
}
#[test]
fn test_bug_14_having_aggregate_not_in_select() {
let db = setup_db("bug14");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER, grp TEXT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10, 'A')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 20, 'A')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 30, 'B')", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (4, 40, 'B')", ())
.expect("Insert failed");
let result = db
.query("SELECT grp FROM t GROUP BY grp HAVING SUM(val) > 50", ())
.expect("Query should succeed - HAVING aggregate not in SELECT");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only group B has SUM(val) > 50");
let row = rows[0].as_ref().expect("Row should exist");
let grp: String = row.get(0).unwrap();
assert_eq!(grp, "B");
}
#[test]
fn test_bug_15_dense_rank() {
let db = setup_db("bug15");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (4, 30)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT id, val, DENSE_RANK() OVER (ORDER BY val) as drank FROM t ORDER BY id",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4);
let expected_ranks = [1i64, 2, 2, 3];
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref().expect("Row should exist");
let drank: i64 = row.get(2).unwrap();
assert_eq!(
drank, expected_ranks[i],
"Row {} should have DENSE_RANK {}",
i, expected_ranks[i]
);
}
}
#[test]
fn test_bug_16_left_right_string_functions() {
let db = setup_db("bug16");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 'hello')", ())
.expect("Insert failed");
let result = db
.query("SELECT LEFT(name, 3), RIGHT(name, 3) FROM t", ())
.expect("LEFT/RIGHT functions should parse correctly");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let left_val: String = row.get(0).unwrap();
let right_val: String = row.get(1).unwrap();
assert_eq!(left_val, "hel", "LEFT('hello', 3) should be 'hel'");
assert_eq!(right_val, "llo", "RIGHT('hello', 3) should be 'llo'");
}
#[test]
fn test_bug_17_char_function() {
let db = setup_db("bug17");
let result = db
.query("SELECT CHAR(65)", ())
.expect("CHAR function should parse correctly");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let char_val: String = row.get(0).unwrap();
assert_eq!(char_val, "A", "CHAR(65) should be 'A'");
}
#[test]
fn test_bug_18_qualified_star() {
let db = setup_db("bug18");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
let result = db
.query("SELECT t.* FROM t", ())
.expect("Qualified star should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let id: i64 = row.get(0).unwrap();
let val: i64 = row.get(1).unwrap();
assert_eq!(id, 1);
assert_eq!(val, 10);
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t2 VALUES (1, 'Alice')", ())
.expect("Insert failed");
let result = db
.query(
"SELECT t.*, t2.name FROM t INNER JOIN t2 ON t.id = t2.id",
(),
)
.expect("Qualified star in join should work");
let column_names = result.columns();
assert_eq!(
column_names.len(),
3,
"Should have 3 columns: t.id, t.val, t2.name"
);
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
}
#[test]
fn test_bug_19_string_escape_sequences() {
let db = setup_db("bug19");
let result = db
.query("SELECT 'Hello ''World''' as escaped", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let escaped: String = row.get(0).unwrap();
assert_eq!(
escaped, "Hello 'World'",
"Escaped quotes should be processed: '' -> '"
);
}
#[test]
fn test_qualified_star_with_alias() {
let db = setup_db("qualified_star_alias");
db.execute(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, dept TEXT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO employees VALUES (1, 'Alice', 'Eng')", ())
.expect("Insert failed");
db.execute("INSERT INTO employees VALUES (2, 'Bob', 'Sales')", ())
.expect("Insert failed");
let result = db
.query("SELECT e.* FROM employees e WHERE e.dept = 'Eng'", ())
.expect("Qualified star with alias should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().expect("Row should exist");
let name: String = row.get(1).unwrap();
assert_eq!(name, "Alice");
}
#[test]
fn test_multiple_qualified_stars_in_join() {
let db = setup_db("multi_qualified_star");
db.execute("CREATE TABLE a (id INTEGER PRIMARY KEY, a_val TEXT)", ())
.expect("Failed to create table");
db.execute("CREATE TABLE b (id INTEGER PRIMARY KEY, b_val TEXT)", ())
.expect("Failed to create table");
db.execute("INSERT INTO a VALUES (1, 'A1')", ())
.expect("Insert failed");
db.execute("INSERT INTO b VALUES (1, 'B1')", ())
.expect("Insert failed");
let result = db
.query("SELECT a.*, b.* FROM a INNER JOIN b ON a.id = b.id", ())
.expect("Multiple qualified stars should work");
let column_names = result.columns();
assert_eq!(column_names.len(), 4, "Should have 4 columns total");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
}
#[test]
fn test_complex_string_escapes() {
let db = setup_db("complex_escapes");
let result = db
.query("SELECT 'It''s a ''test'' string' as complex", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().expect("Row should exist");
let complex: String = row.get(0).unwrap();
assert_eq!(complex, "It's a 'test' string");
let result = db
.query("SELECT '''' as just_quote", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().expect("Row should exist");
let just_quote: String = row.get(0).unwrap();
assert_eq!(just_quote, "'", "Four quotes should become one quote");
}
#[test]
fn test_bug_20_cte_in_subquery() {
let db = setup_db("bug20");
db.execute(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, department TEXT, salary FLOAT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO employees VALUES (1, 'Alice', 'Engineering', 95000.0)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO employees VALUES (2, 'Bob', 'Engineering', 85000.0)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO employees VALUES (3, 'Charlie', 'Sales', 75000.0)",
(),
)
.expect("Insert failed");
let result = db
.query(
"WITH high_depts AS (SELECT department FROM employees WHERE salary > 90000)
SELECT name FROM employees WHERE department IN (SELECT department FROM high_depts)
ORDER BY name",
(),
)
.expect("Query should succeed - CTE in subquery");
let names: Vec<String> = result
.into_iter()
.filter_map(|r| r.ok())
.map(|row| row.get::<String>(0).unwrap())
.collect();
assert_eq!(names, vec!["Alice", "Bob"]);
}
#[test]
fn test_bug_21_group_by_extra_columns() {
let db = setup_db("bug21");
db.execute("CREATE TABLE test (id INTEGER, name TEXT, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO test VALUES (1, 'A', 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO test VALUES (1, 'A', 20)", ())
.expect("Insert failed");
db.execute("INSERT INTO test VALUES (2, 'B', 30)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT name, SUM(val) as total FROM test GROUP BY id, name ORDER BY name",
(),
)
.expect("Query should succeed - GROUP BY with extra columns");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 groups");
let row0 = rows[0].as_ref().expect("Row should exist");
let name: String = row0.get(0).unwrap();
let total: f64 = row0.get(1).unwrap();
assert_eq!(name, "A");
assert_eq!(total, 30.0);
let row1 = rows[1].as_ref().expect("Row should exist");
let name: String = row1.get(0).unwrap();
let total: f64 = row1.get(1).unwrap();
assert_eq!(name, "B");
assert_eq!(total, 30.0);
}
#[test]
fn test_bug_22_window_function_arithmetic() {
let db = setup_db("bug22");
db.execute(
"CREATE TABLE test_wf (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO test_wf VALUES (1, 10), (2, 20), (3, 35), (4, 50)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT id, val, val - LAG(val, 1) OVER (ORDER BY id) AS diff FROM test_wf",
(),
)
.expect("Query should succeed - arithmetic with window function");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4);
let row0 = rows[0].as_ref().expect("Row should exist");
let diff0: Option<i64> = row0.get(2).ok();
assert!(diff0.is_none(), "First row diff should be NULL");
let row1 = rows[1].as_ref().expect("Row should exist");
let diff1: i64 = row1.get(2).unwrap();
assert_eq!(diff1, 10);
let row2 = rows[2].as_ref().expect("Row should exist");
let diff2: i64 = row2.get(2).unwrap();
assert_eq!(diff2, 15);
let row3 = rows[3].as_ref().expect("Row should exist");
let diff3: i64 = row3.get(2).unwrap();
assert_eq!(diff3, 15);
}
#[test]
fn test_bug_22_multiple_window_expressions() {
let db = setup_db("bug22b");
db.execute(
"CREATE TABLE test_wf2 (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO test_wf2 VALUES (1, 10), (2, 20), (3, 35), (4, 50)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT id,
val + LAG(val, 1) OVER (ORDER BY id) AS sum_with_prev,
val * 2 - LEAD(val, 1) OVER (ORDER BY id) AS double_minus_next
FROM test_wf2",
(),
)
.expect("Query should succeed - multiple window function expressions");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4);
let row1 = rows[1].as_ref().expect("Row should exist");
let sum_with_prev: i64 = row1.get(1).unwrap();
let double_minus_next: i64 = row1.get(2).unwrap();
assert_eq!(sum_with_prev, 30);
assert_eq!(double_minus_next, 5);
let row2 = rows[2].as_ref().expect("Row should exist");
let sum_with_prev: i64 = row2.get(1).unwrap();
let double_minus_next: i64 = row2.get(2).unwrap();
assert_eq!(sum_with_prev, 55);
assert_eq!(double_minus_next, 20);
}
#[test]
fn test_bug_23_extract_function() {
let db = setup_db("bug23");
let result = db
.query("SELECT EXTRACT(YEAR FROM DATE '2024-01-15')", ())
.expect("EXTRACT YEAR should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let year: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(year, 2024);
let result = db
.query("SELECT EXTRACT(MONTH FROM DATE '2024-01-15')", ())
.expect("EXTRACT MONTH should work");
let rows: Vec<_> = result.collect();
let month: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(month, 1);
let result = db
.query("SELECT EXTRACT(DAY FROM DATE '2024-01-15')", ())
.expect("EXTRACT DAY should work");
let rows: Vec<_> = result.collect();
let day: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(day, 15);
let result = db
.query(
"SELECT EXTRACT(HOUR FROM TIMESTAMP '2024-01-15 14:30:45')",
(),
)
.expect("EXTRACT HOUR should work");
let rows: Vec<_> = result.collect();
let hour: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(hour, 14);
db.execute(
"CREATE TABLE dates (id INTEGER PRIMARY KEY, dt TIMESTAMP)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO dates VALUES (1, '2024-06-20 09:15:30')", ())
.expect("Insert failed");
let result = db
.query(
"SELECT EXTRACT(YEAR FROM dt), EXTRACT(MONTH FROM dt) FROM dates WHERE id = 1",
(),
)
.expect("EXTRACT from column should work");
let rows: Vec<_> = result.collect();
let year: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
let month: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
assert_eq!(year, 2024);
assert_eq!(month, 6);
}
#[test]
fn test_bug_24_json_operators() {
let db = setup_db("bug24");
let result = db
.query(r#"SELECT '{"name": "test", "value": 42}' -> 'name'"#, ())
.expect("JSON -> operator should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let json_result: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(json_result, "\"test\"");
let result = db
.query(r#"SELECT '{"name": "test", "value": 42}' ->> 'name'"#, ())
.expect("JSON ->> operator should work");
let rows: Vec<_> = result.collect();
let text_result: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(text_result, "test");
let result = db
.query(r#"SELECT '{"name": "test", "value": 42}' ->> 'value'"#, ())
.expect("JSON ->> with number should work");
let rows: Vec<_> = result.collect();
let value: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(value, "42");
let result = db
.query(r#"SELECT '[1, 2, 3]' -> 0"#, ())
.expect("JSON array access should work");
let rows: Vec<_> = result.collect();
let first: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(first, "1");
let result = db
.query(r#"SELECT '["a", "b", "c"]' ->> 1"#, ())
.expect("JSON array ->> should work");
let rows: Vec<_> = result.collect();
let second: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(second, "b");
let result = db
.query(
r#"SELECT '{"user": {"name": "Alice", "age": 30}}' -> 'user' ->> 'name'"#,
(),
)
.expect("Chained JSON access should work");
let rows: Vec<_> = result.collect();
let name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(name, "Alice");
db.execute(
"CREATE TABLE json_data (id INTEGER PRIMARY KEY, data JSON)",
(),
)
.expect("Failed to create table");
db.execute(
r#"INSERT INTO json_data VALUES (1, '{"product": "Widget", "price": 19.99}')"#,
(),
)
.expect("Insert failed");
db.execute(
r#"INSERT INTO json_data VALUES (2, '{"product": "Gadget", "price": 29.99}')"#,
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT id, data ->> 'product' AS product FROM json_data ORDER BY id",
(),
)
.expect("JSON access from column should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
let product1: String = rows[0].as_ref().unwrap().get(1).unwrap();
let product2: String = rows[1].as_ref().unwrap().get(1).unwrap();
assert_eq!(product1, "Widget");
assert_eq!(product2, "Gadget");
let result = db
.query(r#"SELECT '{"a": 1}' -> 'missing'"#, ())
.expect("Missing key should return NULL");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let null_val: Option<String> = row.get(0).unwrap();
assert!(null_val.is_none(), "Missing key should return NULL");
}
#[test]
fn test_bug_25_multi_column_in() {
let db = setup_db("bug25");
db.execute(
"CREATE TABLE multi_in_test (a INTEGER, b INTEGER, c TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO multi_in_test VALUES (1, 10, 'x'), (2, 20, 'y'), (3, 30, 'x'), (1, 10, 'z')",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT a, b, c FROM multi_in_test WHERE (a, b) IN ((1, 10), (3, 30)) ORDER BY a, c",
(),
)
.expect("Multi-column IN should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
3,
"Should match 3 rows (two with (1,10), one with (3,30))"
);
let row0 = rows[0].as_ref().unwrap();
assert_eq!(row0.get::<i64>(0).unwrap(), 1);
assert_eq!(row0.get::<i64>(1).unwrap(), 10);
let result = db
.query(
"SELECT a, b FROM multi_in_test WHERE (a, b) NOT IN ((1, 10), (3, 30))",
(),
)
.expect("Multi-column NOT IN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only (2, 20) should not match");
let row = rows[0].as_ref().unwrap();
assert_eq!(row.get::<i64>(0).unwrap(), 2);
assert_eq!(row.get::<i64>(1).unwrap(), 20);
let result = db
.query(
"SELECT a, b, c FROM multi_in_test WHERE (a, b, c) IN ((1, 10, 'x'), (2, 20, 'y'))",
(),
)
.expect("Three-column IN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should match exactly 2 rows");
let texts: Vec<String> = rows
.iter()
.map(|r| r.as_ref().unwrap().get::<String>(2).unwrap())
.collect();
assert!(texts.contains(&"x".to_string()));
assert!(texts.contains(&"y".to_string()));
}
#[test]
fn test_bug_26_union_with_as_keyword() {
let db = setup_db("bug26");
db.execute(
"CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, dept TEXT, salary FLOAT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO employees VALUES (1, 'Alice', 'Engineering', 95000)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO employees VALUES (2, 'Bob', 'Engineering', 85000)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO employees VALUES (3, 'Charlie', 'Sales', 75000)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT name, 'High' as level FROM employees WHERE salary > 90000
UNION
SELECT name, 'Low' as level FROM employees WHERE salary < 80000",
(),
)
.expect("UNION with AS keyword should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"Should have 2 rows (Alice=High, Charlie=Low)"
);
let mut found_alice = false;
let mut found_charlie = false;
for row in &rows {
let row = row.as_ref().unwrap();
let name: String = row.get(0).unwrap();
let level: String = row.get(1).unwrap();
if name == "Alice" {
assert_eq!(level, "High");
found_alice = true;
}
if name == "Charlie" {
assert_eq!(level, "Low");
found_charlie = true;
}
}
assert!(found_alice && found_charlie);
}
#[test]
fn test_bug_27_aggregate_in_expression() {
let db = setup_db("bug27");
db.execute("CREATE TABLE t27 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t27 VALUES (1, 10), (2, 20), (3, 30)", ())
.expect("Insert failed");
let result = db
.query("SELECT COALESCE(SUM(val), 0) FROM t27", ())
.expect("COALESCE(SUM(val), 0) should work");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let sum: i64 = row.get(0).unwrap();
assert_eq!(sum, 60, "COALESCE(SUM(val), 0) should be 60");
let result = db
.query("SELECT SUM(val) + 10 as sum_plus FROM t27", ())
.expect("SUM(val) + 10 should work");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let sum_plus: i64 = row.get(0).unwrap();
assert_eq!(sum_plus, 70, "SUM(val) + 10 should be 70");
let result = db
.query("SELECT ABS(SUM(val)) FROM t27", ())
.expect("ABS(SUM(val)) should work");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let abs_sum: i64 = row.get(0).unwrap();
assert_eq!(abs_sum, 60, "ABS(SUM(val)) should be 60");
}
#[test]
fn test_bug_28_scalar_subquery_column_resolution() {
let db = setup_db("bug28");
db.execute(
"CREATE TABLE mc (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO mc VALUES (1, 10, 100), (2, 20, 200)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT id, (SELECT MAX(b) FROM mc) as max_b FROM mc ORDER BY id",
(),
)
.expect("Scalar subquery with other columns should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
for row in &rows {
let row = row.as_ref().unwrap();
let max_b: i64 = row.get(1).unwrap();
assert_eq!(max_b, 200, "Scalar subquery should return MAX(b) = 200");
}
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 2]);
}
#[test]
fn test_bug_29_view_with_aggregate() {
let db = setup_db("bug29");
db.execute(
"CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price FLOAT, category TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO products VALUES (1, 'Apple', 1.50, 'Fruit')",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO products VALUES (2, 'Banana', 0.75, 'Fruit')",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO products VALUES (3, 'Orange', 2.00, 'Fruit')",
(),
)
.expect("Insert failed");
db.execute(
"CREATE VIEW fruit_stats AS SELECT COUNT(*) as cnt, AVG(price) as avg_price FROM products WHERE category = 'Fruit'",
(),
)
.expect("Failed to create view");
let result = db
.query("SELECT * FROM fruit_stats", ())
.expect("VIEW with aggregate should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let row = rows[0].as_ref().unwrap();
let cnt: i64 = row.get(0).unwrap();
let avg_price: f64 = row.get(1).unwrap();
assert_eq!(cnt, 3, "COUNT(*) should be 3");
assert!(
(avg_price - 1.4167).abs() < 0.01,
"AVG(price) should be ~1.4167"
);
}
#[test]
fn test_bug_30_aggregation_on_views() {
let db = setup_db("bug30");
db.execute(
"CREATE TABLE t30 (id INTEGER PRIMARY KEY, cat TEXT, val FLOAT, active BOOLEAN)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t30 VALUES (1, 'A', 100.0, TRUE), (2, 'A', 150.0, TRUE), (3, 'B', 200.0, TRUE)",
(),
)
.expect("Insert failed");
db.execute(
"CREATE VIEW v30 AS SELECT id, cat, val FROM t30 WHERE active = TRUE",
(),
)
.expect("Failed to create view");
let result = db
.query(
"SELECT cat, SUM(val) as total FROM v30 GROUP BY cat ORDER BY cat",
(),
)
.expect("Aggregation on view should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 category groups");
let row0 = rows[0].as_ref().unwrap();
let cat0: String = row0.get(0).unwrap();
let total0: f64 = row0.get(1).unwrap();
assert_eq!(cat0, "A");
assert_eq!(total0, 250.0);
let row1 = rows[1].as_ref().unwrap();
let cat1: String = row1.get(0).unwrap();
let total1: f64 = row1.get(1).unwrap();
assert_eq!(cat1, "B");
assert_eq!(total1, 200.0);
}
#[test]
fn test_bug_31_window_frame_rows_between() {
let db = setup_db("bug31");
db.execute("CREATE TABLE t31 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute(
"INSERT INTO t31 VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT id, val, SUM(val) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as win_sum FROM t31",
(),
)
.expect("Window frame ROWS BETWEEN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 5);
let expected_sums = [30, 60, 90, 120, 90];
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref().unwrap();
let win_sum: i64 = row.get(2).unwrap();
assert_eq!(
win_sum,
expected_sums[i],
"Window sum at row {} should be {}",
i + 1,
expected_sums[i]
);
}
}
#[test]
fn test_bug_32_group_by_ordinal() {
let db = setup_db("bug32");
db.execute(
"CREATE TABLE t32 (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t32 VALUES (1, 10, 100), (2, 10, 200), (3, 20, 150), (4, 20, 250)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT a, SUM(b) as total FROM t32 GROUP BY 1 ORDER BY 1",
(),
)
.expect("GROUP BY ordinal should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 groups (a=10 and a=20)");
let row0 = rows[0].as_ref().unwrap();
let a0: i64 = row0.get(0).unwrap();
let sum0: i64 = row0.get(1).unwrap();
assert_eq!(a0, 10);
assert_eq!(sum0, 300);
let row1 = rows[1].as_ref().unwrap();
let a1: i64 = row1.get(0).unwrap();
let sum1: i64 = row1.get(1).unwrap();
assert_eq!(a1, 20);
assert_eq!(sum1, 400); }
#[test]
fn test_bug_33_natural_join() {
let db = setup_db("bug33");
db.execute(
"CREATE TABLE t33_left (id INTEGER PRIMARY KEY, name TEXT, val INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE TABLE t33_right (id INTEGER PRIMARY KEY, name TEXT, extra TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t33_left VALUES (1, 'Alice', 100), (2, 'Bob', 200)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO t33_right VALUES (1, 'Alice', 'X'), (3, 'Charlie', 'Y')",
(),
)
.expect("Insert failed");
let result = db
.query("SELECT * FROM t33_left NATURAL JOIN t33_right", ())
.expect("NATURAL JOIN should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
1,
"Only one row should match (id=1, name='Alice')"
);
}
#[test]
fn test_bug_34_implicit_cross_join_comma_syntax() {
let db = setup_db("bug34");
db.execute("CREATE TABLE colors (id INTEGER, color TEXT)", ())
.expect("Failed to create table");
db.execute("CREATE TABLE sizes (id INTEGER, size TEXT)", ())
.expect("Failed to create table");
db.execute("INSERT INTO colors VALUES (1, 'Red'), (2, 'Blue')", ())
.expect("Insert failed");
db.execute("INSERT INTO sizes VALUES (1, 'Small'), (2, 'Large')", ())
.expect("Insert failed");
let result = db
.query(
"SELECT colors.color, sizes.size FROM colors, sizes ORDER BY colors.color, sizes.size",
(),
)
.expect("Implicit CROSS JOIN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4, "Should have 4 rows (2x2 cross product)");
let result = db
.query("SELECT colors.color, sizes.size FROM colors, sizes WHERE colors.id = sizes.id ORDER BY colors.id", ())
.expect("Implicit CROSS JOIN with WHERE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 rows where id matches");
}
#[test]
fn test_bug_35_delete_update_with_expression_in_where() {
let db = setup_db("bug35");
db.execute(
"CREATE TABLE t35 (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t35 VALUES (1, 10, 20), (2, 30, 40), (3, 50, 60)",
(),
)
.expect("Insert failed");
db.execute("DELETE FROM t35 WHERE a + b > 100", ())
.expect("DELETE with expression should work");
let result = db.query("SELECT id FROM t35 ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Row with a+b > 100 should be deleted");
db.execute("UPDATE t35 SET a = 999 WHERE a + b < 50", ())
.expect("UPDATE with expression should work");
let result = db.query("SELECT a FROM t35 WHERE id = 1", ()).unwrap();
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let a: i64 = row.get(0).unwrap();
assert_eq!(a, 999, "Row with a+b < 50 (id=1, 30<50) should be updated");
}
#[test]
fn test_bug_36_aggregate_with_expression_inside() {
let db = setup_db("bug36");
db.execute("CREATE TABLE t36 (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t36 VALUES (1, 10), (2, 20), (3, 30)", ())
.expect("Insert failed");
let result = db
.query("SELECT SUM(val * 2) as doubled_sum FROM t36", ())
.expect("SUM with expression should work");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let sum: i64 = row.get(0).unwrap();
assert_eq!(sum, 120, "SUM(val * 2) should be 120 (10*2 + 20*2 + 30*2)");
let result = db
.query("SELECT AVG(val + 10) as avg_plus_10 FROM t36", ())
.expect("AVG with expression should work");
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let avg: f64 = row.get(0).unwrap();
assert!(
(avg - 30.0).abs() < 0.01,
"AVG(val + 10) should be 30 ((20+30+40)/3)"
);
}
#[test]
fn test_bug_37_recursive_cte_with_table_join() {
let db = setup_db("bug37");
db.execute(
"CREATE TABLE tree (id INTEGER PRIMARY KEY, parent_id INTEGER, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO tree VALUES (1, NULL, 'Root'), (2, 1, 'Child1'), (3, 1, 'Child2'), (4, 2, 'GrandChild')",
(),
)
.expect("Insert failed");
let result = db
.query(
"WITH RECURSIVE h AS (
SELECT id, name FROM tree WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.name FROM tree t JOIN h ON t.parent_id = h.id
)
SELECT * FROM h ORDER BY id",
(),
)
.expect("Recursive CTE with table JOIN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4, "Should traverse entire tree (4 nodes)");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 2, 3, 4]);
}
#[test]
fn test_bug_38_ilike_operator() {
let db = setup_db("bug38");
db.execute("CREATE TABLE t38 (id INTEGER PRIMARY KEY, val TEXT)", ())
.expect("Failed to create table");
db.execute(
"INSERT INTO t38 VALUES (1, 'test'), (2, 'TEST'), (3, 'Test'), (4, 'Other')",
(),
)
.expect("Insert failed");
let result = db
.query("SELECT id FROM t38 WHERE val ILIKE 'test' ORDER BY id", ())
.expect("ILIKE should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
3,
"ILIKE 'test' should match 3 rows (case-insensitive)"
);
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 2, 3]);
let result = db
.query("SELECT id FROM t38 WHERE val ILIKE '%EST' ORDER BY id", ())
.expect("ILIKE with wildcard should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "ILIKE '%EST' should match 3 rows");
let result = db
.query(
"SELECT id FROM t38 WHERE val NOT ILIKE 'test' ORDER BY id",
(),
)
.expect("NOT ILIKE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "NOT ILIKE 'test' should match 1 row");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 4);
}
#[test]
fn test_bug_40_having_with_expression_group_by() {
let db = setup_db("bug40");
db.execute(
"CREATE TABLE t40 (id INTEGER PRIMARY KEY, name TEXT, value INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t40 VALUES (1, 'Alice', 10), (2, 'Alice', 20), (3, 'Bob', 15), (4, 'Bob', 25), (5, 'Charlie', 30)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT UPPER(name) as upper_name, SUM(value) as total FROM t40 GROUP BY UPPER(name) HAVING SUM(value) > 30 ORDER BY upper_name",
(),
)
.expect("HAVING with expression GROUP BY should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only BOB has SUM > 30 (40)");
let row = rows[0].as_ref().unwrap();
let upper_name: String = row.get(0).unwrap();
let total: i64 = row.get(1).unwrap();
assert_eq!(upper_name, "BOB", "Grouped expression should not be NULL");
assert_eq!(total, 40);
}
#[test]
fn test_bug_41_scalar_subquery_in_case() {
let db = setup_db("bug41");
db.execute(
"CREATE TABLE emp41 (id INTEGER PRIMARY KEY, name TEXT, dept TEXT, salary FLOAT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO emp41 VALUES (1, 'Alice', 'Engineering', 100000.0)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO emp41 VALUES (2, 'Bob', 'Engineering', 80000.0)",
(),
)
.expect("Insert failed");
db.execute(
"INSERT INTO emp41 VALUES (3, 'Charlie', 'Sales', 70000.0)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT name, salary,
CASE
WHEN salary > (SELECT AVG(salary) FROM emp41) THEN 'Above Average'
ELSE 'Below Average'
END as salary_level
FROM emp41 ORDER BY name",
(),
)
.expect("Scalar subquery in CASE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let row0 = rows[0].as_ref().unwrap();
let name0: String = row0.get(0).unwrap();
let level0: String = row0.get(2).unwrap();
assert_eq!(name0, "Alice");
assert_eq!(level0, "Above Average");
let row1 = rows[1].as_ref().unwrap();
let name1: String = row1.get(0).unwrap();
let level1: String = row1.get(2).unwrap();
assert_eq!(name1, "Bob");
assert_eq!(level1, "Below Average");
}
#[test]
fn test_bug_51_is_true_false() {
let db = setup_db("bug51");
db.execute(
"CREATE TABLE t51 (id INTEGER PRIMARY KEY, active BOOLEAN)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t51 VALUES (1, true), (2, false), (3, NULL)",
(),
)
.expect("Insert failed");
let result = db
.query("SELECT id FROM t51 WHERE active IS TRUE ORDER BY id", ())
.expect("IS TRUE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only id=1 has active IS TRUE");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 1);
let result = db
.query("SELECT id FROM t51 WHERE active IS FALSE ORDER BY id", ())
.expect("IS FALSE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only id=2 has active IS FALSE");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 2);
let result = db
.query(
"SELECT id FROM t51 WHERE active IS NOT TRUE ORDER BY id",
(),
)
.expect("IS NOT TRUE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "id=2 and id=3 have active IS NOT TRUE");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![2, 3]);
let result = db
.query(
"SELECT id FROM t51 WHERE active IS NOT FALSE ORDER BY id",
(),
)
.expect("IS NOT FALSE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "id=1 and id=3 have active IS NOT FALSE");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 3]);
}
#[test]
fn test_bug_51_is_true_false_storage_expressions() {
let db = setup_db("bug51b");
db.execute(
"CREATE TABLE t51b (id INTEGER PRIMARY KEY, active BOOLEAN)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t51b VALUES (1, true), (2, false), (3, NULL)",
(),
)
.expect("Insert failed");
db.execute("DELETE FROM t51b WHERE active IS TRUE", ())
.expect("DELETE with IS TRUE should work");
let result = db.query("SELECT id FROM t51b ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Row with active IS TRUE should be deleted");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![2, 3]);
db.execute("DROP TABLE t51b", ()).unwrap();
db.execute(
"CREATE TABLE t51b (id INTEGER PRIMARY KEY, active BOOLEAN)",
(),
)
.unwrap();
db.execute(
"INSERT INTO t51b VALUES (1, true), (2, false), (3, NULL)",
(),
)
.unwrap();
db.execute("UPDATE t51b SET active = true WHERE active IS FALSE", ())
.expect("UPDATE with IS FALSE should work");
let result = db
.query("SELECT id, active FROM t51b WHERE id = 2", ())
.unwrap();
let rows: Vec<_> = result.collect();
let row = rows[0].as_ref().unwrap();
let active: bool = row.get(1).unwrap();
assert!(active, "Row with IS FALSE should be updated to true");
}
#[test]
fn test_bug_52_xor_operator() {
let db = setup_db("bug52");
let result = db
.query("SELECT true XOR false", ())
.expect("XOR should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(val, "true XOR false should be true");
let result = db
.query("SELECT true XOR true", ())
.expect("XOR should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(!val, "true XOR true should be false");
let result = db
.query("SELECT false XOR false", ())
.expect("XOR should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(!val, "false XOR false should be false");
let result = db
.query("SELECT false XOR true", ())
.expect("XOR should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(val, "false XOR true should be true");
db.execute(
"CREATE TABLE t52 (id INTEGER PRIMARY KEY, a BOOLEAN, b BOOLEAN)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t52 VALUES (1, true, true), (2, true, false), (3, false, true), (4, false, false)",
(),
)
.expect("Insert failed");
let result = db
.query("SELECT id FROM t52 WHERE a XOR b ORDER BY id", ())
.expect("XOR in WHERE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "XOR should be true for rows 2 and 3");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![2, 3]);
}
#[test]
fn test_bug_52_xor_storage_expressions() {
let db = setup_db("bug52b");
db.execute(
"CREATE TABLE t52b (id INTEGER PRIMARY KEY, a BOOLEAN, b BOOLEAN)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t52b VALUES (1, true, true), (2, true, false), (3, false, true), (4, false, false)",
(),
)
.expect("Insert failed");
db.execute("DELETE FROM t52b WHERE a XOR b", ())
.expect("DELETE with XOR should work");
let result = db.query("SELECT id FROM t52b ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Rows 2 and 3 should be deleted (XOR = true)");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 4], "Only rows where both same should remain");
}
#[test]
fn test_bug_56_substr_function() {
let db = setup_db("bug56");
let result = db
.query("SELECT SUBSTR('hello world', 7)", ())
.expect("SUBSTR with 2 args should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let value: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(value, "world");
let result = db
.query("SELECT SUBSTR('hello world', 1, 5)", ())
.expect("SUBSTR with 3 args should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let value: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(value, "hello");
}
#[test]
fn test_bug_57_join_using() {
let db = setup_db("bug57");
db.execute("CREATE TABLE t57a (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Create table failed");
db.execute(
"CREATE TABLE t57b (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create table failed");
db.execute(
"INSERT INTO t57a VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')",
(),
)
.expect("Insert failed");
db.execute("INSERT INTO t57b VALUES (1, 100), (2, 200), (4, 400)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT t57a.name, t57b.value FROM t57a JOIN t57b USING (id) ORDER BY t57a.name",
(),
)
.expect("JOIN USING should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should return 2 matching rows");
let names: Vec<String> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(names, vec!["Alice", "Bob"]);
let result = db
.query(
"SELECT t57a.name, t57b.value FROM t57a LEFT JOIN t57b USING (id) ORDER BY t57a.name",
(),
)
.expect("LEFT JOIN USING should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
3,
"Should return 3 rows (with NULL for Charlie)"
);
}
#[test]
fn test_bug_58_create_table_as_select() {
let db = setup_db("bug58");
db.execute(
"CREATE TABLE t58 (id INTEGER PRIMARY KEY, name TEXT, value FLOAT)",
(),
)
.expect("Create table failed");
db.execute(
"INSERT INTO t58 VALUES (1, 'Alice', 100.0), (2, 'Bob', 200.0), (3, 'Charlie', 150.0)",
(),
)
.expect("Insert failed");
db.execute("CREATE TABLE t58_copy AS SELECT * FROM t58", ())
.expect("CREATE TABLE AS SELECT should work");
let result = db.query("SELECT * FROM t58_copy ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should have copied all 3 rows");
db.execute(
"CREATE TABLE t58_filtered AS SELECT id, name FROM t58 WHERE value > 120.0",
(),
)
.expect("CREATE TABLE AS SELECT with WHERE should work");
let result = db
.query("SELECT * FROM t58_filtered ORDER BY id", ())
.unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 filtered rows");
let names: Vec<String> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(1).unwrap())
.collect();
assert_eq!(names, vec!["Bob", "Charlie"]);
db.execute(
"CREATE TABLE t58_agg AS SELECT COUNT(*) as cnt, SUM(value) as total FROM t58",
(),
)
.expect("CREATE TABLE AS SELECT with aggregation should work");
let result = db.query("SELECT * FROM t58_agg", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let cnt: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(cnt, 3);
}
#[test]
fn test_check_constraint() {
let db = setup_db("check_constraint");
db.execute(
"CREATE TABLE t_check (id INTEGER PRIMARY KEY, value INTEGER CHECK (value > 0))",
(),
)
.expect("Create table with CHECK constraint should work");
db.execute("INSERT INTO t_check VALUES (1, 100)", ())
.expect("Insert with valid value should work");
let result = db.execute("INSERT INTO t_check VALUES (2, -50)", ());
assert!(
result.is_err(),
"Insert with value <= 0 should fail CHECK constraint"
);
let result = db.query("SELECT * FROM t_check", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only one row should be inserted");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 1);
}
#[test]
fn test_default_values() {
let db = setup_db("default_values");
db.execute(
"CREATE TABLE t_default (id INTEGER PRIMARY KEY, name TEXT DEFAULT 'unnamed', value INTEGER DEFAULT 42)",
(),
)
.expect("Create table with DEFAULT should work");
db.execute("INSERT INTO t_default (id) VALUES (1)", ())
.expect("Insert with partial columns should work");
db.execute("INSERT INTO t_default (id, name) VALUES (2, 'Bob')", ())
.expect("Insert with partial columns should work");
db.execute("INSERT INTO t_default VALUES (3, 'Alice', 100)", ())
.expect("Insert with all columns should work");
let result = db.query("SELECT * FROM t_default ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let name1: String = rows[0].as_ref().unwrap().get(1).unwrap();
let value1: i64 = rows[0].as_ref().unwrap().get(2).unwrap();
assert_eq!(name1, "unnamed");
assert_eq!(value1, 42);
let name2: String = rows[1].as_ref().unwrap().get(1).unwrap();
let value2: i64 = rows[1].as_ref().unwrap().get(2).unwrap();
assert_eq!(name2, "Bob");
assert_eq!(value2, 42);
let name3: String = rows[2].as_ref().unwrap().get(1).unwrap();
let value3: i64 = rows[2].as_ref().unwrap().get(2).unwrap();
assert_eq!(name3, "Alice");
assert_eq!(value3, 100);
}
#[test]
fn test_unique_constraint() {
let db = setup_db("unique_constraint");
db.execute(
"CREATE TABLE t_unique (id INTEGER PRIMARY KEY, email TEXT UNIQUE)",
(),
)
.expect("Create table with UNIQUE constraint should work");
db.execute("INSERT INTO t_unique VALUES (1, 'test@example.com')", ())
.expect("First insert should work");
let result = db.execute("INSERT INTO t_unique VALUES (2, 'test@example.com')", ());
assert!(
result.is_err(),
"Insert with duplicate UNIQUE value should fail"
);
db.execute("INSERT INTO t_unique VALUES (3, 'other@example.com')", ())
.expect("Insert with different value should work");
let result = db.query("SELECT * FROM t_unique ORDER BY id", ()).unwrap();
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
}
#[test]
fn test_bug_62_group_by_qualified_column() {
let db = setup_db("bug62");
db.execute(
"CREATE TABLE products (id INTEGER PRIMARY KEY, category TEXT, price FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO products VALUES (1, 'Electronics', 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO products VALUES (2, 'Electronics', 200.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO products VALUES (3, 'Books', 50.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT products.category, SUM(products.price) as total FROM products GROUP BY products.category ORDER BY products.category",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 categories");
let row1 = rows[0].as_ref().expect("Row should exist");
let category1: String = row1.get(0).unwrap();
let total1: f64 = row1.get(1).unwrap();
assert_eq!(category1, "Books");
assert_eq!(total1, 50.0);
let row2 = rows[1].as_ref().expect("Row should exist");
let category2: String = row2.get(0).unwrap();
let total2: f64 = row2.get(1).unwrap();
assert_eq!(category2, "Electronics");
assert_eq!(total2, 300.0);
}
#[test]
fn test_bug_63_scalar_subquery_with_group_by() {
let db = setup_db("bug63");
db.execute(
"CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT, country TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER, amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO customers VALUES (1, 'Alice', 'USA')", ())
.expect("Insert failed");
db.execute("INSERT INTO customers VALUES (2, 'Bob', 'UK')", ())
.expect("Insert failed");
db.execute("INSERT INTO customers VALUES (3, 'Charlie', 'USA')", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (1, 1, 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (2, 1, 200.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (3, 3, 150.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT country, COUNT(*) as cnt, (SELECT MAX(amount) FROM orders) as max_order FROM customers GROUP BY country ORDER BY country",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 countries");
let row1 = rows[0].as_ref().expect("Row should exist");
let country1: String = row1.get(0).unwrap();
let cnt1: i64 = row1.get(1).unwrap();
let max_order1: f64 = row1.get(2).unwrap();
assert_eq!(country1, "UK");
assert_eq!(cnt1, 1);
assert_eq!(
max_order1, 200.0,
"Scalar subquery should return 200.0, not NULL"
);
let row2 = rows[1].as_ref().expect("Row should exist");
let country2: String = row2.get(0).unwrap();
let cnt2: i64 = row2.get(1).unwrap();
let max_order2: f64 = row2.get(2).unwrap();
assert_eq!(country2, "USA");
assert_eq!(cnt2, 2);
assert_eq!(
max_order2, 200.0,
"Scalar subquery should return 200.0, not NULL"
);
}
#[test]
fn test_bug_64_subquery_in_having() {
let db = setup_db("bug64");
db.execute(
"CREATE TABLE sales (id INTEGER PRIMARY KEY, region TEXT, amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE TABLE thresholds (id INTEGER PRIMARY KEY, min_amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO sales VALUES (1, 'North', 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO sales VALUES (2, 'North', 200.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO sales VALUES (3, 'South', 50.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO sales VALUES (4, 'South', 75.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO thresholds VALUES (1, 150.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT region, SUM(amount) as total FROM sales GROUP BY region HAVING SUM(amount) > (SELECT min_amount FROM thresholds WHERE id = 1)",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Only North region has sum > 150");
let row = rows[0].as_ref().expect("Row should exist");
let region: String = row.get(0).unwrap();
let total: f64 = row.get(1).unwrap();
assert_eq!(region, "North");
assert_eq!(total, 300.0);
}
#[test]
fn test_bug_67_window_function_with_join() {
let db = setup_db("bug67");
db.execute(
"CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.expect("Failed to create table");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER, amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO customers VALUES (1, 'Alice')", ())
.expect("Insert failed");
db.execute("INSERT INTO customers VALUES (2, 'Bob')", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (1, 1, 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (2, 1, 200.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO orders VALUES (3, 2, 150.0)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT c.name, o.amount, ROW_NUMBER() OVER (ORDER BY o.amount DESC) as rn FROM customers c INNER JOIN orders o ON c.id = o.customer_id",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should have 3 rows");
let mut names: Vec<String> = Vec::new();
let mut amounts: Vec<f64> = Vec::new();
for row in &rows {
let row = row.as_ref().expect("Row should exist");
let name: String = row.get(0).unwrap();
let amount: f64 = row.get(1).unwrap();
names.push(name);
amounts.push(amount);
}
assert!(
names.iter().all(|n| !n.is_empty()),
"All names should be non-empty - bug #67 fix"
);
let alice_count = names.iter().filter(|n| *n == "Alice").count();
let bob_count = names.iter().filter(|n| *n == "Bob").count();
assert_eq!(alice_count, 2, "Alice should appear twice");
assert_eq!(bob_count, 1, "Bob should appear once");
amounts.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(amounts, vec![100.0, 150.0, 200.0]);
}
#[test]
fn test_bug_68_three_valued_logic() {
let db = setup_db("bug68");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (2, NULL)", ())
.expect("Insert failed");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert failed");
let result = db
.query("SELECT id FROM t WHERE (val IS NULL) AND TRUE", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 2);
let result = db
.query("SELECT id FROM t WHERE NULL OR FALSE", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 0, "NULL OR FALSE = NULL, should match no rows");
let result = db
.query("SELECT id FROM t WHERE NULL OR TRUE ORDER BY id", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "NULL OR TRUE = TRUE, should match all rows");
let result = db
.query("SELECT id FROM t WHERE NULL AND FALSE", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
0,
"NULL AND FALSE = FALSE, should match no rows"
);
let result = db
.query("SELECT id FROM t WHERE NOT NULL", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 0, "NOT NULL = NULL, should match no rows");
}
#[test]
fn test_bug_69_limit_offset_without_order_by() {
let db = setup_db("bug69");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY)", ())
.expect("Failed to create table");
for i in 1..=10 {
db.execute(&format!("INSERT INTO t VALUES ({})", i), ())
.expect("Insert failed");
}
let result = db
.query("SELECT * FROM t LIMIT 3", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "LIMIT 3 should return 3 rows");
let result = db
.query("SELECT * FROM t OFFSET 7", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "OFFSET 7 should return 3 rows (8, 9, 10)");
let result = db
.query("SELECT * FROM t LIMIT 3 OFFSET 3", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "LIMIT 3 OFFSET 3 should return 3 rows");
let result = db
.query("SELECT * FROM t ORDER BY id LIMIT 3 OFFSET 3", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
3,
"ORDER BY + LIMIT 3 OFFSET 3 should return 3 rows"
);
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![4, 5, 6]);
}
#[test]
fn test_bug_70_negative_prefix_aggregate() {
let db = setup_db("bug70");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10), (2, 20)", ())
.expect("Insert failed");
let result: i64 = db
.query_one("SELECT -SUM(val) FROM t", ())
.expect("Query should succeed");
assert_eq!(result, -30, "-SUM(val) should be -30");
let result: i64 = db
.query_one("SELECT SUM(val) * -1 FROM t", ())
.expect("Query should succeed");
assert_eq!(result, -30, "SUM(val) * -1 should be -30");
let result: i64 = db
.query_one("SELECT SUM(val) + 5 FROM t", ())
.expect("Query should succeed");
assert_eq!(result, 35, "SUM(val) + 5 should be 35");
let result: i64 = db
.query_one(
"SELECT -total FROM (SELECT SUM(val) AS total FROM t) sub",
(),
)
.expect("Query should succeed");
assert_eq!(result, -30, "-total from derived table should be -30");
let result: i64 = db
.query_one("SELECT -SUM(val) FROM (SELECT 10 as val) sub", ())
.expect("Query should succeed");
assert_eq!(result, -10, "-SUM(val) from derived should be -10");
}
#[test]
fn test_bug_71_truncate_table() {
let db = setup_db("bug71");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Failed to create table");
db.execute("INSERT INTO t VALUES (1, 10), (2, 20), (3, 30)", ())
.expect("Insert failed");
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("Query should succeed");
assert_eq!(count, 3, "Should have 3 rows before TRUNCATE");
db.execute("TRUNCATE TABLE t", ())
.expect("TRUNCATE should succeed");
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("Query should succeed");
assert_eq!(count, 0, "Should have 0 rows after TRUNCATE");
db.execute("INSERT INTO t VALUES (1, 100)", ())
.expect("Should be able to insert after TRUNCATE");
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("Query should succeed");
assert_eq!(count, 1, "Should have 1 row after new INSERT");
}
#[test]
fn test_bug_72_aggregate_window_group_by() {
let db = setup_db("bug72");
db.execute(
"CREATE TABLE orders (id INTEGER PRIMARY KEY, category TEXT, amount FLOAT)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO orders VALUES (1, 'A', 100.0), (2, 'A', 150.0), (3, 'B', 200.0), (4, 'B', 50.0)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT category, SUM(amount) AS total, RANK() OVER (ORDER BY SUM(amount) DESC) AS rnk FROM orders GROUP BY category",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have 2 rows (A and B)");
let mut data: Vec<(String, f64, i64)> = rows
.iter()
.map(|r| {
let r = r.as_ref().unwrap();
(
r.get::<String>(0).unwrap(),
r.get::<f64>(1).unwrap(),
r.get::<i64>(2).unwrap(),
)
})
.collect();
data.sort_by(|a, b| a.0.cmp(&b.0));
assert_eq!(data[0].0, "A");
assert_eq!(data[0].1, 250.0);
assert_eq!(data[0].2, 1);
assert_eq!(data[1].0, "B");
assert_eq!(data[1].1, 250.0);
assert_eq!(data[1].2, 1);
}
#[test]
fn test_bug_73_distinct_order_by_non_select_column() {
let db = setup_db("bug73");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, a TEXT, b INTEGER)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO t VALUES (1, 'X', 1), (2, 'Y', 2), (3, 'X', 3)",
(),
)
.expect("Insert failed");
let result = db
.query("SELECT DISTINCT a FROM t ORDER BY b", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"DISTINCT should return only 2 unique values (X, Y)"
);
let values: Vec<String> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(values, vec!["X", "Y"]);
let result = db
.query("SELECT DISTINCT a FROM t", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"DISTINCT without ORDER BY should also return 2 rows"
);
let result = db
.query("SELECT DISTINCT a FROM t ORDER BY a DESC", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
let values: Vec<String> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(values, vec!["Y", "X"]);
}
#[test]
fn test_bug_74_json_extract_function() {
let db = setup_db("bug74");
db.execute("CREATE TABLE j (id INTEGER PRIMARY KEY, data JSON)", ())
.expect("Failed to create table");
db.execute(
"INSERT INTO j VALUES (1, '{\"name\": \"Alice\", \"age\": 30}')",
(),
)
.expect("Failed to insert data");
let result = db
.query("SELECT JSON_EXTRACT(data, '$.name') FROM j", ())
.expect("JSON_EXTRACT should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(name, "Alice");
let result = db
.query("SELECT JSON_EXTRACT(data, '$.age') FROM j", ())
.expect("JSON_EXTRACT should work for numbers");
let rows: Vec<_> = result.collect();
let age: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(age, 30);
}
#[test]
fn test_bug_75_typeof_function() {
let db = setup_db("bug75");
let result = db
.query("SELECT TYPEOF(123)", ())
.expect("TYPEOF should work with integers");
let rows: Vec<_> = result.collect();
let type_name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(type_name, "INTEGER");
let result = db
.query("SELECT TYPEOF('hello')", ())
.expect("TYPEOF should work with text");
let rows: Vec<_> = result.collect();
let type_name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(type_name, "TEXT");
let result = db
.query("SELECT TYPEOF(3.14)", ())
.expect("TYPEOF should work with floats");
let rows: Vec<_> = result.collect();
let type_name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(type_name, "FLOAT");
let result = db
.query("SELECT TYPEOF(TRUE)", ())
.expect("TYPEOF should work with booleans");
let rows: Vec<_> = result.collect();
let type_name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(type_name, "BOOLEAN");
let result = db
.query("SELECT TYPEOF(NULL)", ())
.expect("TYPEOF should work with NULL");
let rows: Vec<_> = result.collect();
let type_name: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(type_name, "NULL");
}
#[test]
fn test_bug_76_cast_to_date() {
let db = setup_db("bug76");
let result = db
.query("SELECT CAST('2024-01-15' AS DATE)", ())
.expect("CAST to DATE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let date_str: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(
date_str.contains("2024-01-15"),
"Date should contain 2024-01-15"
);
let result = db
.query("SELECT CAST('2024-06-15 12:30:45' AS TIMESTAMP)", ())
.expect("CAST to TIMESTAMP should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
}
#[test]
fn test_bug_77_date_diff_alias() {
let db = setup_db("bug77");
let result = db
.query("SELECT DATEDIFF('2024-03-20', '2024-03-15')", ())
.expect("DATEDIFF should work");
let rows: Vec<_> = result.collect();
let diff: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(diff, 5);
let result = db
.query("SELECT DATE_DIFF('2024-03-20', '2024-03-15')", ())
.expect("DATE_DIFF should work as alias");
let rows: Vec<_> = result.collect();
let diff: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(diff, 5);
}
#[test]
fn test_bug_78_integer_overflow_handling() {
let db = setup_db("bug78");
let result = db.query("SELECT 9223372036854775807 + 1", ());
assert!(
result.is_err(),
"Integer overflow should return an error, not wrap"
);
let result = db.query("SELECT 9223372036854775807 * 2", ());
assert!(
result.is_err(),
"Integer overflow on multiplication should return an error"
);
let result = db.query("SELECT -9223372036854775808 - 1", ());
assert!(result.is_err(), "Integer underflow should return an error");
let result = db
.query("SELECT 100 + 200", ())
.expect("Normal arithmetic should work");
let rows: Vec<_> = result.collect();
let sum: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(sum, 300);
}
#[test]
fn test_bug_92_boolean_short_circuit() {
let db = setup_db("bug92");
let result = db
.query("SELECT false AND (1/0 > 0)", ())
.expect("FALSE AND (error) should short-circuit to FALSE");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(!val, "FALSE AND anything = FALSE");
let result = db
.query("SELECT true OR (1/0 > 0)", ())
.expect("TRUE OR (error) should short-circuit to TRUE");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(val, "TRUE OR anything = TRUE");
let result = db
.query("SELECT true AND false", ())
.expect("Normal AND should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(!val, "TRUE AND FALSE = FALSE");
let result = db
.query("SELECT false OR true", ())
.expect("Normal OR should work");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(val, "FALSE OR TRUE = TRUE");
let result = db
.query("SELECT false AND false AND (1/0 > 0)", ())
.expect("Chained FALSE AND should short-circuit");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(!val, "FALSE AND FALSE AND anything = FALSE");
let result = db
.query("SELECT true OR true OR (1/0 > 0)", ())
.expect("Chained TRUE OR should short-circuit");
let rows: Vec<_> = result.collect();
let val: bool = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(val, "TRUE OR TRUE OR anything = TRUE");
}
#[test]
fn test_bug_93_describe_table() {
let db = setup_db("bug93");
db.execute(
"CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price FLOAT)",
(),
)
.expect("Failed to create table");
let result = db
.query("DESCRIBE products", ())
.expect("DESCRIBE should work");
let columns = result.columns();
assert_eq!(columns.len(), 6, "DESCRIBE should return 6 columns");
assert_eq!(columns[0], "Field");
assert_eq!(columns[1], "Type");
assert_eq!(columns[2], "Null");
assert_eq!(columns[3], "Key");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should return 3 rows for 3 columns");
let row = rows[0].as_ref().unwrap();
let field: String = row.get(0).unwrap();
let key: String = row.get(3).unwrap();
assert_eq!(field, "id");
assert_eq!(key, "PRI");
let result = db
.query("DESC products", ())
.expect("DESC shorthand should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
}
#[test]
fn test_bug_96_natural_join_column_deduplication() {
let db = setup_db("bug96");
db.execute("CREATE TABLE t1 (id INTEGER, val TEXT)", ())
.expect("Create t1");
db.execute("CREATE TABLE t2 (id INTEGER, data TEXT)", ())
.expect("Create t2");
db.execute("INSERT INTO t1 VALUES (1, 'A'), (2, 'B')", ())
.expect("Insert t1");
db.execute("INSERT INTO t2 VALUES (1, 'X'), (2, 'Y')", ())
.expect("Insert t2");
let result = db
.query("SELECT * FROM t1 NATURAL JOIN t2", ())
.expect("NATURAL JOIN should work");
let columns = result.columns();
assert_eq!(
columns.len(),
3,
"NATURAL JOIN should deduplicate common columns, got: {:?}",
columns
);
assert_eq!(columns[0], "id", "Join column should be unqualified 'id'");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should return 2 matched rows");
}
#[test]
fn test_bug_97_join_using_column_deduplication() {
let db = setup_db("bug97");
db.execute("CREATE TABLE t1 (id INTEGER, val TEXT)", ())
.expect("Create t1");
db.execute("CREATE TABLE t2 (id INTEGER, data TEXT)", ())
.expect("Create t2");
db.execute("INSERT INTO t1 VALUES (1, 'A'), (2, 'B')", ())
.expect("Insert t1");
db.execute("INSERT INTO t2 VALUES (1, 'X'), (2, 'Y')", ())
.expect("Insert t2");
let result = db
.query("SELECT * FROM t1 JOIN t2 USING (id)", ())
.expect("JOIN USING should work");
let columns = result.columns();
assert_eq!(
columns.len(),
3,
"JOIN USING should deduplicate the USING column, got: {:?}",
columns
);
assert_eq!(columns[0], "id", "USING column should be unqualified 'id'");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should return 2 matched rows");
let row = rows[0].as_ref().unwrap();
let id: i64 = row.get(0).unwrap();
let val: String = row.get(1).unwrap();
let data: String = row.get(2).unwrap();
assert_eq!(id, 1);
assert_eq!(val, "A");
assert_eq!(data, "X");
}
#[test]
fn test_bug_98_qualified_star_in_join() {
let db = setup_db("bug98");
db.execute("CREATE TABLE t1 (id INTEGER, grp TEXT, val INTEGER)", ())
.expect("Create t1");
db.execute("CREATE TABLE t2 (id INTEGER, grp TEXT, data TEXT)", ())
.expect("Create t2");
db.execute("INSERT INTO t1 VALUES (1, 'A', 10), (2, 'B', 20)", ())
.expect("Insert t1");
db.execute("INSERT INTO t2 VALUES (1, 'A', 'x')", ())
.expect("Insert t2");
let result = db
.query(
"SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.id = t2.id AND t1.grp = t2.grp WHERE t2.id IS NULL",
(),
)
.expect("Anti-join should work");
let columns = result.columns();
assert_eq!(
columns.len(),
3,
"SELECT t1.* should only return t1's columns, got: {:?}",
columns
);
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
1,
"Only row (2, 'B', 20) should match anti-join"
);
let row = rows[0].as_ref().unwrap();
let id: i64 = row.get(0).unwrap();
let grp: String = row.get(1).unwrap();
let val: i64 = row.get(2).unwrap();
assert_eq!(id, 2);
assert_eq!(grp, "B");
assert_eq!(val, 20);
}
#[test]
fn test_bug_47_glob_operator() {
let db = setup_db("bug47_glob");
db.execute("CREATE TABLE t47 (id INTEGER PRIMARY KEY, data TEXT)", ())
.expect("Create table");
db.execute(
"INSERT INTO t47 VALUES (1, 'hello world'), (2, 'hello there'), (3, 'goodbye'), (4, 'test123'), (5, NULL)",
(),
)
.expect("Insert");
let result = db
.query(
"SELECT id FROM t47 WHERE data GLOB 'hello*' ORDER BY id",
(),
)
.expect("GLOB should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "GLOB 'hello*' should match 2 rows");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 2]);
let result = db
.query(
"SELECT id FROM t47 WHERE data GLOB 'goodby?' ORDER BY id",
(),
)
.expect("GLOB should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "GLOB 'goodby?' should match 1 row");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 3);
let result = db
.query("SELECT id FROM t47 WHERE data GLOB '*123' ORDER BY id", ())
.expect("GLOB should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "GLOB '*123' should match 1 row");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 4);
let result = db
.query(
"SELECT id FROM t47 WHERE data NOT GLOB 'hello*' ORDER BY id",
(),
)
.expect("NOT GLOB should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"NOT GLOB 'hello*' should match goodbye and test123"
);
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![3, 4]);
}
#[test]
fn test_bug_47_regexp_operator() {
let db = setup_db("bug47_regexp");
db.execute("CREATE TABLE t47r (id INTEGER PRIMARY KEY, data TEXT)", ())
.expect("Create table");
db.execute(
"INSERT INTO t47r VALUES (1, 'hello world'), (2, 'hello there'), (3, 'goodbye'), (4, 'test123'), (5, NULL)",
(),
)
.expect("Insert");
let result = db
.query(
"SELECT id FROM t47r WHERE data REGEXP '^hello' ORDER BY id",
(),
)
.expect("REGEXP should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "REGEXP '^hello' should match 2 rows");
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 2]);
let result = db
.query(
"SELECT id FROM t47r WHERE data REGEXP 'world$' ORDER BY id",
(),
)
.expect("REGEXP should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "REGEXP 'world$' should match 1 row");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 1);
let result = db
.query(
"SELECT id FROM t47r WHERE data REGEXP '[0-9]+' ORDER BY id",
(),
)
.expect("REGEXP should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "REGEXP '[0-9]+' should match test123");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 4);
let result = db
.query(
"SELECT id FROM t47r WHERE data NOT REGEXP '^hello' ORDER BY id",
(),
)
.expect("NOT REGEXP should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
2,
"NOT REGEXP '^hello' should match goodbye and test123"
);
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![3, 4]);
let result = db
.query(
"SELECT id FROM t47r WHERE data RLIKE 'good' ORDER BY id",
(),
)
.expect("RLIKE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "RLIKE 'good' should match goodbye");
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 3);
}
#[test]
fn test_bug_66_aggregate_in_where_error() {
let db = setup_db("bug66");
db.execute("CREATE TABLE t66 (id INTEGER PRIMARY KEY, a INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t66 VALUES (1, 10), (2, 20)", ())
.expect("Insert");
let result = db.query("SELECT * FROM t66 WHERE SUM(a) > 10", ());
match result {
Ok(_) => panic!("Aggregate in WHERE should error"),
Err(e) => {
let err = e.to_string();
assert!(
err.contains("aggregate") && err.contains("WHERE"),
"Error should mention aggregate and WHERE: {}",
err
);
}
}
let result = db.query("SELECT * FROM t66 WHERE COUNT(*) > 1", ());
assert!(result.is_err(), "COUNT in WHERE should error");
let result = db.query("SELECT * FROM t66 WHERE AVG(a) > 10", ());
assert!(result.is_err(), "AVG in WHERE should error");
let result = db.query("SELECT a FROM t66 GROUP BY a HAVING SUM(a) > 5", ());
assert!(result.is_ok(), "Aggregate in HAVING should work");
}
#[test]
fn test_bug_104_union_column_count_validation() {
let db = setup_db("bug104");
db.execute("CREATE TABLE t104a (a INTEGER, b INTEGER, c INTEGER)", ())
.expect("Create table");
db.execute("CREATE TABLE t104b (x INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t104a VALUES (1, 2, 3)", ())
.expect("Insert");
db.execute("INSERT INTO t104b VALUES (100)", ())
.expect("Insert");
let result = db.query(
"SELECT a, b, c FROM t104a UNION ALL SELECT x FROM t104b",
(),
);
match result {
Ok(_) => panic!("UNION with mismatched columns should error"),
Err(e) => {
let err = e.to_string();
assert!(
err.contains("UNION") && err.contains("column"),
"Error should mention UNION and columns: {}",
err
);
}
}
let result = db.query("SELECT a, b FROM t104a INTERSECT SELECT x FROM t104b", ());
assert!(
result.is_err(),
"INTERSECT with mismatched columns should error"
);
let result = db.query("SELECT a FROM t104a EXCEPT SELECT x, x FROM t104b", ());
assert!(
result.is_err(),
"EXCEPT with mismatched columns should error"
);
let result = db.query("SELECT a FROM t104a UNION ALL SELECT x FROM t104b", ());
assert!(
result.is_ok(),
"UNION with matching column counts should work"
);
let rows: Vec<_> = result.unwrap().collect();
assert_eq!(rows.len(), 2, "Should have 2 rows from UNION");
}
#[test]
fn test_bug_105_window_frame_shorthand() {
let db = setup_db("bug105");
db.execute(
"CREATE TABLE t105 (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.expect("Create table");
db.execute(
"INSERT INTO t105 VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50)",
(),
)
.expect("Insert");
let result = db
.query(
"SELECT id, val, SUM(val) OVER (ORDER BY id ROWS UNBOUNDED PRECEDING) as running FROM t105",
(),
)
.expect("Window frame shorthand should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 5);
let expected_running = [10i64, 30, 60, 100, 150];
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref().unwrap();
let running: i64 = row.get(2).unwrap();
assert_eq!(
running,
expected_running[i],
"Row {} running sum should be {}",
i + 1,
expected_running[i]
);
}
let result = db
.query(
"SELECT id, SUM(val) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as running FROM t105",
(),
)
.expect("Full BETWEEN syntax should work");
let rows: Vec<_> = result.collect();
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref().unwrap();
let running: i64 = row.get(1).unwrap();
assert_eq!(
running,
expected_running[i],
"BETWEEN syntax row {} should match shorthand",
i + 1
);
}
}
#[test]
fn test_bug_106_aggregate_arithmetic_with_expressions() {
let db = setup_db("bug106");
db.execute("CREATE TABLE t106 (a INTEGER, b INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t106 VALUES (10, 5), (20, 10), (30, 15)", ())
.expect("Insert");
let result = db
.query("SELECT SUM(a) / SUM(a + b) FROM t106", ())
.expect("Aggregate arithmetic should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let val: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(val, 0, "60 / 90 should be 0 (integer division)");
let result = db
.query("SELECT SUM(a) * 1.0 / SUM(a + b) FROM t106", ())
.expect("Float division should work");
let rows: Vec<_> = result.collect();
let val: f64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert!(
(val - 0.666666).abs() < 0.001,
"60.0 / 90 should be ~0.666, got {}",
val
);
let result = db
.query("SELECT SUM(a + b) - SUM(a) FROM t106", ())
.expect("Aggregate subtraction should work");
let rows: Vec<_> = result.collect();
let val: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(val, 30, "90 - 60 should be 30");
let result = db
.query("SELECT SUM(a) * SUM(b) / 100 FROM t106", ())
.expect("Aggregate multiplication should work");
let rows: Vec<_> = result.collect();
let val: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(val, 18, "60 * 30 / 100 should be 18");
}
#[test]
fn test_bug_107_case_null_matching() {
let db = setup_db("bug107");
db.execute(
"CREATE TABLE t107 (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.expect("Create table");
db.execute("INSERT INTO t107 VALUES (1, 10), (2, NULL), (3, 20)", ())
.expect("Insert");
let result = db
.query(
"SELECT id, CASE val WHEN NULL THEN 'matched' ELSE 'no' END as result FROM t107 ORDER BY id",
(),
)
.expect("CASE should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
for row in &rows {
let row = row.as_ref().unwrap();
let result: String = row.get(1).unwrap();
assert_eq!(result, "no", "CASE val WHEN NULL should never match");
}
let result = db
.query(
"SELECT id, CASE WHEN val IS NULL THEN 'null' ELSE 'not null' END as result FROM t107 ORDER BY id",
(),
)
.expect("Searched CASE should work");
let rows: Vec<_> = result.collect();
let row1: String = rows[0].as_ref().unwrap().get(1).unwrap();
let row2: String = rows[1].as_ref().unwrap().get(1).unwrap();
let row3: String = rows[2].as_ref().unwrap().get(1).unwrap();
assert_eq!(row1, "not null", "id=1 should be not null");
assert_eq!(row2, "null", "id=2 should be null");
assert_eq!(row3, "not null", "id=3 should be not null");
let result = db
.query(
"SELECT id, CASE val WHEN 10 THEN 'ten' WHEN 20 THEN 'twenty' ELSE 'other' END as result FROM t107 ORDER BY id",
(),
)
.expect("CASE with values should work");
let rows: Vec<_> = result.collect();
let row1: String = rows[0].as_ref().unwrap().get(1).unwrap();
let row2: String = rows[1].as_ref().unwrap().get(1).unwrap();
let row3: String = rows[2].as_ref().unwrap().get(1).unwrap();
assert_eq!(row1, "ten", "id=1 (val=10) should be 'ten'");
assert_eq!(row2, "other", "id=2 (val=NULL) should be 'other'");
assert_eq!(row3, "twenty", "id=3 (val=20) should be 'twenty'");
}
#[test]
fn test_bug_108_cast_timestamp_to_date() {
let db = setup_db("bug108");
db.execute(
"CREATE TABLE t108 (id INTEGER PRIMARY KEY, ts TIMESTAMP, val INTEGER)",
(),
)
.expect("Create table");
db.execute("INSERT INTO t108 VALUES (1, '2024-01-15 10:00:00', 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t108 VALUES (2, '2024-01-15 14:30:00', 20)", ())
.expect("Insert 2");
db.execute("INSERT INTO t108 VALUES (3, '2024-01-16 08:00:00', 30)", ())
.expect("Insert 3");
let result = db
.query(
"SELECT CAST(ts AS DATE) as day, SUM(val) as total FROM t108 GROUP BY CAST(ts AS DATE) ORDER BY day",
(),
)
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should group same-day timestamps together");
let total1: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
assert_eq!(total1, 30, "Jan 15 total should be 30");
let total2: i64 = rows[1].as_ref().unwrap().get(1).unwrap();
assert_eq!(total2, 30, "Jan 16 total should be 30");
}
#[test]
fn test_bug_109_count_distinct_over() {
let db = setup_db("bug109");
db.execute("CREATE TABLE t109 (id INTEGER PRIMARY KEY, a INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t109 VALUES (1, 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t109 VALUES (2, 10)", ())
.expect("Insert 2");
db.execute("INSERT INTO t109 VALUES (3, 20)", ())
.expect("Insert 3");
db.execute("INSERT INTO t109 VALUES (4, 20)", ())
.expect("Insert 4");
let result = db
.query(
"SELECT id, a, COUNT(DISTINCT a) OVER () as dist_count FROM t109 ORDER BY id",
(),
)
.expect("COUNT DISTINCT OVER should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 4);
for row in &rows {
let count: i64 = row.as_ref().unwrap().get(2).unwrap();
assert_eq!(count, 2, "COUNT(DISTINCT a) should be 2");
}
}
#[test]
fn test_bug_110_negative_limit() {
let db = setup_db("bug110");
db.execute("CREATE TABLE t110 (id INTEGER PRIMARY KEY)", ())
.expect("Create table");
db.execute("INSERT INTO t110 VALUES (1), (2), (3)", ())
.expect("Insert");
let result = db.query("SELECT * FROM t110 LIMIT -1", ());
match result {
Ok(_) => panic!("Negative LIMIT should return an error"),
Err(e) => {
let err_msg = e.to_string();
assert!(
err_msg.contains("non-negative") || err_msg.contains("LIMIT"),
"Error should mention LIMIT must be non-negative: {}",
err_msg
);
}
}
}
#[test]
fn test_bug_111_negative_offset() {
let db = setup_db("bug111");
db.execute("CREATE TABLE t111 (id INTEGER PRIMARY KEY)", ())
.expect("Create table");
db.execute("INSERT INTO t111 VALUES (1), (2), (3)", ())
.expect("Insert");
let result = db.query("SELECT * FROM t111 LIMIT 2 OFFSET -1", ());
match result {
Ok(_) => panic!("Negative OFFSET should return an error"),
Err(e) => {
let err_msg = e.to_string();
assert!(
err_msg.contains("non-negative") || err_msg.contains("OFFSET"),
"Error should mention OFFSET must be non-negative: {}",
err_msg
);
}
}
}
#[test]
fn test_bug_112_text_primary_key() {
let db = setup_db("bug112");
let result = db.execute("CREATE TABLE t112 (id TEXT PRIMARY KEY, val INTEGER)", ());
assert!(
result.is_err(),
"TEXT PRIMARY KEY should fail at CREATE TABLE time"
);
let err_msg = result.unwrap_err().to_string();
assert!(
err_msg.contains("INTEGER") || err_msg.contains("PRIMARY KEY"),
"Error should mention PRIMARY KEY must be INTEGER: {}",
err_msg
);
}
#[test]
fn test_bug_113_not_between_with_null() {
let db = setup_db("bug113");
db.execute(
"CREATE TABLE t113 (id INTEGER PRIMARY KEY, val INTEGER)",
(),
)
.expect("Create table");
db.execute("INSERT INTO t113 VALUES (1, 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t113 VALUES (2, NULL)", ())
.expect("Insert 2");
db.execute("INSERT INTO t113 VALUES (3, 30)", ())
.expect("Insert 3");
let result = db
.query(
"SELECT id, val FROM t113 WHERE val NOT BETWEEN 10 AND 20 ORDER BY id",
(),
)
.expect("NOT BETWEEN should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
1,
"Only non-NULL values outside range should match"
);
let id: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(id, 3, "Only id=3 (val=30) should be returned");
let result = db
.query(
"SELECT id FROM t113 WHERE val BETWEEN 5 AND 35 ORDER BY id",
(),
)
.expect("BETWEEN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "BETWEEN should exclude NULL values");
}
#[test]
fn test_bugs2_01_order_by_with_rollup() {
let db = setup_db("bugs2_01");
db.execute(
"CREATE TABLE sales (id INTEGER PRIMARY KEY, region TEXT, product TEXT, amount FLOAT)",
(),
)
.expect("Create table");
db.execute("INSERT INTO sales VALUES (1, 'North', 'A', 100)", ())
.expect("Insert 1");
db.execute("INSERT INTO sales VALUES (2, 'South', 'B', 200)", ())
.expect("Insert 2");
db.execute("INSERT INTO sales VALUES (3, 'North', 'B', 150)", ())
.expect("Insert 3");
let result = db
.query(
"SELECT region, SUM(amount) as total FROM sales GROUP BY ROLLUP(region) ORDER BY region",
(),
)
.expect("ROLLUP with ORDER BY should work");
let rows: Vec<_> = result.collect();
assert_eq!(
rows.len(),
3,
"Should have 3 rows (2 regions + grand total)"
);
let result = db
.query(
"SELECT region, product, SUM(amount) as total FROM sales GROUP BY CUBE(region, product) ORDER BY region, product",
(),
)
.expect("CUBE with ORDER BY should work");
let rows: Vec<_> = result.collect();
assert!(!rows.is_empty(), "CUBE with ORDER BY should return results");
}
#[test]
fn test_bugs2_02_correlated_subquery_in_update() {
let db = setup_db("bugs2_02");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert 2");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert 3");
db.execute(
"UPDATE t SET val = (SELECT MAX(val) FROM t t2 WHERE t2.id != t.id)",
(),
)
.expect("Correlated UPDATE should work");
let result = db
.query("SELECT id, val FROM t ORDER BY id", ())
.expect("Select after update");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let val1: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
assert_eq!(val1, 30, "id=1 should have val=30 (max of 20, 30)");
let val2: i64 = rows[1].as_ref().unwrap().get(1).unwrap();
assert_eq!(val2, 30, "id=2 should have val=30 (max of 10, 30)");
let val3: i64 = rows[2].as_ref().unwrap().get(1).unwrap();
assert_eq!(val3, 20, "id=3 should have val=20 (max of 10, 20)");
}
#[test]
fn test_bugs2_03_case_when_with_window_function() {
let db = setup_db("bugs2_03");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert 2");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert 3");
let result = db
.query(
"SELECT id, val, CASE WHEN val > AVG(val) OVER () THEN 'above' ELSE 'below' END as position FROM t ORDER BY id",
(),
)
.expect("CASE with window function should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let pos1: String = rows[0].as_ref().unwrap().get(2).unwrap();
assert_eq!(pos1, "below", "id=1 (val=10) should be 'below' (10 < 20)");
let pos2: String = rows[1].as_ref().unwrap().get(2).unwrap();
assert_eq!(
pos2, "below",
"id=2 (val=20) should be 'below' (20 = 20, not >)"
);
let pos3: String = rows[2].as_ref().unwrap().get(2).unwrap();
assert_eq!(pos3, "above", "id=3 (val=30) should be 'above' (30 > 20)");
}
#[test]
fn test_bugs2_04_array_agg() {
let db = setup_db("bugs2_04");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, grp TEXT, val INTEGER)",
(),
)
.expect("Create table");
db.execute("INSERT INTO t VALUES (1, 'A', 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t VALUES (2, 'A', 20)", ())
.expect("Insert 2");
db.execute("INSERT INTO t VALUES (3, 'B', 30)", ())
.expect("Insert 3");
let result = db
.query(
"SELECT grp, ARRAY_AGG(val) as vals FROM t GROUP BY grp ORDER BY grp",
(),
)
.expect("ARRAY_AGG should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
let vals_a: String = rows[0].as_ref().unwrap().get(1).unwrap();
assert!(
vals_a.contains("10") && vals_a.contains("20"),
"Group A should contain 10 and 20, got: {}",
vals_a
);
let vals_b: String = rows[1].as_ref().unwrap().get(1).unwrap();
assert!(
vals_b.contains("30"),
"Group B should contain 30, got: {}",
vals_b
);
}
#[test]
fn test_bugs2_05_range_frame_specification() {
let db = setup_db("bugs2_05");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create table");
db.execute("INSERT INTO t VALUES (1, 10)", ())
.expect("Insert 1");
db.execute("INSERT INTO t VALUES (2, 20)", ())
.expect("Insert 2");
db.execute("INSERT INTO t VALUES (3, 30)", ())
.expect("Insert 3");
db.execute("INSERT INTO t VALUES (4, 40)", ())
.expect("Insert 4");
db.execute("INSERT INTO t VALUES (5, 50)", ())
.expect("Insert 5");
let result = db
.query(
"SELECT id, val, SUM(val) OVER (ORDER BY val RANGE BETWEEN 15 PRECEDING AND 15 FOLLOWING) as range_sum FROM t ORDER BY id",
(),
)
.expect("RANGE frame should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 5);
let sum1: i64 = rows[0].as_ref().unwrap().get(2).unwrap();
assert_eq!(sum1, 30, "id=1: range [-5, 25] should sum to 30 (10+20)");
let sum2: i64 = rows[1].as_ref().unwrap().get(2).unwrap();
assert_eq!(sum2, 60, "id=2: range [5, 35] should sum to 60 (10+20+30)");
let sum3: i64 = rows[2].as_ref().unwrap().get(2).unwrap();
assert_eq!(sum3, 90, "id=3: range [15, 45] should sum to 90 (20+30+40)");
let sum4: i64 = rows[3].as_ref().unwrap().get(2).unwrap();
assert_eq!(
sum4, 120,
"id=4: range [25, 55] should sum to 120 (30+40+50)"
);
let sum5: i64 = rows[4].as_ref().unwrap().get(2).unwrap();
assert_eq!(sum5, 90, "id=5: range [35, 65] should sum to 90 (40+50)");
}
#[test]
fn test_bugs2_06_cte_with_column_list() {
let db = setup_db("bugs2_06");
let result = db
.query(
"WITH cte(col1, col2) AS (SELECT 1, 2) SELECT * FROM cte",
(),
)
.expect("CTE with column list should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1);
let col1: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
let col2: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
assert_eq!(col1, 1);
assert_eq!(col2, 2);
let result = db
.query(
"WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cnt WHERE x < 5) SELECT * FROM cnt",
(),
)
.expect("Recursive CTE with column list should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 5, "Recursive CTE should generate 5 rows");
for (i, row) in rows.iter().enumerate() {
let x: i64 = row.as_ref().unwrap().get(0).unwrap();
assert_eq!(x, (i + 1) as i64, "Row {} should have x={}", i, i + 1);
}
}
#[test]
fn test_bugs2_07_window_expression_argument() {
let db = setup_db("bugs2_07");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create failed");
db.execute("INSERT INTO t VALUES (1, 10), (2, 20), (3, 30)", ())
.expect("Insert failed");
let result = db
.query(
"SELECT id, SUM(val * 2) OVER (ORDER BY id) as running FROM t ORDER BY id",
(),
)
.expect("Window with expression should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let running1: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
let running2: i64 = rows[1].as_ref().unwrap().get(1).unwrap();
let running3: i64 = rows[2].as_ref().unwrap().get(1).unwrap();
assert_eq!(running1, 20, "First running sum of val*2 should be 20");
assert_eq!(running2, 60, "Second running sum of val*2 should be 60");
assert_eq!(running3, 120, "Third running sum of val*2 should be 120");
let result = db
.query("SELECT SUM(val + 100) OVER () as total FROM t LIMIT 1", ())
.expect("Window with addition expression should work");
let rows: Vec<_> = result.collect();
let total: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(total, 360, "SUM(val + 100) should be 360 (110+120+130)");
}
#[test]
fn test_bugs2_08_window_partition_after_join() {
let db = setup_db("bugs2_08");
db.execute(
"CREATE TABLE left_t (id INTEGER PRIMARY KEY, grp TEXT, val INTEGER)",
(),
)
.expect("Create left failed");
db.execute(
"CREATE TABLE right_t (id INTEGER PRIMARY KEY, left_id INTEGER)",
(),
)
.expect("Create right failed");
db.execute(
"INSERT INTO left_t VALUES (1, 'A', 10), (2, 'A', 20), (3, 'B', 30)",
(),
)
.expect("Insert left failed");
db.execute("INSERT INTO right_t VALUES (1, 1), (2, 2), (3, 3)", ())
.expect("Insert right failed");
let result = db
.query(
"SELECT l.id, l.grp, l.val, SUM(l.val) OVER (PARTITION BY l.grp) as sum_grp \
FROM left_t l JOIN right_t r ON l.id = r.left_id ORDER BY l.id",
(),
)
.expect("Window PARTITION BY after JOIN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let sum1: i64 = rows[0].as_ref().unwrap().get(3).unwrap();
let sum2: i64 = rows[1].as_ref().unwrap().get(3).unwrap();
let sum3: i64 = rows[2].as_ref().unwrap().get(3).unwrap();
assert_eq!(sum1, 30, "Group A sum should be 30");
assert_eq!(sum2, 30, "Group A sum should be 30");
assert_eq!(sum3, 30, "Group B sum should be 30");
}
#[test]
fn test_bugs2_09_nested_aggregate_window() {
let db = setup_db("bugs2_09");
db.execute(
"CREATE TABLE t (id INTEGER PRIMARY KEY, grp TEXT, val INTEGER)",
(),
)
.expect("Create failed");
db.execute(
"INSERT INTO t VALUES (1, 'X', 100), (2, 'X', 200), (3, 'Y', 300), (4, 'Y', 400)",
(),
)
.expect("Insert failed");
let result = db
.query(
"SELECT grp, SUM(val) as grp_sum, SUM(SUM(val)) OVER () as total \
FROM t GROUP BY grp ORDER BY grp",
(),
)
.expect("Nested aggregate in window should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2);
let grp_sum_x: i64 = rows[0].as_ref().unwrap().get(1).unwrap();
let total_x: i64 = rows[0].as_ref().unwrap().get(2).unwrap();
let grp_sum_y: i64 = rows[1].as_ref().unwrap().get(1).unwrap();
let total_y: i64 = rows[1].as_ref().unwrap().get(2).unwrap();
assert_eq!(grp_sum_x, 300, "X group sum should be 300");
assert_eq!(grp_sum_y, 700, "Y group sum should be 700");
assert_eq!(total_x, 1000, "Total of group sums should be 1000");
assert_eq!(total_y, 1000, "Total of group sums should be 1000");
let result = db
.query(
"SELECT grp, SUM(val) as grp_sum, MAX(SUM(val)) OVER () as max_of_sums \
FROM t GROUP BY grp ORDER BY grp LIMIT 1",
(),
)
.expect("MAX of SUM in window should work");
let rows: Vec<_> = result.collect();
let max: i64 = rows[0].as_ref().unwrap().get(2).unwrap();
assert_eq!(max, 700, "MAX of sums should be 700");
}
#[test]
fn test_bugs2_10_table_level_unique_constraint() {
let db = setup_db("bugs2_10");
db.execute(
"CREATE TABLE t1 (id INTEGER PRIMARY KEY, code TEXT, name TEXT, UNIQUE(code))",
(),
)
.expect("Table-level UNIQUE should be parsed");
db.execute("INSERT INTO t1 VALUES (1, 'A', 'Alice')", ())
.expect("First insert should succeed");
db.execute("INSERT INTO t1 VALUES (2, 'B', 'Bob')", ())
.expect("Second insert should succeed");
let result = db.execute("INSERT INTO t1 VALUES (3, 'A', 'Charlie')", ());
assert!(
result.is_err(),
"Duplicate code should violate unique constraint"
);
let result = db
.query("SELECT * FROM t1 ORDER BY id", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should have exactly 2 rows");
}
#[test]
fn test_bugs2_11_cast_of_aggregate() {
let db = setup_db("bugs2_11");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create failed");
db.execute("INSERT INTO t VALUES (1, 10), (2, 20), (3, 30)", ())
.expect("Insert failed");
let result = db
.query("SELECT CAST(SUM(val) AS TEXT) as sum_text FROM t", ())
.expect("CAST of SUM should work");
let rows: Vec<_> = result.collect();
let sum_text: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(sum_text, "60", "SUM should be cast to text '60'");
let result = db
.query("SELECT CAST(AVG(val) AS INTEGER) as avg_int FROM t", ())
.expect("CAST of AVG should work");
let rows: Vec<_> = result.collect();
let avg_int: i64 = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(avg_int, 20, "AVG should be cast to integer 20");
let result = db
.query("SELECT CAST(COUNT(*) AS TEXT) as cnt_text FROM t", ())
.expect("CAST of COUNT should work");
let rows: Vec<_> = result.collect();
let cnt_text: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(cnt_text, "3", "COUNT should be cast to text '3'");
}
#[test]
fn test_bugs2_12_order_by_expression_with_alias() {
let db = setup_db("bugs2_12");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("Create failed");
db.execute("INSERT INTO t VALUES (1, 30), (2, 10), (3, 20)", ())
.expect("Insert failed");
let result = db
.query("SELECT id, val * 2 as doubled FROM t ORDER BY doubled", ())
.expect("ORDER BY alias should work");
let rows: Vec<_> = result.collect();
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![2, 3, 1], "ORDER BY doubled: should be 2,3,1");
let result = db
.query("SELECT id, val * 2 as doubled FROM t ORDER BY val * 2", ())
.expect("ORDER BY expression should work");
let rows: Vec<_> = result.collect();
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![2, 3, 1], "ORDER BY val * 2: should also be 2,3,1");
let result = db
.query(
"SELECT id, val * 2 as doubled FROM t ORDER BY val * 2 DESC",
(),
)
.expect("ORDER BY expression DESC should work");
let rows: Vec<_> = result.collect();
let ids: Vec<i64> = rows
.iter()
.map(|r| r.as_ref().unwrap().get(0).unwrap())
.collect();
assert_eq!(ids, vec![1, 3, 2], "ORDER BY val * 2 DESC: should be 1,3,2");
}
#[test]
fn test_bugs2_13_window_with_cte_and_join() {
let db = setup_db("bugs2_13");
db.execute(
"CREATE TABLE products (id INTEGER PRIMARY KEY, category TEXT, price FLOAT)",
(),
)
.expect("Create failed");
db.execute(
"INSERT INTO products VALUES (1, 'A', 10.0), (2, 'A', 20.0), (3, 'B', 30.0)",
(),
)
.expect("Insert failed");
let result = db
.query(
"WITH cat_avg AS (SELECT category, AVG(price) as avg FROM products GROUP BY category) \
SELECT p.category, p.price, c.avg \
FROM products p JOIN cat_avg c ON p.category = c.category \
ORDER BY p.id",
(),
)
.expect("CTE + JOIN should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3);
let result = db
.query(
"WITH cat_avg AS (SELECT category, AVG(price) as avg FROM products GROUP BY category) \
SELECT p.category, p.price, \
RANK() OVER (PARTITION BY p.category ORDER BY p.price) as rnk \
FROM products p JOIN cat_avg c ON p.category = c.category \
ORDER BY p.category, rnk",
(),
)
.expect("CTE + JOIN + window function should work");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should have 3 rows");
let rank1: i64 = rows[0].as_ref().unwrap().get(2).unwrap();
let rank2: i64 = rows[1].as_ref().unwrap().get(2).unwrap();
let rank3: i64 = rows[2].as_ref().unwrap().get(2).unwrap();
assert_eq!(rank1, 1, "First A product should have rank 1");
assert_eq!(rank2, 2, "Second A product should have rank 2");
assert_eq!(rank3, 1, "B product should have rank 1");
}
#[test]
fn test_reserved_keyword_error_message() {
let db = setup_db("reserved_keyword");
let result = db.execute("CREATE TABLE t (key TEXT PRIMARY KEY, val INTEGER)", ());
assert!(result.is_err(), "Using reserved keyword should fail");
let err_msg = format!("{:?}", result.unwrap_err());
assert!(
err_msg.contains("reserved keyword") || err_msg.contains("KEY"),
"Error should mention reserved keyword: {}",
err_msg
);
db.execute("CREATE TABLE t (\"key\" TEXT, id INTEGER PRIMARY KEY)", ())
.expect("Quoted reserved keyword should work");
db.execute("INSERT INTO t VALUES ('test', 1)", ())
.expect("Insert should work");
let result = db
.query("SELECT \"key\" FROM t", ())
.expect("Query with quoted identifier should work");
let rows: Vec<_> = result.collect();
let key_val: String = rows[0].as_ref().unwrap().get(0).unwrap();
assert_eq!(key_val, "test");
}
#[test]
fn test_order_by_limit_with_unique_constraint() {
let db = setup_db("order_by_limit_unique");
db.execute(
"CREATE TABLE items (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name TEXT NOT NULL UNIQUE
)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO items (name) VALUES ('C'), ('A'), ('B')", ())
.expect("Insert failed");
let result = db
.query("SELECT * FROM items ORDER BY name ASC LIMIT 2", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should return 2 rows with LIMIT 2");
let row0 = rows[0].as_ref().expect("Row should exist");
let name0: String = row0.get(1).unwrap();
assert_eq!(name0, "A", "First row should be 'A'");
let row1 = rows[1].as_ref().expect("Row should exist");
let name1: String = row1.get(1).unwrap();
assert_eq!(name1, "B", "Second row should be 'B'");
let result = db
.query("SELECT * FROM items ORDER BY name DESC LIMIT 2", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 2, "Should return 2 rows with LIMIT 2 DESC");
let row0 = rows[0].as_ref().expect("Row should exist");
let name0: String = row0.get(1).unwrap();
assert_eq!(name0, "C", "First row DESC should be 'C'");
let result = db
.query("SELECT * FROM items ORDER BY name ASC LIMIT 1 OFFSET 1", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 1, "Should return 1 row with LIMIT 1 OFFSET 1");
let row0 = rows[0].as_ref().expect("Row should exist");
let name0: String = row0.get(1).unwrap();
assert_eq!(name0, "B", "Row at offset 1 should be 'B'");
let result = db
.query("SELECT * FROM items ORDER BY name ASC", ())
.expect("Query should succeed");
let rows: Vec<_> = result.collect();
assert_eq!(rows.len(), 3, "Should return all 3 rows without LIMIT");
}