use fsqlite_core::connection::Connection;
use fsqlite_planner::stats::parse_stat1;
fn stat1_n_rows(conn: &Connection, table: &str) -> Option<u64> {
let rows = conn
.query_with_params(
"SELECT stat FROM sqlite_stat1 WHERE tbl = ?1 AND idx IS NULL",
&[fsqlite_types::value::SqliteValue::Text(
table.to_owned().into(),
)],
)
.expect("sqlite_stat1 query");
let mut out: Option<u64> = None;
for row in &rows {
if let Some(fsqlite_types::value::SqliteValue::Text(stat)) = row.values().first() {
if let Some(parsed) = parse_stat1(stat.as_ref()) {
out = Some(parsed.n_rows);
}
}
}
out
}
#[test]
fn analyze_populates_sqlite_stat1_and_planner_can_parse_it() {
let conn = Connection::open(":memory:").unwrap();
conn.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v INTEGER);")
.unwrap();
for i in 0..42 {
conn.execute_with_params(
"INSERT INTO t(v) VALUES (?1);",
&[fsqlite_types::value::SqliteValue::Integer(i)],
)
.unwrap();
}
conn.execute("ANALYZE;").unwrap();
let n_rows = stat1_n_rows(&conn, "t")
.expect("ANALYZE must write a table-level row to sqlite_stat1 for 't'");
assert_eq!(
n_rows, 42,
"planner's parse_stat1 must recover the inserted row count"
);
}
#[test]
fn sqlite_stat1_parse_matches_multi_row_counts() {
let conn = Connection::open(":memory:").unwrap();
conn.execute("CREATE TABLE small (id INTEGER PRIMARY KEY);")
.unwrap();
conn.execute("CREATE TABLE big (id INTEGER PRIMARY KEY);")
.unwrap();
conn.execute("BEGIN;").unwrap();
for _ in 0..3 {
conn.execute("INSERT INTO small DEFAULT VALUES;").unwrap();
}
for _ in 0..200 {
conn.execute("INSERT INTO big DEFAULT VALUES;").unwrap();
}
conn.execute("COMMIT;").unwrap();
conn.execute("ANALYZE;").unwrap();
let small = stat1_n_rows(&conn, "small").expect("small must appear in sqlite_stat1");
let big = stat1_n_rows(&conn, "big").expect("big must appear in sqlite_stat1");
assert_eq!(small, 3);
assert_eq!(big, 200);
assert!(big > small, "planner must distinguish small from big table");
}
#[test]
fn parse_stat1_rejects_malformed_and_handles_empty() {
assert!(parse_stat1("").is_none());
assert!(parse_stat1("abc").is_none());
let parsed = parse_stat1("1234").unwrap();
assert_eq!(parsed.n_rows, 1234);
assert!(parsed.per_column_distinct.is_empty());
}