use vibesql_ast::Statement;
use vibesql_executor::{SelectExecutor, ExecutorError};
use vibesql_parser::Parser;
use vibesql_storage::Database;
fn run_ddl(db: &mut Database, sql: &str) {
let stmt = Parser::parse_sql(sql).expect("parse failed");
match stmt {
Statement::CreateTable(s) => {
vibesql_executor::CreateTableExecutor::execute(&s, db).unwrap();
}
Statement::CreateView(s) => {
vibesql_executor::advanced_objects::execute_create_view(&s, db).unwrap();
}
Statement::Insert(s) => {
vibesql_executor::InsertExecutor::execute(db, &s).unwrap();
}
other => panic!("unsupported DDL in test: {:?}", other),
}
}
fn run_select(db: &Database, sql: &str) -> Result<(), ExecutorError> {
let stmt = Parser::parse_sql(sql).expect("parse failed");
let Statement::Select(select) = stmt else {
panic!("expected SELECT");
};
let executor = SelectExecutor::new(db);
executor.execute_with_columns(&select).map(|_| ())
}
fn build_doubling_nest(db: &mut Database, levels: u32) {
run_ddl(db, "CREATE TABLE t1(x)");
run_ddl(db, "INSERT INTO t1 VALUES(5)");
run_ddl(db, "CREATE VIEW v1 AS SELECT x*2 FROM t1");
let mut prev = 1u64;
for _ in 0..levels {
let next = prev * 2;
run_ddl(
db,
&format!("CREATE VIEW v{next} AS SELECT * FROM v{prev} UNION SELECT * FROM v{prev}"),
);
prev = next;
}
}
#[test]
fn view3_doubling_nest_errors_instead_of_hanging() {
let mut db = Database::new();
build_doubling_nest(&mut db, 15);
let err = run_select(&db, "SELECT * FROM v32768 UNION SELECT * FROM v32768")
.expect_err("expected reference-limit error, not a hang");
let msg = err.to_string();
assert!(
msg.contains("too many references") && msg.contains("65535"),
"unexpected error message: {msg}"
);
}
#[test]
fn shallow_doubling_nest_executes_normally() {
let mut db = Database::new();
build_doubling_nest(&mut db, 6);
run_select(&db, "SELECT * FROM v64 UNION SELECT * FROM v64")
.expect("shallow nest should execute fine");
}
#[test]
fn ordinary_view_query_is_unaffected() {
let mut db = Database::new();
run_ddl(&mut db, "CREATE TABLE t(a, b)");
run_ddl(&mut db, "INSERT INTO t VALUES(1, 2)");
run_ddl(&mut db, "CREATE VIEW v AS SELECT a FROM t");
run_select(&db, "SELECT * FROM v").expect("plain view query should work");
}
#[test]
fn cte_named_like_a_view_is_not_counted() {
let mut db = Database::new();
build_doubling_nest(&mut db, 15); run_ddl(&mut db, "CREATE TABLE base(x)");
run_ddl(&mut db, "INSERT INTO base VALUES(7)");
run_ddl(&mut db, "CREATE VIEW v32768x AS SELECT * FROM v32768");
run_select(&db, "WITH v32768x AS (SELECT 1 AS x) SELECT * FROM v32768x")
.expect("CTE shadowing a heavy view must not trip the guard");
}