Commit Graph

10075 Commits

Author SHA1 Message Date
Diego Reis
da323fa0c4 Some clean ups and correctly working on WHERE clauses 2025-10-09 11:57:15 -03:00
Diego Reis
79958f468d Add jump_target_null to ConditionMetadata
It's kinda make sense, conditions can be evaluated into 3 values: false,
true and null. Now we handle that.
2025-10-09 11:56:14 -03:00
Diego Reis
52ed0f7997 Add in expr optimization at the parser level instead of translation.
lhs IN () and lhs NOT IN () can be translated to false and true.
2025-10-09 11:56:14 -03:00
Diego Reis
70fc509046 First step to fix 3277
This follows almost step by step sqlite's functions, and indeed it's
correct. But still have to translate some of this logic to our current
semantics
2025-10-09 11:56:14 -03:00
Jussi Saurio
7948259d37 Merge 'optimizer: optimize range scans to use upper and lower bounds more efficiently' from Jussi Saurio
Made a new PR based on @sivukhin 's PR #2869 that had a lot of
conflicts. You can check out the PR description from there.
## The main idea is:
Before, if we had an index on `x` and had a query like `WHERE x > 100
and x < 200`, the plan would be something like:
```
- Seek to first row where x > 100
- Then, for every row, discard the row if x >= 200
```
This is highly wasteful in cases where there are a lot of rows where `x
>= 200`. Since our index is sorted on `x`, we know that once we hit the
_first_ row where `x >= 200`, we can stop iterating entirely.
So, the new plan is:
```
- Seek to first row where x > 100
- Then, iterate rows until x >= 200, and then stop
```
This also improves the situation for multi-column indexes. Imagine index
on `(x,y)` and a condition like `WHERE x = 100 and y > 100 and y < 200`.
Before, the plan was:
```
- Seek to first row where x=100 and y > 100
- Then, iterate rows while x = 100 and discard the row if y >= 200
- Stop when x > 100
```
This also suffers from a problem where if there are a lot of rows where
`x=100` and `y >= 200`, we go through those rows unnecessarily. The new
plan is:
```
- Seek to first row where x=100 and y > 100
- Then, iterate rows while x = 100 and y < 200
- Stop when either x > 100 or y >= 200
```
Which prevents us from iterating rows like `x=100, y = 666`
unnecessarily because we know the index is sorted on `(x,y)` - once we
hit any row where `x>100` OR `x=100, y >= 200`, we can stop.

Closes #3644
2025-10-09 14:47:15 +03:00
Jussi Saurio
f9f8eda3c3 Merge 'add Calendar-based timezone conversion support in JDBC4ResultSet' from 김민석
## Summary
Implemented Calendar-based Date/Time/Timestamp getter methods in
JDBC4ResultSet to support timezone conversions.
## Changes
- Implemented `getDate(int, Calendar)` and `getDate(String, Calendar)`
- Implemented `getTime(int, Calendar)` and `getTime(String, Calendar)`
- Implemented `getTimestamp(int, Calendar)` and `getTimestamp(String,
Calendar)`
- Fixed timezone conversion logic (changed from subtraction to addition)
- Added comprehensive test cases for all implemented methods
Test Results
- All tests passed successfully
- New tests validate timezone conversion with UTC and Seoul (UTC+9)

Reviewed-by: Kim Seon Woo (@seonWKim)

Closes #3607
2025-10-09 12:52:09 +03:00
Jussi Saurio
e726803ab4 Merge 'translate: make bind_and_rewrite_expr() reject unbound identifiers if no referenced tables exist' from Jussi Saurio
Before, we just skipped evaluating `Id`, `Qualified` and
`DoublyQualified` if `referenced_tables` was `None`, leading to shit
like #3621. Let's eagerly return `"No such column"` parse errors in
these cases instead, and punch exceptions for cases where that doesn't
cleanly work
Top tip: use `Hide whitespace` toggle when inspecting the diff of this
PR
Closes #3621

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

Closes #3626
2025-10-09 12:45:16 +03:00
Jussi Saurio
ab88e7c206 Merge 'don't allow duplicate col names in create table' from Pavan Nambi
closes https://github.com/tursodatabase/turso/issues/3637

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

Closes #3641
2025-10-09 12:44:28 +03:00
Jussi Saurio
190e6f2e93 Merge 'Simulator: ignore Property::AllTableHaveExpectedContent when counting stats' from Pedro Muniz
`Property::AllTableHaveExpectedContent` adds a lot of simple Select full
table scans to check the DB state. These statements were being counted
in `InteractionStats`. The stats are used to calculate the Remaining
queries we need to make. By not counting these simple checks we allow
the simulator to create more meaningful interactions.

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

Closes #3643
2025-10-09 12:43:56 +03:00
Jussi Saurio
a76cdb83c5 fuzz: sometimes add another condition on the same column to exercise index range queries 2025-10-09 12:34:52 +03:00
Nikita Sivukhin
4313f57ecb Optimize range scans 2025-10-09 11:47:41 +03:00
Pavan-Nambi
414f92d0a0 go back to for loop
cleanup

clippy
2025-10-09 13:50:45 +05:30
Jussi Saurio
acb3c97fea Merge 'When pwritev fails, clear the dirty pages' from Pedro Muniz
If we don't clear the dirty pages, we will initiate a rollback. In the
rollback, we will attempt to clear the whole page cache, but it will
then panic because there will still be dirty pages from the failed
writev

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

Closes #3189
2025-10-09 10:38:47 +03:00
Pekka Enberg
e3144a74aa Merge 'Add Nightly versions of benchmarks that run on Nyrkiö runners' from Henrik Ingo
Nyrkiö is piloting a GitHub Runner service, and congratulations, you are
the pilot customer! In order to reduce the risk somewhat, we'll
introduce this as a parallel workflow, so the existing benchmarks will
continue to run on the regular runners and they won't have any
discontinuity in their results because of this. Also since these runners
are actually a bit more expensive, we can manage the cost by only
running them periodically. Similarly, this allows us to fine tune the
Nyrkiö instance size, for example to have an EBS disk that is the
optimal size and IOPS configuration, so you don't pay for empty space.
I will show up in discord to discuss.
And congratulations on the beta release by the way! I worked hard to get
this done for your beta period, let's hope it works now.

Closes #3619
2025-10-09 10:09:57 +03:00
pedrocarlo
f54b1132ca ignore Property::AllTableHaveExpectedContent when counting stats, so we can generate more interesting interactions 2025-10-09 01:20:03 -03:00
Pavan-Nambi
f0d9ead19f add more tests
refactor and use sort_unstable_by_key
2025-10-09 08:28:59 +05:30
Pavan-Nambi
f138448da2 don't allow duplicate col names in create table 2025-10-09 08:09:31 +05:30
kimminseok
76320e82db lint issues with spotless 2025-10-09 11:19:29 +09:00
kimminseok
f9e95697c8 handle empty string in findColumn() method 2025-10-09 10:46:27 +09:00
kimminseok
76b57e5d0c correctly detect empty ResultSet in next() 2025-10-09 10:29:46 +09:00
Pere Diaz Bou
f06ee571be Merge 'MVCC: Don't modify the row version chain on rollback' from Duy Dang
Rollback shouldn't modify the row version chain. This is crucial for
implementing a Non-blocking row version chain in #3499

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

Closes #3583
2025-10-08 18:00:02 +02:00
Pekka Enberg
08cf663d7b Merge 'Add support for sqlite_version() star syntax' from Glauber Costa
SQLite surprisingly supports this:
select sqlite_version(*);
this gets translated at the parser level to sqlite_version(), and it
works for all functions that take 0 arguments.
Let's be compatible with SQLite and support the same thing.

Closes #3630
2025-10-08 17:41:27 +03:00
Pekka Enberg
3c525219a2 Merge 'mvcc: Disable automatic checkpointing by default' from Pekka Enberg
MVCC checkpointing currently prevents concurrent writes so disable it by
default while we work on it.

Closes #3631
2025-10-08 17:09:37 +03:00
Duy Dang
4fe3282d8e Fix missing let from merge 2025-10-08 21:06:13 +07:00
Duy Dang
f7b3033a09 Merge branch 'main' into rollback-fix 2025-10-08 20:56:54 +07:00
Pekka Enberg
17a578a496 bindings/rust: Tokio is not required
The bindings use just async Rust so any async runtime should work.
2025-10-08 11:47:39 +03:00
Pekka Enberg
d8fc548b7f Merge 'Fix rusqlite compatibility claim' from Dave Warnock
Make it clear that the Turso rust binding is not a drop-in replacement
for rusqlite. Turso is async and rusqlite isn't

Closes #3633
2025-10-08 11:47:10 +03:00
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
Dave Warnock
e28ece6950 Update Doc regarding rusqlite compatibility
Make it clear that it's not a drop in replacement for rusqlite as that
isn't async
2025-10-08 08:03:43 +01:00
Pekka Enberg
f92d19ddeb Tweak README a bit 2025-10-08 09:20:44 +03:00
Pekka Enberg
94c343770d mvcc: Disable automatic checkpointing by default
MVCC checkpointing currently prevents concurrent writes so disable it by
default while we work on it.
2025-10-08 09:14:55 +03:00
Glauber Costa
111b6fcb81 support the same syntax as sqlite for version function
SQLite surprisingly supports this:

select sqlite_version(*);

this gets translated at the parser level to sqlite_version(), and it
works for all functions that take 0 arguments.

Let's be compatible with SQLite and support the same thing.
2025-10-07 23:00:56 -07:00
Jussi Saurio
f5766379ce Allow unbound identifiers specifically for INSERT ... ON CONFLICT
the binding for the ON CONFLICT clause is done later.
2025-10-08 09:00:41 +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
23248d9001 Add UPSERT to fuzzing for FK 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
Jussi Saurio
a343dacaaf translate: make bind_and_rewrite_expr() reject identifiers if no referenced tables exist 2025-10-07 23:34:26 +03:00
PThorpe92
16d19fd39e Add tcl tests for foreign keys 2025-10-07 16:28:04 -04:00
PThorpe92
2db18f8230 Add fk_fuzzing sql file to .gitignore 2025-10-07 16:28:04 -04:00
PThorpe92
346e6fedfa Create ForeignKey, ResolvedFkRef types and FK resolution 2025-10-07 16:27:49 -04:00
Henrik Ingo
223b060a6a Increase instance size to avoid OOM 2025-10-07 23:26:19 +03: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
PThorpe92
b40e784903 Update COMPAT.md, add fk related opcodes 2025-10-07 16:22:15 -04:00