use vibesql_parser::Parser;
use vibesql_storage::Database;
use vibesql_types::SqlValue;
use crate::SelectExecutor;
fn execute_sql(db: &Database, sql: &str) -> Vec<vibesql_storage::Row> {
let stmt = Parser::parse_sql(sql).expect("Failed to parse SQL");
if let vibesql_ast::Statement::Select(select) = stmt {
let executor = SelectExecutor::new(db);
let result = executor.execute_with_columns(&select).expect("Failed to execute SELECT");
result.rows
} else {
panic!("Expected SELECT statement");
}
}
fn execute_dml(db: &mut Database, sql: &str) {
let stmt = Parser::parse_sql(sql).expect("Failed to parse SQL");
match stmt {
vibesql_ast::Statement::CreateTable(create) => {
crate::CreateTableExecutor::execute(&create, db).expect("Failed to create table");
}
vibesql_ast::Statement::Insert(insert) => {
crate::InsertExecutor::execute(db, &insert).expect("Failed to insert");
}
vibesql_ast::Statement::CreateIndex(create_idx) => {
crate::CreateIndexExecutor::execute(&create_idx, db).expect("Failed to create index");
}
_ => panic!("Unexpected statement type"),
}
}
#[test]
fn test_search_count_basic() {
let db = Database::new();
assert_eq!(db.search_count(), 0);
db.reset_search_count();
assert_eq!(db.search_count(), 0);
db.increment_search_count(5);
assert_eq!(db.search_count(), 5);
db.increment_search_count(3);
assert_eq!(db.search_count(), 8);
db.reset_search_count();
assert_eq!(db.search_count(), 0);
}
#[test]
fn test_search_count_function() {
let db = Database::new();
let rows = execute_sql(&db, "SELECT sqlite_search_count()");
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].values[0], SqlValue::Bigint(0));
}
#[test]
fn test_search_count_reset_function() {
let db = Database::new();
db.increment_search_count(42);
assert_eq!(db.search_count(), 42);
let rows = execute_sql(&db, "SELECT sqlite_search_count_reset()");
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].values[0], SqlValue::Bigint(0));
assert_eq!(db.search_count(), 0);
}
#[test]
fn test_search_count_tracks_table_scan() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT, y INT)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1, 10)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2, 20)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (3, 30)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1");
assert_eq!(rows.len(), 3);
let count = db.search_count();
assert!(count >= 3, "Expected at least 3 rows examined, got {}", count);
assert!(count % 3 == 0, "Expected count to be multiple of 3, got {}", count);
}
#[test]
fn test_search_count_with_where_clause() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT, y INT)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1, 10)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2, 20)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (3, 30)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (4, 40)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (5, 50)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1 WHERE x = 3");
assert_eq!(rows.len(), 1);
let count = db.search_count();
assert!(count >= 5, "Expected at least 5 rows examined, got {}", count);
assert!(count % 5 == 0, "Expected count to be multiple of 5, got {}", count);
}
#[test]
fn test_search_count_with_index() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (id INT PRIMARY KEY, x INT, y INT)");
execute_dml(&mut db, "CREATE INDEX idx_x ON t1 (x)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1, 10, 100)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2, 20, 200)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (3, 30, 300)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (4, 40, 400)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (5, 50, 500)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1 WHERE x = 30");
assert_eq!(rows.len(), 1);
let count = db.search_count();
assert!(count >= 1, "Expected at least 1 row examined via index, got {}", count);
assert!(count <= 4, "Expected fewer rows with index scan, got {}", count);
}
#[test]
fn test_search_count_reset_between_queries() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2)");
db.reset_search_count();
execute_sql(&db, "SELECT * FROM t1");
let first_count = db.search_count();
assert!(first_count >= 2, "Expected at least 2 rows examined, got {}", first_count);
db.reset_search_count();
execute_sql(&db, "SELECT * FROM t1 WHERE x = 1");
let second_count = db.search_count();
assert!(second_count >= 2, "Expected at least 2 rows examined, got {}", second_count);
}
#[test]
fn test_search_count_via_sql_reset() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (3)");
execute_sql(&db, "SELECT sqlite_search_count_reset()");
execute_sql(&db, "SELECT * FROM t1");
let rows = execute_sql(&db, "SELECT sqlite_search_count()");
if let SqlValue::Bigint(count) = &rows[0].values[0] {
assert!(*count >= 3, "Expected at least 3 rows examined, got {}", count);
assert!(*count % 3 == 0, "Expected count to be multiple of 3, got {}", count);
} else {
panic!("Expected Bigint value");
}
}
#[test]
fn test_search_count_multiple_tables() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT)");
execute_dml(&mut db, "CREATE TABLE t2 (y INT)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2)");
execute_dml(&mut db, "INSERT INTO t2 VALUES (10)");
execute_dml(&mut db, "INSERT INTO t2 VALUES (20)");
execute_dml(&mut db, "INSERT INTO t2 VALUES (30)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1, t2");
assert_eq!(rows.len(), 6);
let count = db.search_count();
assert!(count >= 5, "Expected at least 5 rows examined, got {}", count);
}
#[test]
fn test_search_count_empty_table() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (x INT)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1");
assert_eq!(rows.len(), 0);
assert_eq!(db.search_count(), 0);
}
#[test]
fn test_search_count_secondary_index() {
let mut db = Database::new();
execute_dml(&mut db, "CREATE TABLE t1 (id INT PRIMARY KEY, val INT)");
execute_dml(&mut db, "CREATE INDEX idx_val ON t1 (val)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (1, 100)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (2, 200)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (3, 100)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (4, 300)");
execute_dml(&mut db, "INSERT INTO t1 VALUES (5, 100)");
db.reset_search_count();
let rows = execute_sql(&db, "SELECT * FROM t1 WHERE val = 100");
assert_eq!(rows.len(), 3);
let count = db.search_count();
assert_eq!(count, 3, "Expected 3 rows examined via index, got {}", count);
}