Fix: Correctly update indexes when INTEGER PRIMARY KEY (rowid alias) changes (Issue #1897)

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.
This commit is contained in:
AdrianAcala 2025-07-01 08:04:27 +00:00
parent bd60cd214c
commit 7ca902979d
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 {