Description
When a virtual generated column is protected by a UNIQUE INDEX, INSERT ... ON CONFLICT DO UPDATE can skip uniqueness enforcement and commit duplicate values. A no-op DO UPDATE that should succeed instead fails. Partial UNIQUE INDEXes on generated columns also fail spuriously. Plain UPDATE against the same UNIQUE INDEX behaves correctly.
Reproducer
-- BUG: duplicate generated values are committed
CREATE TABLE t(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER GENERATED ALWAYS AS (a*2) VIRTUAL);
CREATE UNIQUE INDEX idx_b ON t(b);
INSERT INTO t(id,a) VALUES(1,1),(2,2);
INSERT INTO t(id,a) VALUES(1,2)
ON CONFLICT(id) DO UPDATE SET a=excluded.a;
SELECT id,a,b FROM t ORDER BY id;
-- Turso: 1|2|4 / 2|2|4 (duplicate b=4 committed)
-- SQLite: UNIQUE constraint failed: t.b
-- BUG: no-op DO UPDATE should succeed, but Turso fails
CREATE TABLE t3(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER GENERATED ALWAYS AS (a*2) VIRTUAL);
CREATE UNIQUE INDEX idx_b3 ON t3(b);
INSERT INTO t3(id,a) VALUES(1,1),(2,2);
INSERT INTO t3(id,a) VALUES(1,2)
ON CONFLICT(id) DO UPDATE SET id=id;
SELECT id,a,b FROM t3 ORDER BY id;
-- Turso: fails
-- SQLite: 1|1|2 / 2|2|4
-- BUG: partial UNIQUE INDEX should allow this UPSERT
CREATE TABLE t4(
id INTEGER PRIMARY KEY,
side TEXT,
pill TEXT GENERATED ALWAYS AS (lower(side)) VIRTUAL
);
CREATE UNIQUE INDEX idx_red ON t4(pill) WHERE side LIKE 'red%';
INSERT INTO t4(id,side) VALUES(1,'red-pill'),(2,'blue-pill');
INSERT INTO t4(id,side) VALUES(1,'red-pilled')
ON CONFLICT(id) DO UPDATE SET side=excluded.side;
SELECT id,side,pill FROM t4 ORDER BY id;
-- Turso: fails
-- SQLite: 1|red-pilled|red-pilled / 2|blue-pill|blue-pill
Per SQLite documentation: "If the DO UPDATE clause encounters any constraint violation, the entire INSERT statement rolls back and halts."
This issue brought to you by Mikaël and Claude Code.
Description
When a virtual generated column is protected by a UNIQUE INDEX,
INSERT ... ON CONFLICT DO UPDATEcan skip uniqueness enforcement and commit duplicate values. A no-opDO UPDATEthat should succeed instead fails. Partial UNIQUE INDEXes on generated columns also fail spuriously. Plain UPDATE against the same UNIQUE INDEX behaves correctly.Reproducer
Per SQLite documentation: "If the DO UPDATE clause encounters any constraint violation, the entire INSERT statement rolls back and halts."
This issue brought to you by Mikaël and Claude Code.