Commit Graph

809 Commits

Author SHA1 Message Date
Jussi Saurio
0b17957f4e Merge 'Implement normal views' from Glauber Costa
Now that we actually implemented the statement parsing around views,
implementing normal SQLite views is relatively trivial, as they are just
an alias to a query.
We'll implement them now to get them out of the way, and then I'll go
back to DBSP

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

Closes #2591
2025-08-14 10:54:46 +03:00
Preston Thorpe
78abe72762 Merge 'fix: Handle fresh INSERTs in materialized view incremental maintenance' from Glauber Costa
The op_insert function was incorrectly trying to capture an "old record"
for fresh INSERT operations when a table had dependent materialized
views. This caused a "Cannot delete: no current row" error because the
cursor wasn't positioned on any row for new inserts.
The issue was introduced in commit f38333b3 which refactored the state
machine for incremental view handling but didn't properly distinguish
between:
- Fresh INSERT operations (no old record exists)
- UPDATE operations without rowid change (old record should be captured)
- UPDATE operations with rowid change (already handled by DELETE)
This fix checks if cursor.rowid() returns a value before attempting to
capture the old record. If no row exists (fresh INSERT), we correctly
set old_record to None instead of erroring out.
I am also including tests to make sure this doesn't break. The reason I
didn't include tests earlier is that I didn't know it was possible to
run the tests under a flag. But in here, I am just adding the flag to
the execution script.

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #2579
2025-08-13 21:36:19 -04:00
Glauber Costa
5ab6f78f6b Implement views
Views (non materialized) are relatively simple, since they are just
query aliases.

We can expand them as if they were subqueries.
2025-08-13 14:14:03 -05:00
Glauber Costa
7e76970035 fix: Handle fresh INSERTs in materialized view incremental maintenance
The op_insert function was incorrectly trying to capture an "old record"
for fresh INSERT operations when a table had dependent materialized views.
This caused a "Cannot delete: no current row" error because the cursor
wasn't positioned on any row for new inserts.

The issue was introduced in commit f38333b3 which refactored the state
machine for incremental view handling but didn't properly distinguish
between:
- Fresh INSERT operations (no old record exists)
- UPDATE operations without rowid change (old record should be captured)
- UPDATE operations with rowid change (already handled by DELETE)

This fix checks if cursor.rowid() returns a value before attempting to
capture the old record. If no row exists (fresh INSERT), we correctly
set old_record to None instead of erroring out.

I am also including tests to make sure this doesn't break. The reason I
didn't include tests earlier is that I didn't know it was possible to
run the tests under a flag. But in here, I am just adding the flag to
the execution script.
2025-08-13 06:41:14 -05:00
Levy A.
45d959635c fix: check if index exists with the same name 2025-08-13 08:55:17 +03:00
Pekka Enberg
96673a54a8 bindings/javascript: Add async connect() function
Let's make the API symmetric with libSQL and serverless drivers.
2025-08-12 11:39:59 +03:00
Pekka Enberg
1c6a3bacb9 testing/javascript: Fix libSQL connection setup
The API changed in libSQL to be async.
2025-08-12 11:33:54 +03:00
Jussi Saurio
f598c86fa4 Merge 'Handle single, double and unquoted strings in values clause' from Mikaël Francoeur
I'm not sure how much this will clash with @TcMits's parser rewrite,
hopefully not too much. If it does and we eventually have to remove it,
at least we'll have two new regression tests.
Closes https://github.com/tursodatabase/turso/issues/2484

Closes #2499
2025-08-11 21:08:15 +03:00
PThorpe92
ae22af29cd Fix pragma module list tests 2025-08-11 12:13:47 -04:00
Lucas Forato
673cfdbc0f test: include tests in extensions.py 2025-08-11 08:42:08 -03:00
Lucas Forato
c2a5b43c68 fix: revert changes on testing dbs 2025-08-11 08:42:08 -03:00
Lucas Forato
804df8dd7a feat: changed to non-empty test 2025-08-11 08:42:03 -03:00
Lucas Forato
c37ccd49e1 feat: included tests 2025-08-11 08:42:03 -03:00
Mikaël Francoeur
2cf4e4fe96 handle single, double and unquoted strings in values clause 2025-08-08 09:03:38 -04:00
Jussi Saurio
cca2f6c947 Merge 'Evaluate WHERE conditions after LEFT JOIN' from Piotr Rżysko
This fix ensures that `WHERE` conditions are emitted after the `LEFT
JOIN` match flag is set, so rows from the right table are properly
filtered, even when they are `NULL` due to the outer join.
Previously, the query below would return rows where `products.price` was
`NULL`:
```sql
SELECT users.id, price
FROM users
LEFT JOIN products ON users.id = products.id
WHERE products.price IS NOT NULL;
```

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

Closes #2501
2025-08-08 15:54:17 +03:00
Pekka Enberg
f2b2e4d4d8 Rename JavaScript package to @tursodatabase/database 2025-08-08 13:22:10 +03:00
Pekka Enberg
7a09eb0d4c Merge 'Fix JavaScript bindings packaging' from Nikita Sivukhin
This PR configure `#entry-point` import alias for javascript bindings in
order to use `browser.js` napi-rs generated file in browser context.
Also, this PR forces napi-rs to emit `index.js` entrypoint using ESM and
also use typescript for writing our wrapper code around napi-rs
bindings.
In order to make behaviour consistent when lib is imported through ESM
or CommonJS this PR also replace default export of `Database` by named
on. The problem is that `export default Database` will be logically
equivalent to `modules.export.default = Database` which is not the same
thing as `modules.export = Database` and this will need to access
additional `.default` field with CommonJs style imports (e.g. `new
require('@tursodatabase/turso').default(...)`). In order to remove this
difference - I just replaced default export with named one.

Closes #2488
2025-08-08 10:42:21 +03:00
Piotr Rzysko
375b9047e2 Evaluate WHERE conditions after LEFT JOIN
Previously, the query from the added test would not filter out rows
where `products.price` was NULL.
2025-08-08 06:26:30 +02:00
Preston Thorpe
88d49e402f Merge 'javascript: Organize test cases better' from Pekka Enberg
Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #2490
2025-08-07 21:28:27 -04:00
Nikita Sivukhin
cbe0a7708e update tests 2025-08-08 01:21:37 +04:00
PThorpe92
b131331673 Add shell .py tests for .clone cli command 2025-08-07 16:27:08 -04:00
Pekka Enberg
b033333c8a javascript: Organize test cases better 2025-08-07 15:10:52 +03:00
Pekka Enberg
bae4406e32 testing/javascript: Enable iterate() test cases 2025-08-07 14:28:34 +03:00
Pekka Enberg
b603ee7062 Merge 'JavaScript improvements' from Pekka Enberg
Closes #2467
2025-08-07 14:01:07 +03:00
Jussi Saurio
eb7fa9693d Merge 'Return error on attempting to drop index associated with PRIMARY KEY and UNIQUE constraints' from
Closes issue #2455. Also includes tests.

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

Closes #2461
2025-08-07 09:00:02 +03:00
Preston Thorpe
f55d34a3db Merge 'Fix panic on loading extension on brand new connection' from Preston Thorpe
Closes #2476

Closes #2477
2025-08-06 23:44:38 -04:00
rajajisai
44ba3caaaa Remove miscellaneous characters generated due varying CLI size 2025-08-06 16:02:15 -07:00
PThorpe92
ae99edf4a6 Adjust test to test for behavior of loading extension on brand new connection 2025-08-06 16:55:54 -04:00
Glauber Costa
f36974f086 implement the MaxPgCount opcode
It is used by the pragma max_page_count, which is also implemented.
2025-08-06 13:20:15 -05:00
Jussi Saurio
aaa9ed1d9f Merge 'Add regexp capture' from bit-aloo
This PR adds RegExp Capture to regexp module

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

Closes #2465
2025-08-06 12:13:19 +03:00
bit-aloo
84316d9206 fix python lint 2025-08-06 12:02:20 +05:30
Pekka Enberg
ba37e1dc9a testing/javascript: Enable some passing sync test cases 2025-08-06 09:25:22 +03:00
Pekka Enberg
185b7016dd testing/javascript: Enable Statement.all() raw mode test case 2025-08-06 09:23:16 +03:00
Pekka Enberg
3a5e7f8fb6 testing/javascript: Enable Statement.all() test case 2025-08-06 09:22:48 +03:00
Pekka Enberg
53ac67a2be testing/javascript: Add pragma() after close() test case 2025-08-06 09:10:03 +03:00
Pekka Enberg
66b4de1ad9 testing/javascript: Enable exec() after close() test case 2025-08-06 08:08:35 +03:00
Pekka Enberg
cda3375061 testing/javascript: Enable prepare() after close() test case 2025-08-06 07:50:23 +03:00
rajajisai
9ebfed294e Including tests 2025-08-05 21:18:52 -07:00
Glauber Costa
d1be7ad0bb implement the collseq bytecode instruction
SQLite generates those in aggregations like min / max with collation
information either in the table definition or in the column expression.

We currently generate the wrong result here, and properly generating the
bytecode instruction fixes it.
2025-08-05 13:49:04 -05:00
bit-aloo
b26a58f652 update extension.py with regexp_replace test 2025-08-05 20:36:09 +05:30
Piotr Rzysko
99f87c07c1 Support column references in table-valued function arguments
This change extends table-valued function support by allowing arguments
to be column references, not only literals.

Virtual tables can now reject a plan by returning an error from
best_index (e.g., when a TVF argument references a table that appears
later in the join order). The planner using this information excludes
invalid plans during join order search.
2025-08-05 05:48:28 +02:00
Piotr Rzysko
82491ceb6a Integrate virtual tables with optimizer
This change connects virtual tables with the query optimizer.
The optimizer now considers virtual tables during join order search
and invokes their best_index callbacks to determine feasible access
paths.

Currently, this is not a visible change, since none of the existing
extensions return information indicating that a plan is invalid.
2025-08-05 05:48:28 +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
79e166d722 Implement xBestIndex for kvstore.c
This is to match Rust kv_store implementation.
2025-08-04 19:25:11 +02:00
Pekka Enberg
5037e2dc0d testing/sqlite3: Update all.test 2025-08-02 13:00:18 +03:00
Pekka Enberg
779b8e0149 testing/sqlite3: Import more join test cases 2025-08-02 12:59:11 +03:00
Pekka Enberg
c7497d55b6 testing/sqlite3: Disable select9.test
...it seems to run forever.
2025-08-02 12:59:11 +03:00
Pekka Enberg
a380e0775d testing/sqlite3: Improve tester.tcl
Improve tester.tcl by adding stubs so that we can run more of the test
suite without the test harness giving up.
2025-08-02 12:59:11 +03:00
rajajisai
d2d7adff9e Including test for parsing large numeric strings as number when an operand is numerican when doing logical comparision 2025-08-01 16:30:32 -07:00
Diego Reis
7c70ac2c4a Fix #2390
Single quotes inside a string literal have to be doubled
2025-08-01 11:37:13 -03:00