-
Notifications
You must be signed in to change notification settings - Fork 739
Description
Description
When a DML statement with RETURNING fails due to an immediate foreign key constraint violation, RETURNING still emits the rows even though the statement is rolled back. Data integrity is maintained (the rollback works), but the RETURNING output is spurious. Affects INSERT, UPDATE, and DELETE. CHECK constraints correctly suppress output.
Reproducer
PRAGMA foreign_keys = ON;
CREATE TABLE parent(id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE child(id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id), val TEXT);
INSERT INTO parent VALUES(1, 'p1');
INSERT INTO child VALUES(1, 1, 'c1');
-- INSERT FK violation: RETURNING should NOT output anything
INSERT INTO child VALUES(2, 999, 'c2') RETURNING *;
-- Turso: Error + row (2|999|c2) shown
-- SQLite: Error only, no row output
-- DELETE FK violation: same issue
DELETE FROM parent WHERE id = 1 RETURNING *;
-- Turso: Error + row (1|p1) shown
-- SQLite: Error only, no row output
-- UPDATE FK violation: same issue
CREATE TABLE parent2(id INTEGER PRIMARY KEY);
CREATE TABLE child2(id INTEGER PRIMARY KEY, pid INTEGER REFERENCES parent2(id));
INSERT INTO parent2 VALUES(1);
INSERT INTO child2 VALUES(1, 1);
UPDATE child2 SET pid = 999 WHERE id = 1 RETURNING *;
-- Turso: Error + row (1|999) shown
-- SQLite: Error only, no row outputPer SQLite documentation: "If a statement modifies the contents of the database so that an immediate foreign key constraint is in violation at the conclusion the statement, an exception is thrown and the effects of the statement are reverted."
Since the effects are reverted, RETURNING should not emit any rows. The RETURNING rows are buffered into the ephemeral table before the FK check runs, and then emitted even after rollback.
This issue brought to you by Mikaël and Claude Code.