From 51abeca8961a0053a998741d659b27e021f863e8 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Mon, 9 Jun 2025 08:44:31 +0300 Subject: [PATCH 1/2] Add regression test for updating indexes --- testing/update.test | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/testing/update.test b/testing/update.test index 788bf6434..a0719e042 100755 --- a/testing/update.test +++ b/testing/update.test @@ -170,3 +170,18 @@ do_execsql_test_on_specific_db {:memory:} update_cache_full_regression_test_#162 UPDATE t SET x = randomblob(4096) WHERE rowid = 1; SELECT count(*) FROM t; } {1} + +do_execsql_test_on_specific_db {:memory:} update_index_regression_test { + CREATE TABLE t(x, y); + CREATE INDEX tx ON t (x); + CREATE UNIQUE INDEX tyu ON t (y); + INSERT INTO t VALUES (1, 1); + SELECT x FROM t; -- uses tx index + SELECT y FROM t; -- uses ty index + UPDATE t SET x=2, y=2; + SELECT x FROM t; -- uses tx index + SELECT y FROM t; -- uses ty index +} {1 +1 +2 +2} From 2075e5f3eb47a4fe18caeabac969e4bacaf0f259 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 8 Jun 2025 10:56:44 +0300 Subject: [PATCH 2/2] Fix UPDATE always inserting only nulls into non-unique indexes --- core/translate/emitter.rs | 13 ++++++++----- core/vdbe/execute.rs | 7 ++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/translate/emitter.rs b/core/translate/emitter.rs index 9754ebc63..06ae3ea8d 100644 --- a/core/translate/emitter.rs +++ b/core/translate/emitter.rs @@ -1133,10 +1133,6 @@ fn emit_update_insns( } for (index, (idx_cursor_id, record_reg)) in plan.indexes_to_update.iter().zip(&index_cursors) { - if !index.unique { - continue; - } - let num_cols = index.columns.len(); // allocate scratch registers for the index columns plus rowid let idx_start_reg = program.alloc_registers(num_cols + 1); @@ -1161,6 +1157,7 @@ fn emit_update_insns( amount: 0, }); + // this record will be inserted into the index later program.emit_insn(Insn::MakeRecord { start_reg: idx_start_reg, count: num_cols + 1, @@ -1168,6 +1165,11 @@ fn emit_update_insns( index_name: Some(index.name.clone()), }); + if !index.unique { + continue; + } + + // check if the record already exists in the index for unique indexes and abort if so let constraint_check = program.allocate_label(); program.emit_insn(Insn::NoConflict { cursor_id: *idx_cursor_id, @@ -1280,7 +1282,7 @@ fn emit_update_insns( let num_regs = index.columns.len() + 1; let start_reg = program.alloc_registers(num_regs); - // Emit columns that are part of the index + // Delete existing index key index .columns .iter() @@ -1304,6 +1306,7 @@ fn emit_update_insns( cursor_id: idx_cursor_id, }); + // Insert new index key (filled further above with values from set_clauses) program.emit_insn(Insn::IdxInsert { cursor_id: idx_cursor_id, record_reg: record_reg, diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 28ec562eb..2d06424f0 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -3982,7 +3982,12 @@ pub fn op_idx_insert( let cursor = cursor.as_btree_mut(); let record = match &state.registers[record_reg] { Register::Record(ref r) => r, - _ => return Err(LimboError::InternalError("expected record".into())), + o => { + return Err(LimboError::InternalError(format!( + "expected record, got {:?}", + o + ))); + } }; // To make this reentrant in case of `moved_before` = false, we need to check if the previous cursor.insert started // a write/balancing operation. If it did, it means we already moved to the place we wanted.