Commit graph

6149 commits

Author SHA1 Message Date
Nikita Sivukhin
ef3db24a49 rename methods in core a little bit 2025-11-27 14:12:47 +04:00
Nikita Sivukhin
4ad0f6a98d a little bit of documentation 2025-11-25 11:22:56 +04:00
Nikita Sivukhin
e39e60ef18 introduce program execution state in order to run stmt to completion in case of finalize or reset 2025-11-25 11:14:20 +04:00
Preston Thorpe
e40b07122d
Merge 'Support table xinfo' from Nikita Sivukhin
Some checks are pending
Build & publish @tursodatabase/database / db-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / db-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-apple-darwin - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-wasm32-wasip1-threads - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / Test DB bindings on Linux-x64-gnu - node@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Test DB bindings on browser@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Publish (push) Blocked by required conditions
Python / sdist (push) Waiting to run
Python / Release (push) Blocked by required conditions
Python / configure-strategy (push) Waiting to run
Python / test (push) Blocked by required conditions
Python / lint (push) Waiting to run
Python / linux (x86_64) (push) Waiting to run
Python / macos-arm64 (aarch64) (push) Waiting to run
Rust / cargo-fmt-check (push) Waiting to run
Rust / build-native (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Rust / build-native (macos-latest) (push) Waiting to run
Rust / build-native (windows-latest) (push) Waiting to run
Rust / clippy (push) Waiting to run
Rust / simulator (push) Waiting to run
Rust / test-limbo (push) Waiting to run
Rust / test-sqlite (push) Waiting to run
Rust Benchmarks+Nyrkiö / bench (push) Waiting to run
Rust Benchmarks+Nyrkiö / clickbench (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h-criterion (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h (push) Waiting to run
Rust Benchmarks+Nyrkiö / vfs-bench-compile (push) Waiting to run
Support extended pragma `table_xinfo` which in addition to all
`table_info` columns report extra column about if the column is
hidden/generated/dynamic (while usually all such columns filtered out
from the output of `table_info` pragma).

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

Closes #3994
2025-11-20 19:51:52 -05:00
Pere Diaz Bou
86119b0dba
Merge 'core/mvcc/cursor: implement prev and last ' from Pere Diaz Bou
Some checks are pending
Build & publish @tursodatabase/database / db-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / db-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-apple-darwin - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-wasm32-wasip1-threads - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / Test DB bindings on Linux-x64-gnu - node@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Test DB bindings on browser@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Publish (push) Blocked by required conditions
Python / configure-strategy (push) Waiting to run
Python / test (push) Blocked by required conditions
Python / lint (push) Waiting to run
Python / linux (x86_64) (push) Waiting to run
Python / macos-arm64 (aarch64) (push) Waiting to run
Python / sdist (push) Waiting to run
Python / Release (push) Blocked by required conditions
Rust / test-limbo (push) Waiting to run
Rust / test-sqlite (push) Waiting to run
Rust / clippy (push) Waiting to run
Rust / simulator (push) Waiting to run
Rust / cargo-fmt-check (push) Waiting to run
Rust / build-native (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Rust / build-native (macos-latest) (push) Waiting to run
Rust / build-native (windows-latest) (push) Waiting to run
Rust Benchmarks+Nyrkiö / bench (push) Waiting to run
Rust Benchmarks+Nyrkiö / clickbench (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h-criterion (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h (push) Waiting to run
Rust Benchmarks+Nyrkiö / vfs-bench-compile (push) Waiting to run
Backward scan of a table wasn't implemented yet in MVCC so this achieves
that. I added simple test for mixed btree and mvcc backward scan but I
should add more intense testing for this.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Implements backward scanning and last() in MVCC lazy cursor and adds
directional rowid iteration in the MVCC store, with new tests for mixed
MVCC+B-Tree backward scans.
>
> - **MVCC Cursor (`core/mvcc/cursor.rs`)**:
>   - Implement `prev()` and `last()` with mixed MVCC/B-Tree
coordination using `IterationDirection`.
>   - Add `PrevState` and extend state machine to handle backward
iteration.
>   - Update `get_new_position_from_mvcc_and_btree(...)` to choose
rowids based on direction.
>   - Integrate B-Tree cursor calls (`last`, `prev`) and adjust
`rewind`/rowid selection; tweak next-rowid when at `End`.
> - **MVCC Store (`core/mvcc/database/mod.rs`)**:
>   - Add `get_prev_row_id_for_table(...)` and generalized
`get_row_id_for_table_in_direction(...)` supporting forward/backward
scans.
>   - Add tracing and minor refactors around next/prev rowid retrieval.
> - **Tests (`core/mvcc/database/tests.rs`)**:
>   - Add test for backward scan combining B-Tree and MVCC and an
ignored test covering delete during backward scan.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
430bd457e6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Closes #3980
2025-11-20 18:41:41 +01:00
Nikita Sivukhin
ab3ba6a91a adjust registers allocation 2025-11-20 18:00:54 +04:00
Nikita Sivukhin
035705bc63 fix bugs and improve comments 2025-11-20 17:54:36 +04:00
Nikita Sivukhin
801f51a77d fix build 2025-11-20 17:49:18 +04:00
Nikita Sivukhin
b08374be46 support table_xinfo pragma 2025-11-20 17:38:10 +04:00
Pekka Enberg
d808db6af9 core: Switch to parking_lot::Mutex
It's faster and we eliminate bunch of unwrap() calls.
2025-11-20 10:42:02 +02:00
Pere Diaz Bou
430bd457e6 core/mvcc: fix tests with delete 2025-11-19 17:18:44 +01:00
Pere Diaz Bou
bf1afb56cf core/mvcc: test with delete after checkpoint 2025-11-19 16:56:32 +01:00
Pere Diaz Bou
b4c11705f3 core/mvcc: few suggestions from pr 2025-11-19 16:44:24 +01:00
Jussi Saurio
32063334f9 fix operator precedence bug 2025-11-19 14:29:33 +02:00
Jussi Saurio
fddcea788b refactor 2025-11-19 14:29:33 +02:00
Jussi Saurio
5d9a0b15f8 Handle qualified column references in triggers wrt ALTER TABLE 2025-11-19 14:29:33 +02:00
Jussi Saurio
dbdf60a628 extract common functionality 2025-11-19 14:29:33 +02:00
Jussi Saurio
745cdc3aa2 Align trigger sql rewrite behavior with sqlite
SQLite doesn't rewrite INSERT lists or WHEN clause, it instead
lets the trigger go "stale" and will cause runtime errors. This
may not be great behavior, but it's compatible...
2025-11-19 14:29:33 +02:00
Jussi Saurio
5b1c69a9d0 fix ai slop with more ai slop 2025-11-19 14:29:33 +02:00
Jussi Saurio
a0a1bd6637 Triggers: fix issues with ALTER TABLE
- Disallow DROP COLUMN on columns referenced in triggers
- Propagate RENAME COLUMN to trigger SQL definitions

DROP COLUMN is not allowed when the column is mentioned in a trigger
on the table the column is dropped from, eg:

```
turso> CREATE TABLE t(x,y);
turso> CREATE TRIGGER foo BEFORE INSERT ON t BEGIN INSERT INTO t VALUES (NEW.x); END;
turso> ALTER TABLE t DROP COLUMN x;
  × Parse error: cannot drop column "x": it is referenced in trigger foo
```

However, it is allowed if the trigger is on another table:

```
turso> CREATE TABLE t(x,y);
turso> CREATE TABLE u(x,y);
turso> CREATE TRIGGER bar BEFORE INSERT ON t BEGIN INSERT INTO u(y) VALUES (NEW.x); END;
turso> ALTER TABLE u DROP COLUMN y;
turso> INSERT INTO t VALUES (1,1);
  × Parse error: table u has no column named y
```

Nearly all of the code here is vibecoded. I first asked Cursor Composer to create
an initial implementation. Then, I asked it to try to discover edge cases using the
`turso` and `sqlite3` CLIs, and write tests+fixes for the edge cases found.

The code is a bit slop, but this isn't a particularly performance-critical use case
and it should solve most of the issues with RENAME and DROP COLUMN.
2025-11-19 14:29:33 +02:00
Jussi Saurio
92f47dffb0
Merge 'Trigger support' from Jussi Saurio
## Trigger Support
This PR adds support for triggers:
- `CREATE TRIGGER`
- `DROP TRIGGER`
Supported
- `BEFORE/AFTER INSERT`
- `BEFORE/AFTER DELETE`
- `BEFORE/AFTER UPDATE [OF <col1,col2,col3>]`
Not supported:
- `INSTEAD OF`
- `TEMPORARY`
### Implementation details
- Triggers are executed within a new `Insn::Program` instruction. The
spec of the insn differs a bit from SQlite: we store a `Statement`
inside that instruction that we can `reset()` for every invocation.
- Like Sqlite, trigger programs take `NEW` and `OLD` rows as program
parameters.
Whenever there are triggers that would fire as the result of a DML
statement:
- `DELETE` writes the rows being deleted into a `RowSet` first.
- `UPDATE` and `INSERT` write the rows being updated into an ephemeral
table first.
### Other shit
Also added `EXPLAIN` support - the bytecode plans for trigger
subprograms are appended after the main program.
### AI disclosure
Used Cursor quite a bit for generating boilerplate code for this - you
can blame all the bad code on the AI of course 🤡
### Follow-ups:
1. ALTER TABLE ops need to rewrite the sql in the CREATE TRIGGER
statement e.g. if a column is renamed. Columns cannot be dropped if
referenced in triggers.
2. Fix weird rowid -1 fallback:
https://github.com/tursodatabase/turso/pull/3979#issuecomment-3547999449

Closes #3979
2025-11-19 08:42:41 +02:00
Pere Diaz Bou
ca30756dfd core/mvcc/cursor: implement prev and last 2025-11-18 19:51:27 +01:00
Pere Diaz Bou
b38e69b515 core/mvcc: add get_row_id_for_table_in_direction(forward/backwards) 2025-11-18 19:51:27 +01:00
Pere Diaz Bou
b19762a812 core/mvcc/cursor: get_new_position_from_mvcc_and_btree backwards and last fix 2025-11-18 19:51:27 +01:00
Pere Diaz Bou
73d9f0016c core/mvcc: test order by desc with mvcc 2025-11-18 19:51:27 +01:00
Pere Diaz Bou
72bf195f4b
Merge 'core/mvcc/cursor: rowid don't seek first rowid' from Pere Diaz Bou
Some checks are pending
Build & publish @tursodatabase/database / db-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / db-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-apple-darwin - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-aarch64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-wasm32-wasip1-threads - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-pc-windows-msvc - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / sync-bindings-x86_64-unknown-linux-gnu - node@20 (push) Waiting to run
Build & publish @tursodatabase/database / Test DB bindings on Linux-x64-gnu - node@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Test DB bindings on browser@20 (push) Blocked by required conditions
Build & publish @tursodatabase/database / Publish (push) Blocked by required conditions
Python / linux (x86_64) (push) Waiting to run
Python / configure-strategy (push) Waiting to run
Python / test (push) Blocked by required conditions
Python / lint (push) Waiting to run
Python / macos-arm64 (aarch64) (push) Waiting to run
Python / sdist (push) Waiting to run
Python / Release (push) Blocked by required conditions
Rust / test-sqlite (push) Waiting to run
Rust / cargo-fmt-check (push) Waiting to run
Rust / build-native (blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Rust / build-native (macos-latest) (push) Waiting to run
Rust / build-native (windows-latest) (push) Waiting to run
Rust / clippy (push) Waiting to run
Rust / simulator (push) Waiting to run
Rust / test-limbo (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h (push) Waiting to run
Rust Benchmarks+Nyrkiö / bench (push) Waiting to run
Rust Benchmarks+Nyrkiö / clickbench (push) Waiting to run
Rust Benchmarks+Nyrkiö / tpc-h-criterion (push) Waiting to run
Rust Benchmarks+Nyrkiö / vfs-bench-compile (push) Waiting to run
rowid should only try to use the current's position. So if we are not
pointing to a `Loaded` row, then it should return None
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Change `rowid()` to return `None` unless cursor is on a `Loaded` row,
removing the implicit seek from `BeforeFirst`.
>
> - **Core MVCC Cursor (`core/mvcc/cursor.rs`)**:
>   - Adjust `rowid()` behavior: remove implicit first-row seek when
`BeforeFirst`; return `None` unless position is `Loaded`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8848775a71. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

Closes #3977
2025-11-18 19:51:19 +01:00
Jussi Saurio
ad753281b6 Remove unneeded too_many_arguments annotation 2025-11-18 18:41:45 +02:00
Jussi Saurio
129ee8c82b Remove more AI-generated unnecessary code 2025-11-18 17:24:10 +02:00
Jussi Saurio
2cbc83a01c triggers: add ParamMap abstraction to reduce code noise a bit 2025-11-18 17:08:22 +02:00
Jussi Saurio
11528cff12 Remove weird AI-innovated negative index hack 2025-11-18 16:56:27 +02:00
Jussi Saurio
2674145937 Avoid allocation when no triggers exist 2025-11-18 15:40:06 +02:00
Jussi Saurio
d33c294380 remove unhelpful comment 2025-11-18 15:39:53 +02:00
Jussi Saurio
5c1ebbd011 Use VecDeque for trigger storage for similar reasons as indexes do 2025-11-18 15:19:01 +02:00
Jussi Saurio
9aa09d5ccf Add EXPLAIN support for trigger subprograms
They get printed after the parent program.
2025-11-18 15:19:01 +02:00
Jussi Saurio
423a1444d1 Don't crash if table cursor is already opened 2025-11-18 15:19:01 +02:00
Jussi Saurio
7f536506c3 Clear deferred_seeks for cursor when it is closed
Sometimes the deferred seek never happens, so we don't want it to
dangle if the same cursor is reused for another seek
2025-11-18 15:19:01 +02:00
Jussi Saurio
d398f12471 triggers: subprograms shouldnt commit or use the transaction opcode 2025-11-18 15:19:01 +02:00
Jussi Saurio
be6f8ab8b3 state.end_statement() should not be called separately in cases where abort() already does it 2025-11-18 15:19:01 +02:00
Jussi Saurio
7a12e184a8 Only reset FK violation counter if stmt was rolled back
In the case of trigger subprograms the statement didn't roll back,
since the parent program will roll it back.
2025-11-18 15:19:01 +02:00
Jussi Saurio
770c6eef9f triggers: subprograms dont use transactions 2025-11-18 15:19:01 +02:00
Jussi Saurio
70267f8710 triggers: add translation logic for INSERT triggers 2025-11-18 15:19:01 +02:00
Jussi Saurio
e28301dc2e triggers: add translation logic for UPDATE triggers 2025-11-18 15:19:01 +02:00
Jussi Saurio
516dae5b6a triggers: add translation logic for DELETE triggers 2025-11-18 15:19:01 +02:00
Jussi Saurio
5b037b0f75 resolve labels for RowSetRead insn 2025-11-18 15:19:01 +02:00
Jussi Saurio
7d1543fcc5 triggers: take triggers into account in optimizer decision
- optimize the select plan used for the RowSet in DELETE
- require ephemeral table when UPDATE involves triggers
2025-11-18 15:19:01 +02:00
Jussi Saurio
78ce3c8658 triggers: add capability for DeletePlan to write the write set into a RowSet first
This is needed for safe DELETE when there are DELETE triggers on the affected
table.
2025-11-18 15:19:01 +02:00
Jussi Saurio
e60e37da7d triggers: add execution plumbing to translation and vdbe layers 2025-11-18 15:19:01 +02:00
Jussi Saurio
3d00686f48 triggers: translation functions for DDL 2025-11-18 12:18:07 +02:00
Jussi Saurio
d4b487eebc triggers: add in-memory schema entries 2025-11-18 12:14:27 +02:00
PThorpe92
56f35ad4cd
cargo fmt 2025-11-17 12:22:55 -05:00