use vibesql_executor::{DeleteExecutor, InsertExecutor, SelectExecutor, UpdateExecutor};
use vibesql_types::SqlValue;
fn run_stmt(db: &mut vibesql_storage::Database, sql: &str) {
let stmt = vibesql_parser::Parser::parse_sql(sql)
.unwrap_or_else(|e| panic!("Parse failed: {} -- {:?}", sql, e));
match stmt {
vibesql_ast::Statement::CreateTable(create_table) => {
vibesql_executor::CreateTableExecutor::execute(&create_table, db).unwrap();
}
vibesql_ast::Statement::Insert(insert) => {
InsertExecutor::execute(db, &insert)
.unwrap_or_else(|e| panic!("Insert failed: {} -- {:?}", sql, e));
}
vibesql_ast::Statement::Update(update) => {
UpdateExecutor::execute(&update, db)
.unwrap_or_else(|e| panic!("Update failed: {} -- {:?}", sql, e));
}
vibesql_ast::Statement::Delete(delete) => {
DeleteExecutor::execute(&delete, db)
.unwrap_or_else(|e| panic!("Delete failed: {} -- {:?}", sql, e));
}
other => panic!("Unsupported statement in test setup: {:?}", other),
}
}
fn query(db: &vibesql_storage::Database, sql: &str) -> Vec<Vec<SqlValue>> {
let stmt = vibesql_parser::Parser::parse_sql(sql)
.unwrap_or_else(|e| panic!("Parse failed: {} -- {:?}", sql, e));
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let executor = SelectExecutor::new(db);
executor
.execute(&select_stmt)
.unwrap_or_else(|e| panic!("Query failed: {} -- {:?}", sql, e))
.into_iter()
.map(|row| row.values.to_vec())
.collect()
} else {
panic!("Expected SELECT statement: {}", sql);
}
}
#[test]
fn test_with_insert_values_scalar_subquery() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "WITH c AS (SELECT 8) INSERT INTO t VALUES((SELECT * FROM c))");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(8)]]);
}
#[test]
fn test_with_insert_values_multi_row() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(
&mut db,
"WITH c AS (SELECT 5 AS v) \
INSERT INTO t VALUES((SELECT v FROM c)), ((SELECT v+1 FROM c))",
);
assert_eq!(
query(&db, "SELECT a FROM t ORDER BY a"),
vec![vec![SqlValue::Integer(5)], vec![SqlValue::Integer(6)]]
);
}
#[test]
fn test_with_insert_select_from_cte() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "WITH c AS (SELECT 8 AS v) INSERT INTO t SELECT v FROM c");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(8)]]);
}
#[test]
fn test_with_insert_select_cte_in_where() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE src(x INTEGER)");
run_stmt(&mut db, "INSERT INTO src VALUES(10),(20),(30)");
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(
&mut db,
"WITH c AS (SELECT 15 AS lim) \
INSERT INTO t SELECT x FROM src WHERE x > (SELECT lim FROM c)",
);
assert_eq!(
query(&db, "SELECT a FROM t ORDER BY a"),
vec![vec![SqlValue::Integer(20)], vec![SqlValue::Integer(30)]]
);
}
#[test]
fn test_with_insert_cte_shadows_catalog_table() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE c(v INTEGER)");
run_stmt(&mut db, "INSERT INTO c VALUES(111)");
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "WITH c AS (SELECT 8 AS v) INSERT INTO t SELECT v FROM c");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(8)]]);
run_stmt(&mut db, "DELETE FROM t");
run_stmt(&mut db, "WITH c AS (SELECT 9 AS v) INSERT INTO t VALUES((SELECT v FROM c))");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(9)]]);
assert_eq!(query(&db, "SELECT v FROM c"), vec![vec![SqlValue::Integer(111)]]);
}
#[test]
fn test_with_insert_cte_case_insensitive() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE src(x INTEGER)");
run_stmt(&mut db, "INSERT INTO src VALUES(10),(20),(30)");
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(
&mut db,
"WITH Costs AS (SELECT 15 AS lim) \
INSERT INTO t SELECT x FROM src WHERE x > (SELECT lim FROM cOSTS)",
);
assert_eq!(
query(&db, "SELECT a FROM t ORDER BY a"),
vec![vec![SqlValue::Integer(20)], vec![SqlValue::Integer(30)]]
);
run_stmt(&mut db, "DELETE FROM t");
run_stmt(&mut db, "WITH C AS (SELECT 9 AS v) INSERT INTO t VALUES((SELECT v FROM c))");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(9)]]);
}
#[test]
fn test_with_insert_default_values() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER DEFAULT 7)");
run_stmt(&mut db, "WITH c AS (SELECT 8) INSERT INTO t DEFAULT VALUES");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(7)]]);
}
#[test]
fn test_with_insert_on_conflict_do_update_cte() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER PRIMARY KEY, b INTEGER)");
run_stmt(&mut db, "INSERT INTO t VALUES(1, 0)");
run_stmt(
&mut db,
"WITH c AS (SELECT 8 AS v) INSERT INTO t VALUES(1, 99) \
ON CONFLICT(a) DO UPDATE SET b=(SELECT v FROM c)",
);
assert_eq!(
query(&db, "SELECT a, b FROM t"),
vec![vec![SqlValue::Integer(1), SqlValue::Integer(8)]]
);
}
#[test]
fn test_with_insert_returning_cte_subquery() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
let sql = "WITH c AS (SELECT 8 AS v) INSERT INTO t VALUES(1) RETURNING (SELECT v FROM c)";
let stmt = vibesql_parser::Parser::parse_sql(sql).unwrap();
let vibesql_ast::Statement::Insert(insert) = stmt else {
panic!("Expected INSERT statement");
};
let outcome = InsertExecutor::execute_returning(&mut db, &insert).unwrap();
assert_eq!(outcome.affected_rows, 1);
let returning = outcome.returning.expect("RETURNING result expected");
assert_eq!(returning.rows.len(), 1);
assert_eq!(returning.rows[0].values.to_vec(), vec![SqlValue::Integer(8)]);
}
#[test]
fn test_with_update_cte_in_set_and_where() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "INSERT INTO t VALUES(1),(2)");
run_stmt(&mut db, "WITH c AS (SELECT 1 AS k) UPDATE t SET a = a*10 WHERE a = (SELECT k FROM c)");
assert_eq!(
query(&db, "SELECT a FROM t ORDER BY a"),
vec![vec![SqlValue::Integer(2)], vec![SqlValue::Integer(10)]]
);
}
#[test]
fn test_with_update_returning_cte_subquery() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "INSERT INTO t VALUES(1)");
let sql = "WITH c AS (SELECT 8 AS v) UPDATE t SET a=2 RETURNING (SELECT v FROM c)";
let stmt = vibesql_parser::Parser::parse_sql(sql).unwrap();
let vibesql_ast::Statement::Update(update) = stmt else {
panic!("Expected UPDATE statement");
};
let (count, returning) = UpdateExecutor::execute_returning(&update, &mut db).unwrap();
assert_eq!(count, 1);
let returning = returning.expect("RETURNING result expected");
assert_eq!(returning.rows.len(), 1);
assert_eq!(returning.rows[0].values.to_vec(), vec![SqlValue::Integer(8)]);
}
#[test]
fn test_with_delete_cte_in_where_and_returning() {
let mut db = vibesql_storage::Database::new();
run_stmt(&mut db, "CREATE TABLE t(a INTEGER)");
run_stmt(&mut db, "INSERT INTO t VALUES(2),(10)");
run_stmt(&mut db, "WITH c AS (SELECT 2 AS k) DELETE FROM t WHERE a = (SELECT k FROM c)");
assert_eq!(query(&db, "SELECT a FROM t"), vec![vec![SqlValue::Integer(10)]]);
let sql = "WITH c AS (SELECT 9 AS v) DELETE FROM t RETURNING (SELECT v FROM c)";
let stmt = vibesql_parser::Parser::parse_sql(sql).unwrap();
let vibesql_ast::Statement::Delete(delete) = stmt else {
panic!("Expected DELETE statement");
};
let (count, returning) = DeleteExecutor::execute_returning(&delete, &mut db).unwrap();
assert_eq!(count, 1);
let returning = returning.expect("RETURNING result expected");
assert_eq!(returning.rows.len(), 1);
assert_eq!(returning.rows[0].values.to_vec(), vec![SqlValue::Integer(9)]);
}