-
Notifications
You must be signed in to change notification settings - Fork 739
Description
Description
INSERT and UPSERT RETURNING with correlated subqueries referencing the target table's columns see wrong values. Single-row INSERT sees NULL; multi-row INSERT sees the previous row's value (off-by-one). Affects all correlated subquery forms: scalar subqueries, EXISTS, etc. DELETE RETURNING works correctly.
Reproducer
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
CREATE TABLE lookup(k INTEGER PRIMARY KEY, v TEXT);
INSERT INTO lookup VALUES(1, 'one'), (2, 'two'), (3, 'three');
-- Single INSERT: subquery sees NULL instead of inserted 'a' value
INSERT INTO t1 VALUES(1, 'x') RETURNING a, (SELECT v FROM lookup WHERE k = a) as val;
-- Turso: 1|NULL
-- SQLite: 1|one
-- Multi-row INSERT: off-by-one, each row sees PREVIOUS row's 'a'
INSERT INTO t1 VALUES(2, 'y'), (3, 'z')
RETURNING a, (SELECT v FROM lookup WHERE k = a) as val;
-- Turso: 2|one, 3|two
-- SQLite: 2|two, 3|three
-- UPSERT also affected:
CREATE TABLE t2(a INTEGER PRIMARY KEY, b TEXT);
INSERT INTO t2 VALUES(1, 'orig');
INSERT INTO t2 VALUES(1, 'new') ON CONFLICT(a) DO UPDATE SET b = 'upserted'
RETURNING a, (SELECT v FROM lookup WHERE k = a) as val;
-- Turso: 1|NULL
-- SQLite: 1|one
-- EXISTS also affected:
CREATE TABLE t3(a INTEGER PRIMARY KEY, b TEXT);
CREATE TABLE t4(x INTEGER PRIMARY KEY);
INSERT INTO t4 VALUES(1), (3);
INSERT INTO t3 VALUES(1, 'a'), (2, 'b'), (3, 'c')
RETURNING a, b, EXISTS(SELECT 1 FROM t4 WHERE x = a) as has_match;
-- Turso: 1|a|0, 2|b|1, 3|c|0 (shifted by one row)
-- SQLite: 1|a|1, 2|b|0, 3|c|1Per SQLite documentation: "For INSERT and UPDATE statements, references to columns in the table being modified refer to the value of that column after the change has been applied."
The RETURNING subquery is evaluated before the Insert instruction in the bytecode, so cursor-based column reads (RowId/Column on the write cursor) haven't been positioned to the new row yet. Direct column references work because they use register values.
This issue brought to you by Mikaël and Claude Code.