Commit Graph

720 Commits

Author SHA1 Message Date
Nikita Sivukhin
8acbe3de66 make query_start method to return bool - if result will have some rows or not 2025-10-28 11:27:35 +04:00
Nikita Sivukhin
67c1855ba8 fix bug 2025-10-28 11:27:35 +04:00
Nikita Sivukhin
6206294584 fix clippy 2025-10-28 11:27:35 +04:00
Nikita Sivukhin
8dd2644c07 add support for new cursor type in existing op codes and also implement new opcodes in the VM 2025-10-28 11:27:35 +04:00
Nikita Sivukhin
408ca235d1 small refactoring 2025-10-27 12:43:38 +04:00
Nikita Sivukhin
906bbdd1c4 support deep nestedness 2025-10-27 11:37:42 +04:00
Pekka Enberg
7d035f27d8 Merge 'Strict numeric cast for op_must_be_int' from bit-aloo
closes: #3302

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

Closes #3771
2025-10-26 16:42:35 +02:00
Pekka Enberg
6603f5318a Merge 'core/vdbe: Reuse cursor in op_open_write()' from Pekka Enberg
This optimization reuses an existing cursor when op_open_write() is
called on the same table/index (same root_page). This is safe because
the cursor position doesn't matter - op_rewind() is always called after
op_open_write() to position the cursor at the beginning of the
table/index before any operations are performed.
This change speeds up op_open_write() by avoiding unnecessary cursor re-
initialization.

Closes #3815
2025-10-26 12:29:20 +02:00
Pekka Enberg
ca073b5ecd Merge 'core: Switch RwLock<Arc<Pager>> to ArcSwap<Pager>' from Pekka Enberg
We don't actually need the RwLock locking capabilities, just the ability
to swap the instance.

Closes #3814
2025-10-26 12:29:11 +02:00
Pekka Enberg
c3fb867173 core: Switch RwLock<Arc<Pager>> to ArcSwap<Pager>
We don't actually need the RwLock locking capabilities, just the ability
to swap the instance.
2025-10-24 14:10:08 +03:00
bit-aloo
64bbca9e12 Fix op_must_be_int to use strict numeric cast 2025-10-24 16:08:15 +05:30
Pekka Enberg
413c582b41 core/vdbe: Reuse cursor in op_open_write()
This optimization reuses an existing cursor when op_open_write() is
called on the same table/index (same root_page). This is safe because
the cursor position doesn't matter - op_rewind() is always called
after op_open_write() to position the cursor at the beginning of the
table/index before any operations are performed.

This change speeds up op_open_write() by avoiding unnecessary cursor
re-initialization.
2025-10-23 16:34:42 +03:00
Jussi Saurio
ae22468d8b Merge 'Order by heap sort' from Nikita Sivukhin
This PR implements simple heap-sort approach for query plans like
`SELECT ... FROM t WHERE ... ORDER BY ... LIMIT N` in order to maintain
small set of top N elements in the ephemeral B-tree and avoid sort and
materialization of whole dataset.
I removed all optimizations not related to this particular change in
order to make branch lightweight.

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

Closes #3726
2025-10-23 15:00:42 +03:00
Jussi Saurio
64560a61c3 Merge 'Support statement-level rollback via anonymous savepoints' from Jussi Saurio
## Gist
This PR implements _statement subtransactions_, which means that a
single statement within an interactive transaction can individually be
rolled back.
## Background
The default constraint violation resolution strategy in SQLite is
`ABORT`, which means to rollback the statement that caused the conflict.
For example:
```sql
CREATE TABLE t(x UNIQUE);
INSERT INTO t VALUES (1);

BEGIN;
  INSERT INTO t VALUES (2),(3); -- ok
  INSERT INTO t VALUES (4),(1); -- conflict on 1, this statement should rollback
  INSERT INTO t VALUES (5); -- ok
COMMIT; -- ok

SELECT * FROM t;
1
2
3
5
```
 So far we haven't been able to support this due to lack of support for
subtransactions, and have used the `ROLLBACK` strategy, which means to
rollback the entire transaction on any constraint error.
## Problem
Although PRIMARY KEY and UNIQUE constraints allow defining the conflict
resolution strategy (e.g. `id INTEGER PRIMARY KEY ON CONFLICT
ROLLBACK`), FOREIGN KEY violations do not support this: they always use
`ABORT` i.e. statement subtransaction rollback. For this reason alone it
is important to implement this mechanism now rather than later, since we
already have FOREIGN KEY support implemented.
## Details
This PR implements statement subtransactions with _anonymous
savepoints_. This means that whenever a statement begins, it will open a
new savepoint which will write "page undo images" into a temporary file
called a _subjournal_. Whenever the statement marks a page as dirty, it
will write the before-image of the page into the subjournal so that its
modifications can be undone in the event of an ABORT (statement
rollback).
- Right now, only anonymous savepoints are supported, so the explicit
`SAVEPOINT` syntax is not.
- Due to the above, there can be only one savepoint open per pager, and
this is enforced with assertions.
- The subjournal file is currently entirely in memory. If it were not,
we would either have to block on IO or refactor many usages of code to
account for potentially pending completions.
- Constraint errors no longer cause transactions to abort nor do they
cause the page cache to be cleared - instead, subjournaled pages will be
brought back into the page cache which effectively handles the same
behavior albeit more fine-grained.

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

Closes #3792
2025-10-23 15:00:11 +03:00
Jussi Saurio
2b73260dd9 Handle cases where DB grows or shrinks due to savepoint rollback 2025-10-22 23:40:45 +03:00
Jussi Saurio
fe51804e6b Implement crude way of making opening subtransaction conditional
We don't want something like `BEGIN IMMEDIATE` to start a subtransaction,
so instead we will open it if:

- Statement is write, AND

a) Statement has >0 table_references, or
b) The statement is an INSERT (INSERT doesn't track table_references in
   the same way as other program types)
2025-10-22 23:40:45 +03:00
Jussi Saurio
7376475cb3 Do not start statement subtransactions when MVCC is enabled
MVCC does not support statement-level rollback.
2025-10-22 23:40:45 +03:00
Jussi Saurio
d8cc57cf14 clippy: Remove unnecessary referencing 2025-10-22 23:40:45 +03:00
Jussi Saurio
086ba8c946 VDBE: begin statement subtransaction in op_transaction 2025-10-22 23:40:45 +03:00
Jussi Saurio
904cbe535d VDBE: handle subtransaction commits/aborts in op_halt 2025-10-22 23:40:45 +03:00
Jussi Saurio
ad80285437 Rename is_scope to deferred and invert respective boolean logic
Much clearer name for what it is/does
2025-10-22 23:40:44 +03:00
Jussi Saurio
d4a9797f79 Store two foreign key counters in ProgramState
1. The number of deferred FK violations when the statement started.
   When a statement subtransaction rolls back, the connection's
   deferred violation counter will be reset to this value.
2. The number of immediate FK violations that occurred during the
   statement. In practice we just need to know whether this number
   is nonzero, and if it is, the statement subtransaction will roll
   back.

Statement subtransactions will be implemented in future commits.
2025-10-22 23:40:44 +03:00
Nikita Sivukhin
91ffb4e249 Revert "avoid allocations"
This reverts commit dba195bdfa.
2025-10-22 20:21:39 +04:00
Nikita Sivukhin
53957b6d22 Revert "simplify serial_type size calculation"
This reverts commit f19c73822e.
2025-10-22 20:21:00 +04:00
Nikita Sivukhin
8e1cec5104 Revert "alternative read_variant implementation"
This reverts commit 68650cf594.
2025-10-22 19:30:43 +04:00
Pekka Enberg
5dd503b7b9 core/storage: Cache schema cookie in Pager
Every transaction was reading page 1 from the WAL to check the schema cookie
in op_transaction, causing unnecessary WAL lookups.

This commit caches the schema_cookie in Pager as AtomicU64, similar to how
page_size and reserved_space are already cached. The cache is updated when the
header is read/modified and invalidated in begin_read_tx() when WAL changes
are detected from other connections.

This matches SQLite's approach of caching frequently accessed header fields to
avoid repeated page 1 reads. Improves write throughput by 5% in our
benchmarks.
2025-10-22 16:51:15 +03:00
Nikita Sivukhin
671d266dd6 Revert "wip"
This reverts commit dd34f7fd50.
2025-10-22 11:47:46 +04:00
Nikita Sivukhin
bf77862fab Merge branch 'main' into order-by-heap-sort 2025-10-22 11:44:55 +04:00
Pekka Enberg
1aad1b224a Merge 'core/io: Make random generation deterministically simulated' from Pedro Muniz
Depends on #3584 to use the most up-to-date implementation of
`ThreadRng`
- Add `fill_bytes` method to `IO`
- use `thread_rng` instead of `getrandom`, as `getrandom` is much slower
and `thread_rng` offers enough security
- modify `exec_randomblob`, `exec_random` and random_rowid generation to
use methods from IO for determinism
- modified simulator IO to implement `fill_bytes`
This the PRNG for sqlite if someone is curious. It is similar to
`thread_rng`:
```c
/* Initialize the state of the random number generator once,
  ** the first time this routine is called.
  */
  if( wsdPrng.s[0]==0 ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
    static const u32 chacha20_init[] = {
      0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
    };
    memcpy(&wsdPrng.s[0], chacha20_init, 16);
    if( NEVER(pVfs==0) ){
      memset(&wsdPrng.s[4], 0, 44);
    }else{
      sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
    }
    wsdPrng.s[15] = wsdPrng.s[12];
    wsdPrng.s[12] = 0;
    wsdPrng.n = 0;
  }

  assert( N>0 );
  while( 1 /* exit by break */ ){
    if( N<=wsdPrng.n ){
      memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
      wsdPrng.n -= N;
      break;
    }
    if( wsdPrng.n>0 ){
      memcpy(zBuf, wsdPrng.out, wsdPrng.n);
      N -= wsdPrng.n;
      zBuf += wsdPrng.n;
    }
    wsdPrng.s[12]++;
    chacha_block((u32*)wsdPrng.out, wsdPrng.s);
    wsdPrng.n = 64;
  }
  sqlite3_mutex_leave(mutex);
```

Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #3799
2025-10-22 09:10:36 +03:00
Pere Diaz Bou
3227caaa1d Merge 'core: move BTreeCursor under MVCC cursor' from Pere Diaz Bou
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #3756
2025-10-21 19:20:49 +02:00
pedrocarlo
8c0b9c6979 add additional fill_bytes method to IO to deterministically generate
random bytes and modify random functions to use them
2025-10-21 14:10:38 -03:00
pedrocarlo
8501bc930a use workspace rand version 2025-10-21 14:10:05 -03:00
Pere Diaz Bou
ea04e9033a core/mvcc: add btree_cursor under MVCC cursor 2025-10-21 18:22:37 +02:00
PThorpe92
2fbd4b7cec Ensure op_alter_column and Func::AlterColumn are fixing table references to columns with fk's 2025-10-21 10:46:52 -04:00
Pekka Enberg
16d1398586 Merge 'Switch random blob creation to get_random' from Pedro Muniz
Also added a benchmark for inserting randomblobs. On my machine, I get
something like a 20% increase in performance.

Closes #3787
2025-10-21 16:04:55 +03:00
Pekka Enberg
6139dde081 Revert "Merge 'core/translate: fix ALTER COLUMN to propagate other constraint references' from Preston Thorpe"
This reverts commit 1151f49ff4, reversing
changes made to f4da2194f4.
2025-10-21 16:00:04 +03:00
Pekka Enberg
1151f49ff4 Merge 'core/translate: fix ALTER COLUMN to propagate other constraint references' from Preston Thorpe
closes #3666
and probably other issues i'll have to go digging through to see if
there is any others.
<img width="948" height="445" alt="image" src="https://github.com/user-
attachments/assets/2844e09b-109a-4a70-bd18-d8a814e49ea0" />
Any ALTER COLUMN stmt will now update the constraints on the table
(primary key, foreign key, unique)

Closes #3776
2025-10-21 11:53:42 +03:00
pedrocarlo
a614b51ebf change randomblob generation to use thread_rng 2025-10-21 01:41:40 -03:00
Jussi Saurio
10532544dc Fix: check deferred FK violations before committing to WAL
DEFERRED was a bit too deferred - it allowed the dirty pages to be
written out to WAL before checking for violations, resulting in the
violations effectively being committed even though the transaction
ended up aborting
2025-10-20 14:00:49 +03:00
PThorpe92
fe3a4de0ab Add TCL tests for altering columns that have foreign keys 2025-10-18 13:38:11 -04:00
PThorpe92
25aa2b7190 Properly reparse and revalidate parent and child foreign keys when altering columns 2025-10-18 13:22:48 -04:00
Nikita Sivukhin
dd34f7fd50 wip 2025-10-15 17:27:22 +04:00
Nikita Sivukhin
a1260ca8c7 implement Sequence opcodes for any type of cursors 2025-10-15 17:27:22 +04:00
Nikita Sivukhin
68650cf594 alternative read_variant implementation
- it faster in benchmark (who knows why)
- also seems bit faster for some my query
- let's test on CI
2025-10-15 17:27:22 +04:00
Nikita Sivukhin
f19c73822e simplify serial_type size calculation 2025-10-15 17:27:22 +04:00
Nikita Sivukhin
a6a5ffd821 move read_varint_fast closer to the read_varint impl 2025-10-15 17:27:22 +04:00
Nikita Sivukhin
dba195bdfa avoid allocations 2025-10-15 17:27:22 +04:00
Jussi Saurio
4e6f373e3d Merge 'Fix: Evaluating expression in LIMIT and OFFSET clauses.' from
Closes #3687 .
Previously, the `try_fold_expr_to_i64` function casted `NULL` as `0`
when evaluating expressions in `LIMIT` or `OFFSET` clauses. I removed
this function since evaluating the expression directly and relying on
the MustBeInt operation for casting seems to handle everything.

Closes #3695
2025-10-15 10:36:36 +03:00
Jussi Saurio
25cf56b8e8 Fix expected error message 2025-10-15 09:41:44 +03:00
Jussi Saurio
2791f2f479 Fix change counter incrementation
We merged two concurrent fixes to `nchange` handling last night and
AFAICT the fix in #3692 was incorrect because it doesn't count UPDATEs
in cases where the original row was DELETEd as part of the UPDATE
statement.

The correct fix was in 87434b8
2025-10-15 08:51:27 +03:00