Commit Graph

8400 Commits

Author SHA1 Message Date
PThorpe92
6cbc8ff868 Replace values with constants 2025-08-04 15:14:06 -04:00
pedrocarlo
7bf35bcaf4 remove rexpect crate 2025-08-04 15:59:15 -03:00
PThorpe92
73d1fdef14 Fix and change bitmap, apply suggestions and add some optimizations 2025-08-04 14:58:58 -04:00
PThorpe92
f4197f1eb5 change debug assertions to turso asserts 2025-08-04 14:55:48 -04:00
PThorpe92
54696d2f0d Add additional test for edge cases 2025-08-04 14:55:48 -04:00
PThorpe92
5378195ad6 Add page bitmap to storage mod.rs 2025-08-04 14:55:48 -04:00
PThorpe92
3e30335ea5 Add tests for PageBitmap 2025-08-04 14:55:48 -04:00
PThorpe92
7b1f908c00 Add PageBitmap for use with arena page allocator 2025-08-04 14:55:48 -04:00
pedrocarlo
ebe6aa0d28 adjust cfg for unix and linux IO 2025-08-04 15:49:52 -03:00
pedrocarlo
f2d84a534c adjust clear_overflow_pages 2025-08-04 15:28:06 -03:00
Piotr Rzysko
521eb2368e Return error when no valid plan exists
Replace panics with proper errors when a valid plan does not exist.
Currently, this never happens because a naive plan is always available.
However, once virtual tables are integrated into the planner, it may
occur—for example, when table-valued function arguments are column
references, and the function cannot be placed in the join order so that
its arguments can be evaluated.

Although this change is effectively a no-op for now, it is extracted
into a separate commit to avoid polluting the one that introduces
virtual table integration with the planner.
2025-08-04 20:27:23 +02:00
Piotr Rzysko
c80cd370cb Remove cost_upper_bound_ordered
It was redundant, as it was always equal to cost_upper_bound.
2025-08-04 20:27:23 +02:00
Piotr Rzysko
718598eab8 Introduce scan type
Different scan parameters are required for different table types.
Currently, index and iteration direction are only used by B-tree tables,
while the remaining table types don’t require any parameters. Planning
access to virtual tables, however, will require passing additional
information from the planner, such as the virtual table index (distinct
from a B-tree index) and the constraints that must be forwarded to the
`filter` method.
2025-08-04 20:27:22 +02:00
Piotr Rzysko
9167b30c7c Introduce AccessMethodParams
Previously, AccessMethod stored fields like `iter_dir`, `index`, and
`constraint_refs` directly, but these only applied to BTree tables.
Other table types (virtual tables, subqueries) either ignored these
fields or required different parameters entirely.

This change prepares the planner to handle virtual table access methods
with their own specialized parameters.
2025-08-04 20:23:44 +02:00
Piotr Rzysko
4166735953 Return error when start argument is missing for generate_series
This matches SQLite’s behavior and will help in the future to
differentiate between an invalid function invocation (missing argument,
not provided by the user) and an invalid combination of constraints
proposed by the planner.

No new integration tests are added, since this case was already covered
by the `filter` method. With the ability to return result codes from
`best_index`, we can now detect this error earlier.
2025-08-04 20:18:44 +02:00
Piotr Rzysko
61234eeb19 Add ResultCode to best_index result
The `best_index` implementation now returns a ResultCode along with the
IndexInfo. This allows it to signal specific outcomes, such as errors or
constraint violations. This change aligns better with SQLite’s xBestIndex
contract, where cases like missing constraints or invalid combinations of
constraints must not result in a valid plan.
2025-08-04 20:18:44 +02:00
Piotr Rzysko
6a4cf02a90 Fix computation of argv_index in best_index
The `filter` methods for extensions affected by this fix expect arguments
to be passed in a specific order. For example, `generate_series` assumes
that if the `start` argument exists, it is always passed to `filter`
first. If `start` does not exist, then `stop` is passed first — but
`stop` must never come before `start`.

Previously, this was not guaranteed: `best_index` relied on constraints
being passed in the order matching `filter`'s expectations.
2025-08-04 19:38:45 +02:00
Piotr Rzysko
c465ce6e7b Clarify semantics of argv_index
Extend the documentation of `argv_index` and add validations enforcing
the requirements it must meet.
2025-08-04 19:31:18 +02:00
Piotr Rzysko
b0460a589f Ensure argv_index is either None or >= 1
Previously, there were two ways to indicate that a constraint should not
be passed to the filter function: setting `argv_index` to `None` or to
a value less than 1. This was redundant, so now only `None` is used.
2025-08-04 19:27:53 +02:00
Piotr Rzysko
79e166d722 Implement xBestIndex for kvstore.c
This is to match Rust kv_store implementation.
2025-08-04 19:25:11 +02:00
Piotr Rzysko
c6f398122d Add validation for constraint usage length returned by best_index
Additional changes:
- Update IndexInfo documentation to clarify that constraint_usages must
  have exact 1:1 correspondence with input ConstraintInfo array. The code
  translating constraints into VFilter arguments heavily relies on this.
- Fix best_index implementation in test extension to comply with new
  validation requirements by returning usage entry for each constraint
2025-08-04 19:25:10 +02:00
pedrocarlo
718ad5e7fd btree_destroy retunrn IO 2025-08-04 14:12:51 -03:00
pedrocarlo
e0978844e6 adjust integrity_check 2025-08-04 14:12:50 -03:00
Nikita Sivukhin
443c177d13 fix test for windows 2025-08-04 21:00:29 +04:00
Jussi Saurio
7045d44fdc Merge 'fix/wal: remove start_pages_in_frames_hack to prevent checkpoint data loss' from Jussi Saurio
Closes #2421
## Background
We have some kind of transaction-local hack (`start_pages_in_frames`)
for bookkeeping how many pages are currently in the in-memory WAL frame
cache, I assume for performance reasons or whatever.
`wal.rollback()` clears all the frames from `shared.frame_cache` that
the rollbacking tx is allowed to clear, and then truncates
`shared.pages_in_frames` to however much its local
`start_pages_in_frames` value was.
## Problem
In `complete_append_frame`, we check if `frame_cache` has that key
(page) already, and if not, we add it to `pages_in_frames`.
However, `wal.rollback()` never _removes_ the key (page) if its value is
empty, so we can end up in a scenario where the `frame_cache` key for
`page P` exists but has no frames, and so `page P` does not get added to
`pages_in_frames` in `complete_append_frame`.
This leads to a checkpoint data loss scenario:
- transaction rolls back, has start_pages_in_frames=0, so truncates
shared pages_in_frames to an empty vec. let's say `page P` key in
`frame_cache` still remains but it has no frames.
- The next time someone commits a frame for `page P`, it does NOT get
added to `pages_in_frames` because `frame_cache` has that key (although
the value vector is empty)
- At some point, a checkpoint checkpoints `n` frames, but since
`pages_in_frames` does not have `page P`, it doesn't actually checkpoint
it and all the "checkpointed" frames are simply thrown away
- very similar to the scenario in #2366
## Fix
Remove the `start_pages_in_frames` hack entirely and just make
`pages_in_frames` effectively the same as `frame_cache.keys`. I think we
could also just get rid of `pages_in_frames` and just use
`frame_cache.contains_key(p)` but maybe Pere can chime in here

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

Closes #2422
2025-08-04 19:49:55 +03:00
pedrocarlo
aa05616845 fix tests 2025-08-04 13:08:30 -03:00
pedrocarlo
5f52d9b6b4 state machine for count 2025-08-04 13:00:43 -03:00
pedrocarlo
1585d5cbee state machine for 'next' and prev 2025-08-04 13:00:43 -03:00
pedrocarlo
f1df9a909e state machine for 'rewind' 2025-08-04 12:59:52 -03:00
pedrocarlo
e9c3f0d55b disable schema reprepare for MVCC 2025-08-04 12:32:34 -03:00
pedrocarlo
0e3e64878c workaround the fact that to reparse schema we have to avoid falling into a reprepared statement loop 2025-08-04 12:32:34 -03:00
pedrocarlo
266a7e1c66 do not error in op_transaction if page 1 was not allocated 2025-08-04 12:32:34 -03:00
pedrocarlo
f0ff85a43c add test 2025-08-04 12:32:34 -03:00
pedrocarlo
0779c23bbf fix merge conflicts 2025-08-04 12:32:34 -03:00
pedrocarlo
d2019e95f3 pass schema to epilogue for schema_version checking + do not Pragma Schema Version in open_with_flags to avoid infinite loop in reprepare. Just access the database header directly 2025-08-04 12:32:34 -03:00
pedrocarlo
736748cdf7 Simplify program epilogue by tracking the transaction mode and rollback status in the ProgramBuilder and then calling epilogue just once 2025-08-04 12:32:34 -03:00
pedrocarlo
c567636deb Adjust Transaction OpCode to accept schema cookie + check if cookie changed 2025-08-04 12:32:34 -03:00
pedrocarlo
f8eb4ba14d implement reprepare for statements 2025-08-04 12:32:34 -03:00
pedrocarlo
cffafb8333 remove Rc from Program 2025-08-04 12:32:34 -03:00
pedrocarlo
54636241c2 store Sql String inside Program for reprepare 2025-08-04 12:32:34 -03:00
pedrocarlo
94c25893ae add SchemaUpdated error variant 2025-08-04 12:32:34 -03:00
Jussi Saurio
506bb5f67f Merge 'Direct schema mutation – add instruction' from Levy A.
Resolves #2378.
```
`ALTER TABLE _ RENAME TO _`/limbo_rename_table/
                        time:   [15.645 ms 15.741 ms 15.850 ms]
Found 12 outliers among 100 measurements (12.00%)
  8 (8.00%) high mild
  4 (4.00%) high severe
`ALTER TABLE _ RENAME TO _`/sqlite_rename_table/
                        time:   [34.728 ms 35.260 ms 35.955 ms]
Found 15 outliers among 100 measurements (15.00%)
  8 (8.00%) high mild
  7 (7.00%) high severe
  ```
<img width="1000" height="199" alt="image" src="https://github.com/user-
attachments/assets/ad943355-b57d-43d9-8a84-850461b8af41" />

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

Closes #2399
2025-08-04 16:55:38 +03:00
Jussi Saurio
1813171b91 Merge 'Use pwrite for single buffer pwritev call in unix IO' from Preston Thorpe
Closes #2416
2025-08-04 16:52:14 +03:00
Jussi Saurio
5a06411ce6 Merge 'fix/core/translate: ALTER TABLE DROP COLUMN: ensure schema cookie is updated even when target table is empty' from Jussi Saurio
Closes #2431
Discovered while fuzzing #2086
## What
We update `schema_version` whenever the schema changes
## Problem
Probably unintentionally, we were calling `SetCookie` in a loop for each
row in the target table, instead of only once at the end. This means 2
things:
- For large `n`, this is a lot of unnecessary instructions
- For `n==0`, `SetCookie` doesn't get called at all -> the schema won't
get marked as having been updated -> conns can operate on a stale schema
## Fix
Lift `SetCookie` out of the loop

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

Closes #2432
2025-08-04 16:51:24 +03:00
Nikita Sivukhin
33b814054b fix tests for windows 2025-08-04 17:37:22 +04:00
Pere Diaz Bou
f3079347e7 core/mvcc: op.eq_only 2025-08-04 15:27:59 +02:00
Nikita Sivukhin
9694366645 add one more assert 2025-08-04 17:23:34 +04:00
Nikita Sivukhin
76bdf0c1ab small fixes 2025-08-04 17:02:53 +04:00
Nikita Sivukhin
2e23230e79 extend raw WAL API with few more methods
- try_wal_watermark_read_page - try to read page from the DB with given WAL watermark value
- wal_changed_pages_after - return set of unique pages changed after watermark WAL position
2025-08-04 16:55:50 +04:00
Jussi Saurio
8a1723b3c8 fix/core/translate: ALTER TABLE DROP COLUMN: ensure schema cookie is updated even when target table is empty 2025-08-04 15:05:00 +03:00