Merge 'Fix index update when INTEGER PRIMARY KEY (rowid alias)' from Adrian-Ryan Acala

When an `UPDATE` statement modifies a table's `INTEGER PRIMARY KEY`
(which acts as a `rowid` alias) alongside other indexed columns, the
index entries were incorrectly retaining the old `rowid`. This led to
stale index references, causing subsequent queries to return incorrect
results.
This change ensures that when the `rowid` alias is part of the `SET`
clause in an `UPDATE` statement, the new `rowid` value is used for
generating and updating index records. This guarantees that all index
entries correctly point to the updated row, resolving the data
inconsistency.
Fixes #1897

Closes #1916
This commit is contained in:
Pekka Enberg 2025-07-03 13:10:53 +03:00
commit 471d26a632
2 changed files with 20 additions and 1 deletions

View file

@ -888,7 +888,16 @@ fn emit_update_insns(
// allocate scratch registers for the index columns plus rowid
let idx_start_reg = program.alloc_registers(num_cols + 1);
let rowid_reg = beg;
// Use the new rowid value (if the UPDATE statement sets the rowid alias),
// otherwise keep using the original rowid. This guarantees that any
// newly inserted/updated index entries point at the correct row after
// the primary key change.
let rowid_reg = if has_user_provided_rowid {
// Safe to unwrap because `has_user_provided_rowid` implies the register was allocated.
rowid_set_clause_reg.expect("rowid register must be set when updating rowid alias")
} else {
beg
};
let idx_cols_start_reg = beg + 1;
// copy each index column from the table's column registers into these scratch regs

View file

@ -205,6 +205,16 @@ if {[info exists ::env(SQLITE_EXEC)] && ($::env(SQLITE_EXEC) eq "scripts/limbo-s
1
2
2}
do_execsql_test_on_specific_db {:memory:} update_rowid_alias_index_regression_test {
CREATE TABLE t(a INTEGER PRIMARY KEY, b);
CREATE INDEX idx_b ON t (b);
INSERT INTO t VALUES (1, 'foo');
SELECT a FROM t WHERE b = 'foo';
UPDATE t SET a = 2, b = 'bar';
SELECT a FROM t WHERE b = 'bar';
} {1
2}
}
do_execsql_test_on_specific_db {:memory:} update_where_or_regression_test {