mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-26 04:24:21 +01:00
Closes #2993 ## Background When a `CREATE TABLE` statement specifies constraints like `col UNIQUE`, `col PRIMARY KEY`, `UNIQUE (col1, col2)`, `PRIMARY KEY(col3, col4)`, SQLite creates indexes for these constraints automatically with the naming scheme `sqlite_autoindex_<table_name>_<increasing_number>`. ## Problem SQLite expects these indexes to be created in table definition order. For example: ```sql CREATE TABLE t(x UNIQUE, y PRIMARY KEY, c, d, UNIQUE(c,d)); ``` Should result in: ```sql sqlite_autoindex_t_1 -- x UNIQUE sqlite_autoindex_t_2 -- y PRIMARY KEY sqlite_autoindex_t_3-- UNIQUE(c,d) ``` However, `tursodb` currently doesn't uphold this invariant -- for example: the PRIMARY KEY index is always constructed first. SQLite flags this as a corruption error (see #2993). ## Solution - Process "unique sets" in table definition order. "Unique sets" are groups of 1-n columns that are part of either a UNIQUE or a PRIMARY KEY constraint. - Deduplicate unique sets properly: a PRIMARY KEY of a rowid alias (INTEGER PRIMARY KEY) is not a unique set. `UNIQUE (a desc, b)` and `PRIMARY KEY(a, b)` are a single unique set, not two. - Unify logic for creating automatic indexes and parsing them - remove separate logic in `check_automatic_pk_index_required()` and use the existing `create_table()` utility in both index creation and deserialization. - Deserialize a single automatic index per unique set, and assert that `unique_sets.len() == autoindexes.len()`. - Verify consistent behavior by adding a fuzz tests that creates 1000 databases with 1 table each and runs `PRAGMA integrity_check` on all of them with SQLite. ## Trivia Apart from fixing the exact issue #2993, this PR also fixes other bugs related to autoindex construction - namely cases where too many indexes were created due to improper deduplication of unique sets. Reviewed-by: Preston Thorpe <preston@turso.tech> Closes #3018
Integration and regression test suite.
# run all tests
cargo test
# run individual test
cargo test test_sequential_write -- --nocapture