Commit Graph

908 Commits

Author SHA1 Message Date
Jussi Saurio
d5de088abe Merge 'translate: implement Sequence opcode and fix sort order' from Preston Thorpe
This PR implements the `Sequence` and `SequenceTest` opcodes, although
does not yet add plumbing to emit the latter.
SQLite has two distinct mechanisms that determine the final row order
with aggregates:
Traversal order of GROUP BY, and ORDER BY tiebreaking. When ORDER BY
contains only aggregate expressions and/or constants, SQLite has no
extra tiebreak key, but when ORDER BY mixes aggregate and non-aggregate
terms, SQLite adds an implicit, stable row `sequence` so “ties” respect
the input order.
This PR also fixes an issue with a query like the following:
```sql
SELECT u.first_name, COUNT(*) AS c
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.first_name
ORDER BY c DESC;
```
Because ORDER BY has only an aggregate (COUNT(*) DESC) and no non-
aggregate terms, SQLite traverses the group key (u.first_name) in DESC
order in this case, so ties on c naturally appear with group keys in
descending order.
Previously tursodb would return the group key sorted in ASC order,
because it was used in all cases as the default

Closes #3287
2025-09-24 08:38:08 +03:00
PThorpe92
4cc02dbed1 Add regression test for sort order with aggregate term in orderby with groupby 2025-09-23 23:08:31 -04:00
PThorpe92
efe7891482 Add test to ensure we return proper changes() 2025-09-22 19:18:18 -04:00
Preston Thorpe
44dc4c9636 Merge 'translate/emitter: Implement partial indexes' from Preston Thorpe
This PR adds support for partial indexes, e.g. `CREATE INDEX` with a
provided predicate
```sql
CREATE UNIQUE INDEX idx_expensive ON products(sku) where price > 100;
```
The PR does not yet implement support for using the partial indexes in
the optimizer.

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

Closes #3228
2025-09-22 09:09:54 -04:00
Glauber Costa
2627ad44de support union statements in the DBSP circuit compiler 2025-09-21 21:00:27 -03:00
PThorpe92
33538a1ebf Add some tests for UPSERT with partial indexes 2025-09-20 18:32:50 -04:00
PThorpe92
0f771ecb5d Fix tests to assert for UNIQUE constraint failed: table.col_name instead of idx name 2025-09-20 15:02:38 -04:00
PThorpe92
67cb59d9a7 Add UPDATE tests for partial index behavior 2025-09-20 14:38:49 -04:00
PThorpe92
2d952feae3 Add DELETE behavior tests for partial indexes 2025-09-20 14:38:49 -04:00
PThorpe92
4c6917f849 Add testing for partial indexes 2025-09-20 14:38:48 -04:00
Glauber Costa
e5a106d8d6 enable joins in IncrementalView 2025-09-19 03:59:28 -05:00
Jussi Saurio
1d2b461a2a Merge 'Compat: Translate the 2nd argument of group_concat / string_agg' from Iaroslav Zeigerman
Fixes #3140

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

Closes #3155
2025-09-18 09:23:05 +03:00
PThorpe92
faa3113c77 Add regression test for table creation pk autoincrement constraint with backticks 2025-09-17 15:53:35 -04:00
Preston Thorpe
8c53d7f024 Merge 'translation: rewrite expressions and properly handle quoted identifiers in UPSERT' from Preston Thorpe
This PR fixes bugs found in the [turso-
go](https://github.com/tursodatabase/turso-go) driver with UPSERT clause
earlier, where `Gorm` will (obviously) use Expr::Variable's as well as
use quotes for `Expr::Qualified` in the tail end of an UPSERT statement.
Example:
```sql
INSERT INTO users (a,b,c) VALUES (?,?,?) ON CONFLICT (`users`.`a`) DO UPDATE SET b = `excluded`.`b`, a = ?;
```
and previously we were not properly calling `rewrite_expr`, which was
not properly setting the anonymous `Expr::Variable` to `__param_N` named
parameter, so it would ignore it completely, then return the wrong # of
parameters.
Also, we didn't handle quoted "`excluded`.`x`", so it would panic in the
optimizer that Qualified should have been rewritten earlier.

Closes #3157
2025-09-17 11:25:13 -04:00
Iaroslav Zeigerman
29e0cabf2a Compat: Translate the 2nd argument of group_concat / string_agg 2025-09-17 07:42:07 -07:00
Preston Thorpe
bcafb288ad Merge 'Fix is_nonnull returns true on 1 / 0' from Lâm Hoàng Phúc
turso:
```sh
turso> CREATE TABLE t (x PRIMARY KEY, y, z);
turso> INSERT INTO t VALUES (37, -70, -196792117);
turso> SELECT * FROM t WHERE  (1 / 0) >= -3289742039 < t.x;
┌────┬─────┬────────────┐
│ x  │ y   │ z          │
├────┼─────┼────────────┤
│ 37 │ -70 │ -196792117 │
└────┴─────┴────────────┘
turso>
```
sqlite:
```sh
sqlite> CREATE TABLE t (x PRIMARY KEY, y, z);
sqlite> INSERT INTO t VALUES (37, -70, -196792117);
sqlite> SELECT * FROM t WHERE  (1 / 0) >= -3289742039 < t.x;
sqlite>
```
related: https://github.com/tursodatabase/turso/actions/runs/17765571409
/job/50488042583?pr=3147#step:8:855

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

Closes #3167
2025-09-17 06:55:55 -04:00
PThorpe92
8dd1cf11eb Add some more specific tests for upsert 2025-09-17 06:44:10 -04:00
TcMits
6606bf12d3 is_nonnull returns true on 1 / 0 2025-09-17 14:50:15 +07:00
Jussi Saurio
cae234818b Merge 'Inital support for window functions' from Piotr Rżysko
This adds basic support for window functions. For now:
* Only existing aggregate functions can be used as window functions.
* Specialized window-specific functions (`rank`, `row_number`, etc.) are
not yet supported.
* Only the default frame definition is implemented:
`RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS`.

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

Closes #3079
2025-09-17 08:29:16 +03:00
Pekka Enberg
74331898a3 Merge 'Add quoted identifier test cases for ALTER TABLE' from Levy A.
Resolves #2093
There is a small incompatibility on how we quote the added column on the
final schema, but doesn't change any behavior.

Closes #2943
2025-09-16 11:46:12 +03:00
Piotr Rzysko
f5efcbe745 Add support for window functions
Adds initial support for window functions. For now, only existing
aggregate functions can be used as window functions—no specialized
window-specific functions are supported yet.

Currently, only the default frame definition is implemented:
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS.
2025-09-13 11:12:44 +02:00
Piotr Rzysko
6d84cbedc2 Fix delimiter handling in group_concat and string_agg
Non-literal delimiters must be translated by AggArgumentSource.
2025-09-13 10:49:14 +02:00
Piotr Rzysko
110ffba2a1 Fix accumulator reset when arguments outnumber aggregates
Previously, while resetting accumulator registers, we would also
reset subsequent registers. This happened because the number of registers
to reset was computed as the sum of arguments rather than the number of
aggregate functions.
2025-09-13 10:49:14 +02:00
Pekka Enberg
c620a15a55 Merge 'core: Support ceiling modifier in datetime' from Ceferino Patino
Resolves #2677
- Implements the modifier for Floor on the datetime object.
- Implements the modifier for Ceiling on the datetime object.
- Includes additional testing changes in testing/scalar-functions-
datetime.test to test the sql functionality.
Consolidation PR of #2678 and #2679 since the functions ended up being
much more complicated than I initially thought and had to be done in a
single PR.

Closes #2757
2025-09-10 14:46:07 +03:00
Pekka Enberg
a3d23c2738 Merge 'Fix jsonb functions check valid json string binary' from
closes: #2820
```
turso> select user->>'age' as age from json_user;
┌─────┐
│ age │
├─────┤
│  30 │
└─────┘
```

Closes #2821
2025-09-10 14:44:54 +03:00
Pekka Enberg
f3ee355fa1 testing/compare.test: Clean up tests by using in-memory database
Suggested by Jussi
2025-09-10 14:14:46 +03:00
Pekka Enberg
22b352bc2f Merge 'core: Fix integer/float comparison' from Pavan Nambi
closes #2957

Closes #2958
2025-09-10 14:13:15 +03:00
Preston Thorpe
d32d19b47f Merge 'Implement 2-args json_each' from Mikaël Francoeur
Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #2953
2025-09-09 16:43:24 -04:00
Jussi Saurio
b01033975a regression test for crash in op_column 2025-09-09 00:11:19 +03:00
Jussi Saurio
cc46bfb6d8 add gen-bigass-database.py
ability to create an equivalent big schema so that the issues
reported by Preston using that larger schema can be reproduced
and fixed.
2025-09-08 13:05:33 -04:00
Preston Thorpe
8d05336522 Merge 'Fix affinity handling in MakeRecord' from Pekka Enberg
Closes #2966
2025-09-08 12:14:33 -04:00
Pekka Enberg
0c6398c935 core/vdbe: Fix apply_affinity_char() text parsing
We need strict parsing in apply_affinity_char() to avoid transforming
non-numeric values (for example, "1a") into numeric values.
2025-09-08 18:49:13 +03:00
Mikaël Francoeur
b480b526bc implement 2-args json_each 2025-09-08 11:34:17 -04:00
Jussi Saurio
5820f691af fix: do not crash in Next if cursor stack has no pages 2025-09-08 16:54:35 +03:00
Pavan-Nambi
d757a330ee use sqlite_int_float_compare 2025-09-08 16:26:37 +05:30
Jussi Saurio
68ee447d35 Minimal regression test for 2949 2025-09-08 09:35:11 +03:00
Levy A.
8867d8cdb6 feat: add more alter table test cases 2025-09-05 20:43:18 -03:00
Mikaël Francoeur
e6d3d6ea54 1-arg json_each implementation 2025-09-05 14:47:40 -04:00
Pekka Enberg
44357f93a2 Merge branch 'main' into 2025-08-21-make-limit-and-offset-expr 2025-09-04 09:54:45 +03:00
Preston Thorpe
caaf60a7ea Merge 'Unify resolution of aggregate functions' from Piotr Rżysko
This PR unifies the logic for resolving aggregate functions. Previously,
bare aggregates (e.g. `SELECT max(a) FROM t1`) and aggregates wrapped in
expressions (e.g. `SELECT max(a) + 1 FROM t1`) were handled differently,
which led to duplicated code. Now both cases are resolved consistently.
The added benchmark shows a small improvement:
```
Prepare `SELECT first_name, last_name, state, city, age + 10, LENGTH(email), UPPER(first_name), LOWE...
                        time:   [59.791 µs 59.898 µs 60.006 µs]
                        change: [-7.7090% -7.2760% -6.8242%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  8 (8.00%) high mild
  2 (2.00%) high severe
```
For an existing benchmark, no change:
```
Prepare `SELECT first_name, count(1) FROM users GROUP BY first_name HAVING count(1) > 1 ORDER BY cou...
                        time:   [11.895 µs 11.913 µs 11.931 µs]
                        change: [-0.2545% +0.2426% +0.6960%] (p = 0.34 > 0.05)
                        No change in performance detected.
Found 8 outliers among 100 measurements (8.00%)
  1 (1.00%) low severe
  2 (2.00%) high mild
  5 (5.00%) high severe
```

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

Closes #2884
2025-09-03 19:46:04 -04:00
themixednuts
fa19ba4993 chore: add tests 2025-09-02 10:58:00 -05:00
TcMits
635402fc6f string sometimes used as identifier quoting 2025-09-02 21:35:37 +07:00
Piotr Rzysko
569e41cb1e Skip traversing children of aggregate functions
Aggregate functions cannot be nested, and this is validated during the
translation of aggregate function arguments. Therefore, traversing their
child expressions is unnecessary.
2025-09-02 08:22:37 +02:00
Piotr Rzysko
9b742a64c2 Handle functions with star argument wrapped in expressions
Handled in the same way as in `prepare_one_select_plan` for bare
function calls.
2025-09-02 08:22:36 +02:00
Piotr Rzysko
f3cbc382ce Support external aggregate functions wrapped in expressions
Handled in the same way as in `prepare_one_select_plan` for bare
function calls. In `prepare_one_select_plan`, however, resolving
external scalar functions is performed unnecessarily twice.
2025-09-02 08:22:36 +02:00
Pekka Enberg
7189e98455 Merge 'Unify handling of grouped and ungrouped aggregations' from Piotr Rżysko
The initial commits fix issues and plug gaps between ungrouped and
grouped aggregations.
The final commit consolidates the code that emits `AggStep` to prevent
future disparities between the two.

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

Closes #2867
2025-09-02 09:11:40 +03:00
Pekka Enberg
cfaba4ab10 Merge 'Implement libSQL's ALTER COLUMN extension' from Levy A.
Implement `ALTER COLUMN` as described here:
https://github.com/tursodatabase/libsql/blob/main/libsql-
sqlite3/doc/libsql_extensions.md#altering-columns
- [x] Add `ALTER COLUMN` to parser
- [x] Implement `Insn::AlterColumn`
- [x] Add tests

Closes #2814
2025-09-02 09:06:03 +03:00
themixednuts
b6e64587cb fix: jsonb functions to check if binary is json string
chore: match sqlite error

chore: use existing slice variable

add better parsing logic, and validation

see sqlite source code @ sqlite/src/json.c -> static int jsonArgIsJsonb

chore: clippy
2025-09-01 19:52:57 -05:00
PThorpe92
f02e02af75 Fix TCL test 2025-09-01 11:39:43 -04:00
PThorpe92
bd9d6aa168 Add edge-case tests for boolean literals 2025-09-01 11:27:43 -04:00