Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6483fb8
Vendor the Turso v0.8.1 sqltest corpus and record its new differences
mamoreau-devolutions Sep 30, 2026
9504912
Reject stale MVCC writes over committed peers and keep explicit rowids
mamoreau-devolutions Sep 30, 2026
5f107a8
Close v0.8.1 built-in function, JSON, date/time, and TVF corpus diffe…
mamoreau-devolutions Sep 30, 2026
a85c3e2
Merge built-in function, JSON and date/time v0.8.1 parity
mamoreau-devolutions Sep 30, 2026
e288415
Carry SQLite result codes through the facade, guard explicit checkpoi…
mamoreau-devolutions Sep 30, 2026
e398391
Add replica parity: advanced keywords, explicit pull/push/checkpoint/…
mamoreau-devolutions Sep 30, 2026
6f185ea
Merge replica/sync binding API parity with Turso v0.8.1 bindings/dotnet
mamoreau-devolutions Sep 30, 2026
fb2a094
Report page-1 auto_vacuum mode and reject MVCC ALTER COLUMN index reb…
mamoreau-devolutions Sep 30, 2026
672eb97
Close v0.8.1 schema/DML/pragma parity gaps
mamoreau-devolutions Sep 30, 2026
fb57377
Merge schema, DML and pragma v0.8.1 parity
mamoreau-devolutions Sep 30, 2026
f8b4297
Report STRICT storage-class and generated-column violations from inte…
mamoreau-devolutions Sep 30, 2026
76e7167
Let WAL readers pin read-marks 1..4 while a checkpoint holds read-mark 0
mamoreau-devolutions Sep 30, 2026
2baa7a6
Close v0.8.1 join/unnest correctness gaps and partial-index/EQP plann…
mamoreau-devolutions Sep 30, 2026
358d150
Merge join/unnest correctness and planner/EQP v0.8.1 parity
mamoreau-devolutions Sep 30, 2026
06c9799
Merge error-code fidelity and storage/integrity v0.8.1 parity
mamoreau-devolutions Sep 30, 2026
6fcb786
Unnest correlated comparisons and plan semi/anti inner access with th…
mamoreau-devolutions Sep 30, 2026
25ffee5
Plan IN-list and OR-implied IN index searches, compound multi-index O…
mamoreau-devolutions Sep 30, 2026
3ba59a3
Enforce PRAGMA max_page_count and report real page counts
mamoreau-devolutions Sep 30, 2026
0e88450
Merge max_page_count enforcement and real page counts
mamoreau-devolutions Sep 30, 2026
82d61ad
Cost compiled joins with the Turso v0.8.1 join planner and describe t…
mamoreau-devolutions Sep 30, 2026
5b4ef8f
Report Turso cost-model estimates in EXPLAIN QUERY PLAN FORMAT=JSON a…
mamoreau-devolutions Sep 30, 2026
818d02a
Relabel verified journal-mode policy ledger entries; note v0.8.1 corp…
mamoreau-devolutions Oct 1, 2026
f39c555
Merge Turso 0.8 planner port: unnest comparisons, IN/OR seeks, hash-j…
mamoreau-devolutions Oct 1, 2026
8d600d9
Document the Turso v0.8.1 parity refresh and reconcile the ledger count
mamoreau-devolutions Oct 1, 2026
6717362
Buffer sorter spill I/O so spilled GROUP BY stays fast
mamoreau-devolutions Oct 1, 2026
f857af0
Keep spilled hash joins batching and read partitions in blocks
mamoreau-devolutions Oct 1, 2026
daf6041
Hash-bucket evaluator DISTINCT, compound set operators and DISTINCT a…
mamoreau-devolutions Oct 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ including the tagged browser WASM binding, without cloning ad hoc or guessing
at API shape. Historical gap/MVCC contracts that explicitly name `v0.7.2`
retain that version as their behavioral analysis baseline, and the gap
inventory and audits that name `v0.8.0-pre.7` (commit `277ddd050`) keep that
tag as theirs until they are refreshed against the current pin.
tag as theirs until they are refreshed against the current pin. The vendored
sqltest corpus (`conformance/sqlite-sqltests`) and its expected-failures
ledger are refreshed to `v0.8.1`; see the "v0.8.1 refresh" section of
`docs/turso-remaining-gap-plan.md`.

```powershell
git submodule update --init --recursive # first checkout / fresh clone
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ Common connection-string keywords: `Data Source`, `Mode`, `Cache`, `Pooling`,
`DateTimeKind`, `BinaryGUID`, or `Encryption Cipher` + `Encryption Key` (hex
AES-GCM or AEGIS keys). Turso/Hrana URLs
also accept `Auth Token`, `Replica Path`, `Sync Interval`, `Read Your Writes`,
and `Tls` through either ADO.NET facade. Default local provider is managed-only.
and `Tls` through either ADO.NET facade, plus Turso's advanced embedded-replica
keywords (`Sync Client Name`, `Sync Long Poll Timeout`, `Bootstrap If Empty`,
partial-bootstrap, remote-encryption and threshold keys) and Ahtola's
`Automatic Sync Mode` — see [docs/dotnet-packages.md](docs/dotnet-packages.md#connection-string-reference). Default local provider is managed-only.

### Standard SQLite files

Expand Down
74 changes: 74 additions & 0 deletions conformance/sqlite-sqltests/affinity.sqltest
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,41 @@ expect {
text|3
}

# ============================================
# Vertical tab (0x0B) is whitespace to SQLite's ctype table (0x09-0x0D)
# even though it is not "ASCII whitespace" per Rust's is_ascii_whitespace().
# https://github.com/tursodatabase/turso/issues/8454
# ============================================
@cross-check-integrity
test affinity-vertical-tab-leading {
CREATE TABLE t1(i INTEGER);
INSERT INTO t1 VALUES (CHAR(11) || '12');
SELECT TYPEOF(i), i = 12 FROM t1;
}
expect {
integer|1
}

@cross-check-integrity
test affinity-vertical-tab-trailing {
CREATE TABLE t1(i INTEGER);
INSERT INTO t1 VALUES ('12' || CHAR(11));
SELECT TYPEOF(i), i = 12 FROM t1;
}
expect {
integer|1
}

@cross-check-integrity
test affinity-vertical-tab-integer-primary-key {
CREATE TABLE t1(i INTEGER PRIMARY KEY);
INSERT INTO t1 VALUES (CHAR(11) || '12');
SELECT COUNT(*), TYPEOF(i), i FROM t1;
}
expect {
1|integer|12
}


# ============================================
# REAL affinity with leading + sign
Expand Down Expand Up @@ -540,6 +575,33 @@ expect {
1a|text
}

@cross-check-integrity
test affinity-any-strict-index-comparisons {
CREATE TABLE t(id INTEGER PRIMARY KEY, c ANY) STRICT;
INSERT INTO t VALUES (1, '000123'), (2, 123), (3, '123');
SELECT id FROM t WHERE c = 123 ORDER BY id;
SELECT id FROM t WHERE c = '123' ORDER BY id;
CREATE UNIQUE INDEX t_c ON t(c);
SELECT id FROM t INDEXED BY t_c WHERE c = 123 ORDER BY id;
SELECT id FROM t INDEXED BY t_c WHERE c = '123' ORDER BY id;
SELECT id FROM t INDEXED BY t_c WHERE c = '000123' ORDER BY id;
UPDATE t SET c = '1.5' WHERE id = 1;
INSERT INTO t VALUES (2, '000456') ON CONFLICT(id) DO UPDATE SET c = excluded.c;
SELECT id, c, typeof(c) FROM t ORDER BY id;
PRAGMA integrity_check;
}
expect {
2
3
2
3
1
1|1.5|text
2|000456|text
3|123|text
ok
}

@cross-check-integrity
test cast-text-to-numeric-integral-float {
SELECT CAST('3.0' AS NUMERIC), typeof(CAST('3.0' AS NUMERIC));
Expand Down Expand Up @@ -572,6 +634,18 @@ expect @js {
2251799813685248|real
}

@cross-check-integrity
test cast-text-to-numeric-vertical-tab {
SELECT CAST(CHAR(11) || '12' AS NUMERIC);
SELECT CAST('12' || CHAR(11) AS NUMERIC);
SELECT CAST(CHAR(9) || '12' AS NUMERIC);
}
expect {
12
12
12
}

# Regression tests for https://github.com/tursodatabase/turso/issues/4927
# A compound (UNION/UNION ALL) subquery column's affinity must be combined
# across all arms, not taken from the leftmost arm alone. Scanning left to
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@database :memory:

test json_group_object_skips_null_label {
CREATE TABLE t(k TEXT, n INT);
INSERT INTO t VALUES('a', 1), (NULL, 2), ('b', 3);
SELECT json_group_object(k, n) FROM t;
}
expect {
{"a":1,"b":3}
}

test jsonb_group_object_skips_null_label {
CREATE TABLE t(k TEXT, n INT);
INSERT INTO t VALUES('a', 1), (NULL, 2), ('b', 3);
SELECT json(jsonb_group_object(k, n)) FROM t;
}
expect {
{"a":1,"b":3}
}

test json_group_object_null_label_only {
SELECT json_group_object(NULL, 1), json(jsonb_group_object(NULL, 1)),
json_group_object('a', NULL), json_group_array(NULL);
}
expect {
{}|{}|{"a":null}|[null]
}
51 changes: 51 additions & 0 deletions conformance/sqlite-sqltests/agg-functions/memory.sqltest
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
@database :memory:

test finalize-mixed-aggregates-across-groups {
CREATE TABLE t(g INTEGER, v INTEGER, s TEXT);
INSERT INTO t VALUES (1, 2, 'a'), (1, 4, 'a'),
(2, NULL, NULL), (2, NULL, NULL),
(3, 7, 'c'), (4, 9, 'd');
SELECT g, count(*), count(v), count(DISTINCT v),
coalesce(sum(v), -1), total(v), coalesce(avg(v), -1),
coalesce(min(s), '-'), coalesce(max(s), '-'),
coalesce(group_concat(s), '-'), count(*) FILTER (WHERE 0)
FROM t GROUP BY g ORDER BY g;
}
expect {
1|2|2|2|6|6.0|3.0|a|a|a,a|0
2|2|0|0|-1|0.0|-1|-|-|-|0
3|1|1|1|7|7.0|7.0|c|c|c|0
4|1|1|1|9|9.0|9.0|d|d|d|0
}
expect @js {
1|2|2|2|6|6|3|a|a|a,a|0
2|2|0|0|-1|0|-1|-|-|-|0
3|1|1|1|7|7|7|c|c|c|0
4|1|1|1|9|9|9|d|d|d|0
}

test aggregate-values-preserve-state-across-window-rows {
CREATE TABLE t(id INTEGER, g INTEGER, v INTEGER);
INSERT INTO t VALUES (1, 1, 2), (2, 1, NULL), (3, 1, 4),
(4, 2, NULL), (5, 2, 7);
SELECT id, count(*) OVER w, count(v) OVER w,
coalesce(sum(v) OVER w, -1), total(v) OVER w,
count(*) FILTER (WHERE 0) OVER w
FROM t
WINDOW w AS (PARTITION BY g ORDER BY id
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
ORDER BY id;
}
expect {
1|1|1|2|2.0|0
2|2|1|2|2.0|0
3|2|1|4|4.0|0
4|1|0|-1|0.0|0
5|2|1|7|7.0|0
}
expect @js {
1|1|1|2|2|0
2|2|1|2|2|0
3|2|1|4|4|0
4|1|0|-1|0|0
5|2|1|7|7|0
}

@cross-check-integrity
test min-null-regression-test {
CREATE TABLE t (a);
Expand Down
65 changes: 65 additions & 0 deletions conformance/sqlite-sqltests/agg-functions/sum-large-float.sqltest
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,68 @@ test avg-large-float-infinity {
expect {
Inf
}

test float-sum-and-avg-compensate-rounding-error {
WITH t(x) AS (VALUES(0.1),(0.1),(0.1),(0.1),(0.1),(0.1),(0.1),(0.1),(0.1),(0.1))
SELECT sum(x) = 1.0, total(x) = 1.0, avg(x) = 0.1 FROM t;
}
expect {
1|1|1
}

test float-sum-after-integer-overflow {
WITH t(x) AS (VALUES(9223372036854775807),(1),(0.5),(0.25))
SELECT typeof(sum(x)), sum(x), total(x) FROM t;
}
expect {
real|9.22337203685478e+18|9.22337203685478e+18
}
expect @js {
real|9223372036854776000|9223372036854776000
}

test float-avg-then-large-integer {
WITH t(x) AS (VALUES(0.5),(9007199254740993),(1.5))
SELECT avg(x), sum(x) FROM t;
}
expect {
3.00239975158033e+15|9.007199254741e+15
}
expect @js {
3002399751580332|9007199254740996
}

test float-sum-reaches-infinity-then-finite-value {
WITH t(x) AS (VALUES(1e308),(1e308),(-1e308),(0.5))
SELECT sum(x), avg(x) FROM t;
}
expect {
Inf|Inf
}

test count-mixed-value-types {
WITH t(x) AS (VALUES(1),('a'),(NULL),(2.5),(x'00'),(3))
SELECT count(x), count(*) FROM t;
}
expect {
5|6
}

test float-sum-then-integers {
WITH t(x) AS (VALUES(0.5),(1),(-3),(4503599627370495),(4503599627370496),(9007199254740993),(-9223372036854775808),(2))
SELECT typeof(sum(x)), sum(x), total(x), avg(x) FROM t;
}
expect {
real|-9.20535763834529e+18|-9.20535763834529e+18|-1.15066970479316e+18
}
expect @js {
real|-9205357638345294000|-9205357638345294000|-1150669704793161700
}

test total-over-integers {
WITH t(x) AS (VALUES(9007199254740991),(1),(1),(-2),(4503599627370495))
SELECT printf('%.17g', total(x)), printf('%.17g', avg(x)) FROM t;
}
expect {
13510798882111490|2702159776422297
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@database :memory:

# Regression tests for https://github.com/tursodatabase/turso/issues/9068
#
# ADD COLUMN rewrites the stored CREATE TABLE text. A column named with a
# keyword (`"order"`) that appears inside a table-level PRIMARY KEY must keep
# its quotes in the rewritten text. Otherwise the schema text becomes
# `PRIMARY KEY (id, order)`, which no longer parses, so every later ALTER
# fails and the database file cannot be opened again.

setup keyword-pk-column {
CREATE TABLE g(id INTEGER, "order" NUMERIC, val INTEGER, PRIMARY KEY(id, "order"));
INSERT INTO g VALUES (1, 2, 3);
ALTER TABLE g ADD COLUMN added REAL;
}

@setup keyword-pk-column
test add-column-keeps-quotes-in-table-level-primary-key {
SELECT instr(sql, '"order")') > 0 FROM sqlite_schema WHERE name = 'g';
}
expect {
1
}

@setup keyword-pk-column
test rename-column-after-add-column-with-quoted-pk-column {
ALTER TABLE g RENAME COLUMN val TO v2;
SELECT id, "order", v2, added FROM g;
}
expect {
1|2|3|
}

@setup keyword-pk-column
test add-second-column-after-add-column-with-quoted-pk-column {
ALTER TABLE g ADD COLUMN more TEXT;
SELECT id, "order", val, added, more FROM g;
}
expect {
1|2|3||
}
34 changes: 34 additions & 0 deletions conformance/sqlite-sqltests/alter-column-keeps-pk-desc.sqltest
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@database :memory:

setup desc-pk-tables {
CREATE TABLE t(a INTEGER PRIMARY KEY DESC, q TEXT);
CREATE TABLE v(a TEXT PRIMARY KEY DESC, q TEXT);
CREATE TABLE w(a INTEGER PRIMARY KEY DESC, q TEXT, r TEXT);
}

@setup desc-pk-tables
test add-column-keeps-desc-on-integer-primary-key {
ALTER TABLE t ADD COLUMN z TEXT;
SELECT instr(sql, 'PRIMARY KEY DESC') > 0 FROM sqlite_schema WHERE name = 't';
}
expect {
1
}

@setup desc-pk-tables
test add-column-keeps-desc-on-text-primary-key {
ALTER TABLE v ADD COLUMN z TEXT;
SELECT instr(sql, 'PRIMARY KEY DESC') > 0 FROM sqlite_schema WHERE name = 'v';
}
expect {
1
}

@setup desc-pk-tables
test drop-column-keeps-desc-on-integer-primary-key {
ALTER TABLE w DROP COLUMN r;
SELECT instr(sql, 'PRIMARY KEY DESC') > 0 FROM sqlite_schema WHERE name = 'w';
}
expect {
1
}
Loading
Loading