Commit Graph

5593 Commits

Author SHA1 Message Date
Avinash Sajjanshetty
ee479d2e52 Move all checksum tests behind the feature flag 2025-10-13 13:47:25 +05:30
Jussi Saurio
06bc90bffe Merge 'core/translate: implement basic foreign key constraint support' from Preston Thorpe
This PR introduces support for foreign key constraints, and the `PRAGMA
foreign_keys;`, and relevant opcodes: `FkCounter` and `FkIfZero`.
Extensive fuzz tests were added both for regular and composite
PK/rowid/unique index constraints, as well as some really weird
edgecases to make sure we our affinity handling is correct as well when
we trigger the constraints.
Foreign-key checking is driven by two VDBE ops: `FkCounter` and
`FkIfZero`, and
 `FkCounter` is a running meter on the `Connection` for deferred FK
violations. When an `insert/delete/update` operation creates a potential
orphan (we insert a child row that doesn’t have a matching parent, or we
delete/update a parent that children still point at), this counter is
incremented. When a later operation fixes that (e.g. we insert the
missing parent or re-target the child), we decrement the counter. If any
is remaining at commit time, the commit fails. For immediate
constraints, on the violation path we emit Halt right away.
`FkIfZero` can either be used to guard a decrement of FkCounter to
prevent underflow, or can potentially (in the future) be used to avoid
work checking if any constraints need resolving.
NOTE: this PR does not implement `pragma defer_foreign_keys` for global
`deferred` constraint semantics. only explicit `col INT REFERENCES t(id)
DEFERRABLE INITIALLY DEFERRED` is supported in this PR.
This PR does not add support for `ON UPDATE|DELETE CASCADE`, only for
basic implicit `DO NOTHING` behavior.
~~NOTE: I did notice that, as referenced here: #3463~~
~~our current handling of unique constraints does not pass fuzz tests, I
believe only in the case of composite primary keys,~~ ~~because the fuzz
test for FK referencing composite PK is failing but only for UNIQUE
constraints, never (or as many times as i tried) for foreign key
constraints.~~
EDIT: all fuzzers are passing, because @sivukhin fixed the unique
constraint issue.
The reason that the `deferred` fuzzer is `#[ignore]`'d is because sqlite
uses sub-transactions, and even though the fuzzing only does 1 entry per
transaction... the fuzzer can lose track of _when_ it's in a transaction
and when it hits a FK constraint, and there is an error in both DB's, it
can just continue to do run regular statements, and then the eventual
ROLLBACK will revert different things in sqlite vs turso.. so for now,
we leave it `ignore`d

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #3510
2025-10-08 11:44:24 +03:00
Pekka Enberg
13566e5cad Merge 'Integrity check enhancements' from Jussi Saurio
- add index root pages to list of root pages to check
- check for dangling (unused) pages
```sql
$ cargo run wut.db 
turso> .mode list
turso> pragma integrity_check;
Page 3: never used
Page 4: never used
Page 7: never used
Page 8: never used
```
```sql
$ sqlite3 wut.db 'pragma integrity_check;'
*** in database main ***
Page 3: never used
Page 4: never used
Page 7: never used
Page 8: never used
```

Closes #3613
2025-10-08 08:57:18 +03:00
PThorpe92
7e9277958b Fix deferred FK in vdbe 2025-10-07 16:45:23 -04:00
PThorpe92
a232e3cc7a Implement proper handling of deferred foreign keys 2025-10-07 16:45:23 -04:00
PThorpe92
f56f37fae5 Add more tests for self-referencing FKs and remove unneeded FkIfZero checks/labels in emitter 2025-10-07 16:45:23 -04:00
PThorpe92
99ae96c5f6 Fix self-referential FK relationships and validation of FKs 2025-10-07 16:45:22 -04:00
PThorpe92
fa23cedbbe Add helper to pragma to parse enabled opts and fix schema parsing for foreign key constraints 2025-10-07 16:45:22 -04:00
PThorpe92
37c8abf247 Fix schema representation and methods for ForeignKey resolution 2025-10-07 16:45:22 -04:00
PThorpe92
ae975afe49 Remove unnecessary FK resolution on schema parsing 2025-10-07 16:45:16 -04:00
PThorpe92
346e6fedfa Create ForeignKey, ResolvedFkRef types and FK resolution 2025-10-07 16:27:49 -04:00
PThorpe92
c2b7026131 Add FOREIGN_KEY constraint error 2025-10-07 16:22:20 -04:00
PThorpe92
d04b07b8b7 Add pragma foreign_keys and fk_if_zero and fk_counter opcodes 2025-10-07 16:22:20 -04:00
Levy A.
cf53ecb7e3 refactor: remove TextRef and RawSlice and fix tests 2025-10-07 10:43:45 -03:00
Levy A.
77a412f6af refactor: remove unsafe reference semantics from RefValue
also renames `RefValue` to `ValueRef`, to align with rusqlite and other
crates
2025-10-07 10:43:44 -03:00
Pekka Enberg
243a5c719f Merge 'Fix re-entrancy of op_destroy (used by DROP TABLE)' from Jussi Saurio
op_destroy was assuming we never yield IO from
BTreeCursor::btree_destroy(), so every so often it would just not
complete the procedure and leave dangling pages in the database
Closes #3608

Closes #3618
2025-10-07 16:13:23 +03:00
Jussi Saurio
5583e76981 Fix re-entrancy of op_destroy (used by DROP TABLE)
op_destroy was assuming we never yield IO from BTreeCursor::btree_destroy(),
so every so often it would just not complete the procedure and leave
dangling pages in the database
2025-10-07 15:38:30 +03:00
Pekka Enberg
1dbf493f14 Merge 'emit proper column information for explain prepared statements' from Nikita Sivukhin
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #3612
2025-10-07 13:44:17 +03:00
Pekka Enberg
b98c4ece0d Merge 'core/mvcc/logical-log: switch RwLock to parking_lot' from Pere Diaz Bou
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #3615
2025-10-07 13:43:39 +03:00
Pere Diaz Bou
a7d2462c05 core/io/uring: fix inner usages
Yield is a completion that does not allocate any inner state. By design
it is completed from the start and has no errors. This allows lightly
yield without allocating any locks nor heap allocate inner state.
2025-10-07 12:05:54 +02:00
Pere Diaz Bou
3e508a4b42 core/io: remove new_dummy in place of new_yield
Yield is a completion that does not allocate any inner state. By design
it is completed from the start and has no errors. This allows lightly
yield without allocating any locks nor heap allocate inner state.
2025-10-07 12:00:33 +02:00
Pere Diaz Bou
44152f11d0 core/mvcc/logical-log: switch RwLock to parking_lot 2025-10-07 11:15:48 +02:00
Jussi Saurio
5941c03a4f integrity check: check for dangling (unused) pages 2025-10-07 11:35:38 +03:00
Jussi Saurio
603b7121de integrity check: check index root pages too
we had code in the integrity check state machine for indexes, but
index root pages were never added to the list to check.
2025-10-07 11:34:25 +03:00
Nikita Sivukhin
bd1013d62f emit proper column information for explain prepared statements 2025-10-07 12:28:55 +04:00
Pekka Enberg
a72b07e949 Merge 'Fix VDBE program abort' from Nikita Sivukhin
This PR add proper program abort in case of unfinished statement reset
and interruption.
Also, this PR makes rollback methods non-failing because otherwise of
their callers usually unclear (if rollback failed - what is the state of
statement/connection/transaction?)

Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #3591
2025-10-07 09:07:07 +03:00
Pekka Enberg
dacb8e3350 Merge 'Fix attach I/O error with in-memory databases' from Preston Thorpe
closes #3540

Closes #3602
2025-10-07 09:00:02 +03:00
Pekka Enberg
ce41bebaa8 Merge 'core/incremental: Fix re-insertion of data with same key' from Glauber Costa
There is currently a bug found in our materialized view implementation
that happens when we delete a row, and then re-insert another row with
the same primary key.
Our insert code needs to detect updates and generate a DELETE + INSERT.
But in this case, after the initial DELETE, the fresh insert generates
another delete.
We ended up with the wrong response for aggregations (and I am pretty
sure even filter-only views would manifest the bug as well), where
groups that should still be present just disappeared because of the
extra delete.
A new test case is added that fails without the fix.

Closes #3601
2025-10-07 08:47:38 +03:00
Pekka Enberg
e9be38c769 Merge 'Add MVCC checkpoint threshold pragma' from bit-aloo
closes: #3575

Closes #3604
2025-10-07 08:46:41 +03:00
Pekka Enberg
5f2beb1122 Merge 'core/incremental: Implement "is null" and "is not null" tests for view filter' from Glauber Costa
Just overlook on our side that they were not generated before.

Closes #3603
2025-10-07 08:45:45 +03:00
bit-aloo
afadb32c4c fmt fixes 2025-10-07 10:20:13 +05:30
bit-aloo
68b6ffe57c Implement mvcc_checkpoint_threshold pragma 2025-10-07 10:17:05 +05:30
bit-aloo
551dbf518e Add new mvcc_checkpoint_threshold pragma name 2025-10-07 10:17:05 +05:30
bit-aloo
fb5f5d9a90 Add MVCC checkpoint threshold APIs to Connection 2025-10-07 10:17:04 +05:30
bit-aloo
66c69461fb Add getter/setter for checkpoint threshold in LogicalLog
Wire threshold access through Storage

Add checkpoint threshold accessors to MvStore
2025-10-07 10:17:04 +05:30
Glauber Costa
e2694ff88b implement is null / is not null tests for mview filter
Just overlook on our side that they were not generated before.
2025-10-06 21:22:30 -05:00
PThorpe92
20d2ca55fe fix clippy warning 2025-10-06 21:43:48 -04:00
PThorpe92
17da71ee3c Open db with proper IO when attaching database to fix #3540 2025-10-06 21:33:20 -04:00
Glauber Costa
beb44e8e8c fix mviews with re-insertion of data with the same key
There is currently a bug found in our materialized view implementation
that happens when we delete a row, and then re-insert another row with
the same primary key.

Our insert code needs to detect updates and generate a DELETE +
INSERT. But in this case, after the initial DELETE, the fresh insert
generates another delete.

We ended up with the wrong response for aggregations (and I am pretty
sure even filter-only views would manifest the bug as well), where
groups that should still be present just disappeared because of the
extra delete.

A new test case is added that fails without the fix.
2025-10-06 20:12:49 -05:00
Preston Thorpe
497808a40c Merge 'eliminate the need for another Once in Completion' from Pedro Muniz
I added the `Once` before so fix a bug, but it was a bit hackery. We can
`get_or_init` to achieve the same purpose, and the code becomes much
cleaner. `get_or_init` guarantees the init will happen only once as
well.

Reviewed-by: Preston Thorpe <preston@turso.tech>
Reviewed-by: bit-aloo (@Shourya742)

Closes #3578
2025-10-06 19:52:41 -04:00
Pekka Enberg
f8bdc02986 Merge 'Rename Completion methods' from Pedro Muniz
Reviewed-by: bit-aloo (@Shourya742)
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #3579
2025-10-06 20:12:21 +03:00
Pere Diaz Bou
59c08c1062 Merge 'core/mvcc: implement PartialOrd for RowId' from Pere Diaz Bou
Closes #3597
2025-10-06 16:42:04 +02:00
pedrocarlo
2ce0e9db57 eliminate the need for another Once in Completion 2025-10-06 11:10:41 -03:00
pedrocarlo
5a7390735d rename Completion functions 2025-10-06 11:07:06 -03:00
Nikita Sivukhin
e2f7310617 add explicit tracker for Txn cleanup necessary for statement 2025-10-06 17:51:43 +04:00
Pekka Enberg
41d909e1fb Merge 'MVCC: do checkpoint writes in ascending order of rowid' from Jussi Saurio
For insert-heavy checkpoints this gives a much higher chance of using
the balance-quick subalgorithm instead of the more complex and slower
balance-nonroot.

Closes #3589
2025-10-06 16:30:19 +03:00
Pere Diaz Bou
aed255d2e6 core/mvcc: implement PartialOrd for RowId 2025-10-06 13:43:42 +02:00
Pere Diaz Bou
fc7e1639a0 core/mvcc: filter out seek results where is not same table_id 2025-10-06 13:29:10 +02:00
Pere Diaz Bou
b9b9831d17 core/mvcc: test seek with empty table 2025-10-06 13:28:51 +02:00
Nikita Sivukhin
0ace1f9d90 fix code in order to not reset internal prepared statements created during DDL execution 2025-10-06 15:11:23 +04:00