Commit Graph

6001 Commits

Author SHA1 Message Date
Nikita Sivukhin
39daf6df37 ask agent to rewrite compile-heavy function 2025-11-09 15:15:45 +04:00
Pekka Enberg
23be2b2787 Merge 'Stop blob json parsing at null terminator' from Duy Dang
Close #3912

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

Closes #3915
2025-11-09 10:03:56 +02:00
RS2007
3a562f734c feat: alter table disallow generated columns, support foreign keys for alter table 2025-11-08 13:45:17 +05:30
PThorpe92
dd2e3e8e16 Fix clippy warning 2025-11-07 20:04:57 -05:00
PThorpe92
a012e98bfa core/translate remove unused ParamState and some minor refactoring 2025-11-07 19:18:10 -05:00
Pekka Enberg
a6593d109e Merge 'Toy index improvements' from Nikita Sivukhin
This PR implements more sophisticated algorithm in the toy vector sparse
index: now we enumerate components based on the frequency (in order to
check unpopular "features" first) and also estimate length threshold
which can give us better results compared with current top-k set.
Also, this PR adds optional `delta` parameter which can enable
approximate search which will return results with score not more than
`delta` away from the optimal.
In order to implement this index method - index code were slightly
adjusted in order to allow to store some non-key payload in the index
rows. So, now index can hold N columns where first K <= N columns will
be used as identity (before that K always was equal to N).

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

Closes #3862
2025-11-07 08:29:47 +02:00
Preston Thorpe
4e8b4c96d3 Merge 'use dyn DatabaseStorage instead of DatabaseFile' from Nikita Sivukhin
Partial sync for sync engine will need to implement its own version of
`DatabaseStorage` which willl load database pages on demand

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

Closes #3922
2025-11-06 15:11:13 -05:00
Preston Thorpe
29c5271c44 Merge 'Prevent DROP TABLE when table is referenced by foreign keys' from Joao Faria
## Related issue
- closes #3885
## Description
Add a check to reject dropping a table when PRAGMA foreign_keys=ON and
the table is referenced by foreign keys

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

Closes #3913
2025-11-06 15:10:05 -05:00
Preston Thorpe
b037941b01 Merge 'core/vdbe Handle renaming child FK definitions in rename table stmt' from Preston Thorpe
closes https://github.com/tursodatabase/turso/issues/3886

Closes #3904
2025-11-06 13:27:41 -05:00
Nikita Sivukhin
7294ef347f fix tests 2025-11-06 17:45:12 +04:00
Nikita Sivukhin
da61fa32b4 use dyn DatabaseStorage instead of DatabaseFile 2025-11-06 17:42:03 +04:00
Nikita Sivukhin
68a4c90446 fix fmt and test 2025-11-05 20:53:34 +04:00
Nikita Sivukhin
a64aef780d Merge branch 'main' into toy-index-improvements 2025-11-05 20:48:16 +04:00
Nikita Sivukhin
8c449c2ffa rename scratch -> inverted index 2025-11-05 20:47:58 +04:00
Nikita Sivukhin
fe974dd414 fix slice operation implementation 2025-11-05 20:44:43 +04:00
Nikita Sivukhin
fb63a5a3ff final adjustment to align implementation with blog post 2025-11-05 20:44:11 +04:00
Duy Dang
8fba4659c8 Stop blob json parsing at null terminator 2025-11-04 23:04:33 +07:00
joao.faria
2ba643cd68 fix: prevent DROP TABLE when table is referenced by foreign keys
Add foreign key constraint check in translate_drop_table to reject
dropping tables that are referenced by foreign keys when
PRAGMA foreign_keys=ON
2025-11-04 12:32:19 -03:00
Duy Dang
d4b874cc40 Fix EXISTS on LEFT JOIN null rows 2025-11-04 22:01:18 +07:00
PThorpe92
c5a3e590f7 Fix rewriting sql to persist for foreign keys in alter table func 2025-11-03 09:47:28 -05:00
PThorpe92
ef24911824 Handle renaming child foreign keys on op_rename_table 2025-11-03 09:47:28 -05:00
Pekka Enberg
2bf5eb84cf Merge 'Prevent misuse of subqueries that return multiple columns' from Jussi Saurio
Closes #3892
Closes #3888
Stuff like:
```sql
turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select case (select y, z from t2) when 1 then 'one' else 'other' end from t1;
  × Parse error: base expression in CASE must return 1 value

turso>     create table t(x, y);
    insert into t values (1, 2);
    select (select x, y from t) as result;
  × Parse error: result column must return 1 value, got 2

turso>     create table t1(x,y);
    create table t2(y);
    insert into t1 values (1,1);
    insert into t2 values (1);
    select * from t2 where y = (select x,y from t1);
  × Parse error: all arguments to binary operator = must return the same number of
  │ values. Got: (1) = (2)

turso>     create table orders(customer_id, amount);
    create table thresholds(min_amount, max_amount);
    insert into orders values (100, 50), (100, 150);
    insert into thresholds values (100, 200);
    select customer_id, sum(amount) as total 
    from orders 
    group by customer_id 
    having total > (select min_amount, max_amount from thresholds);
  × Parse error: all arguments to binary operator > must return the same number of
  │ values. Got: (1) > (2)

turso>     create table items(id);
    create table config(max_results, other_col);
    insert into items values (1), (2), (3);
    insert into config values (2, 3);
    select * from items limit (select max_results, other_col from config);
  × Parse error: limit expression must return 1 value, got 2

turso>     create table items(id);
    create table config(skip_count, other_col);
    insert into items values (1), (2), (3);
    insert into config values (1, 2);
    select * from items limit 1 offset (select skip_count, other_col from config);
  × Parse error: offset expression must return 1 value, got 2

turso>     create table items(id, name);
    create table sort_order(priority, other_col);
    insert into items values (1, 'a'), (2, 'b');
    insert into sort_order values (1, 2);
    select * from items order by (select priority, other_col from sort_order);
  × Parse error: order by expression must return 1 value, got 2

turso>     create table sales(product_id, amount);
    create table grouping(category, other_col);
    insert into sales values (1, 100), (2, 200);
    insert into grouping values (1, 2);
    select sum(amount) from sales group by (select category, other_col from grouping);
  × Parse error: group by expression must return 1 value, got 2

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select case when (select y, z from t2) then 'yes' else 'no' end from t1;
  × Parse error: when expression in CASE must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select case when x = 1 then (select y, z from t2) else 0 end from t1;
  × Parse error: then expression in CASE must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select case when x = 2 then 0 else (select y, z from t2) end from t1;
  × Parse error: else expression in CASE must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select max((select y, z from t2)) from t1;
  × Parse error: argument 0 to function call max must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select x + (select y, z from t2) from t1;
  × Parse error: all arguments to binary operator + must return the same number of
  │ values. Got: (1) + (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (5);
    insert into t2 values (1, 2);
    select * from t1 where x between (select y, z from t2) and 10;
  × Parse error: all arguments to binary operator <= must return the same number of
  │ values. Got: (2) <= (1)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select cast((select y, z from t2) as integer) from t1;
  × Parse error: argument to CAST must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values ('a', 'b');
    select (select y, z from t2) collate nocase from t1;
  × Parse error: argument to COLLATE must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select * from t1 where (select y, z from t2) is null;
  × Parse error: all arguments to binary operator IS must return the same number of
  │ values. Got: (2) IS (1)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select * from t1 where (select y, z from t2) not null;
  × Parse error: argument to NOT NULL must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values ('a', 'b');
    select * from t1 where (select y, z from t2) like 'a%';
  × Parse error: left operand of LIKE must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select -(select y, z from t2) from t1;
  × Parse error: argument to unary operator - must return 1 value. Got: (2)

turso>     create table t1(x);
    create table t2(y, z);
    insert into t1 values (1);
    insert into t2 values (1, 2);
    select abs((select y, z from t2)) from t1;
  × Parse error: argument 0 to function call abs must return 1 value. Got: (2)
  ```

Closes #3906
2025-11-03 13:06:38 +02:00
Pekka Enberg
9aae220509 Merge 'Optimize and refactor schema::Column type' from Preston Thorpe
closes https://github.com/tursodatabase/turso/issues/3773
## Before
```rust
#[derive(Debug, Clone)]
pub struct Column {
    pub name: Option<String>,
    pub ty: Type,
    // many sqlite operations like table_info retain the original string
    pub ty_str: String,
    pub primary_key: bool,
    pub is_rowid_alias: bool,
    pub notnull: bool,
    pub default: Option<Box<Expr>>,
    pub unique: bool,
    pub collation: Option<CollationSeq>,
    pub hidden: bool,
}
```
obviously not ideal. so lets pack `type`, `hidden`, `primary_key`,
`is_rowid_alias`, `notnull` and `collation` into a u16.
## After:
```rust
#[derive(Debug, Clone)]
pub struct Column {
    pub name: Option<String>,
    pub ty_str: String,
    pub default: Option<Box<Expr>>,
    raw: u16,
}
```
Also saw a place to replace a `Mutex<Enum>` with `AtomicEnum`, so I
snuck that in here too

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

Closes #3905
2025-11-03 13:05:35 +02:00
Jussi Saurio
1c2a8e62ca Fix: return error on provided insert column count mismatch 2025-11-03 11:41:50 +02:00
Jussi Saurio
005d922ab4 Fix: prevent misuse of subqueries that return multiple columns 2025-11-03 11:04:09 +02:00
PThorpe92
481d86f567 Optimize and refactor schema::Column type 2025-11-02 20:46:02 -05:00
Pekka Enberg
72edc6d758 Merge 'Clean up Connection::from_uri() by using DatabaseOpts' from Rohith Suresh
Fixes #3900
Migrating the `from_uri` function to use `DatabaseOpts`

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

Closes #3901
2025-11-02 16:55:44 +02:00
pedrocarlo
28c52cdf09 pass the left select in compound select to correctly choose the collation sequence 2025-11-02 11:26:48 -03:00
RS2007
60cbc6d8ea migrating from_uri to database opts 2025-11-02 16:28:22 +05:30
Pekka Enberg
913b7ac600 core: Disable autovacuum by default
People have discovered various bugs in autovacuum so let's disable it by
default for now.
2025-11-02 12:09:21 +02:00
PThorpe92
23496f0bea Fix incorrect unreachable precondition for affinity char in op_seek_rowid 2025-11-01 20:43:44 -04:00
Pekka Enberg
c091f94de8 Merge 'Fix INSERT UNION ALL' from Duy Dang
Close #3849
Close #3855

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

Closes #3877
2025-11-01 11:12:38 +02:00
Pekka Enberg
7283f35a29 Merge 'Fix LEFT JOIN subqueries reusing stale right-side values' from Duy Dang
Close #3867

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

Closes #3874
2025-11-01 11:12:24 +02:00
Duy Dang
e0f6b7cffe Fix INSERT handling for compound VALUES sources 2025-11-01 02:27:42 +07:00
Duy Dang
4b18e3bab5 Fix VALUES UNION ALL register reuse during INSERTs 2025-11-01 02:01:30 +07:00
Duy Dang
3ee47a2c3c Fix LEFT JOIN subqueries reusing stale right-side values 2025-11-01 01:24:31 +07:00
RS2007
7fff8daaa5 Fixing clippy error 2025-10-31 23:14:08 +05:30
RS2007
1f576593ec adding duplicate cte name checks in planner.rs 2025-10-31 23:14:08 +05:30
Nikita Sivukhin
20919212f9 fix clippy 2025-10-31 14:30:07 +04:00
Nikita Sivukhin
20ba6990a9 ignore "virtual" index entries corresponding to the index_methods from integrity check 2025-10-31 14:25:59 +04:00
Nikita Sivukhin
c2e8f77ea1 fix bug in the toy vector index in case when seek target located in the internal node of index btree 2025-10-31 14:23:56 +04:00
Duy Dang
733dc762ed Fix self-insert SUM when table uses INTEGER PRIMARY KEY 2025-10-31 03:34:10 +07:00
Nikita Sivukhin
476de1805a adjust bounds 2025-10-29 22:49:17 +04:00
Nikita Sivukhin
c187595492 finalize improvements for toy index 2025-10-29 22:15:09 +04:00
Pekka Enberg
eaff2d135f Merge 'Fix database state going back in time after sync' from Nikita Sivukhin
This PR fixes sync engine bug which leads to the state of db going back
in time.
The mistake was made in the pull operation which before fetched
information about last commited changes to the remote separately. This
crates a problem since pull already works with fixed WAL updates
received earlier from remote - and this WAL update can be inconsistent
with more fresh value of last_change_id fetched from remote.
The fix is to use only WAL update and "extract" necessary information
from it. In order to do that sync now read meta sync table while pull
operation is in progress (at the moment when local changes are rolled
back and remote changes already applied) and do not use any external
source to consume that information.
Also, this PR fixes bug in the JS tursodatabase client and reset
statement in the finally block opposed to the previous approach to reset
statement at the beginning. The problem with previous approach were in
cases when client do not fully consumed the statement (e.g. abort
iteration and take only one row) in which case the statement will be
kept active and can prevent another write transaction from starting or
just occupy place as a read transaction.

Closes #3860
2025-10-29 17:53:45 +02:00
Nikita Sivukhin
a69dc51b3c adjust assertions in core in order to store auxilary data in the index row 2025-10-29 18:11:06 +04:00
Nikita Sivukhin
a440102b9b add components stats table 2025-10-29 18:10:48 +04:00
Jussi Saurio
6cf2072b51 translate: disallow correlated subqueries in HAVING and ORDER BY
These are supported by SQLite, but we cannot handle them correctly yet.
2025-10-29 15:37:19 +02:00
Nikita Sivukhin
4c98861590 adjust logs 2025-10-29 16:24:05 +04:00
Jussi Saurio
96990e1168 Merge 'Stmt reset cursors' from Nikita Sivukhin
This PR reset cursor state in the `stmt.reset()` method because under
the hood statement caches some BTree state which can be no longer valid
at the moment of next statement run.

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

Closes #3859
2025-10-29 14:04:52 +02:00