diff --git a/core/translate/emitter.rs b/core/translate/emitter.rs index 8e3e2c81e..67c8695de 100644 --- a/core/translate/emitter.rs +++ b/core/translate/emitter.rs @@ -1194,6 +1194,7 @@ fn emit_update_insns( extra_amount: 0, }); } + // last register is the rowid program.emit_insn(Insn::Copy { src_reg: rowid_reg, dst_reg: idx_start_reg + num_cols, @@ -1209,8 +1210,9 @@ fn emit_update_insns( }); // Handle unique constraint - if index.unique { + if !index.unique { let constraint_check = program.allocate_label(); + // check if the record already exists in the index for unique indexes and abort if so program.emit_insn(Insn::NoConflict { cursor_id: *idx_cursor_id, target_pc: constraint_check, @@ -1224,6 +1226,7 @@ fn emit_update_insns( dest: idx_rowid_reg, }); + // Skip over the UNIQUE constraint failure if the existing row is the one that we are currently changing program.emit_insn(Insn::Eq { lhs: beg, rhs: idx_rowid_reg, @@ -1232,12 +1235,18 @@ fn emit_update_insns( collation: program.curr_collation(), }); - let column_names = index - .columns - .iter() - .map(|c| format!("{}.{}", table_ref.table.get_name(), c.name)) - .collect::>() - .join(", "); + let column_names = index.columns.iter().enumerate().fold( + String::with_capacity(50), + |mut accum, (idx, col)| { + if idx > 0 { + accum.push_str(", "); + } + accum.push_str(table_ref.table.get_name()); + accum.push('.'); + accum.push_str(&col.name); + accum + }, + ); program.emit_insn(Insn::Halt { err_code: SQLITE_CONSTRAINT_PRIMARYKEY, diff --git a/core/translate/update.rs b/core/translate/update.rs index 14d5f46d2..8f565b630 100644 --- a/core/translate/update.rs +++ b/core/translate/update.rs @@ -379,7 +379,8 @@ pub fn prepare_update_plan( // If the rowid alias is used in the SET clause, we need to update all indexes indexes.to_vec() } else { - // otherwise we need to update the indexes whose columns are set in the SET clause + // otherwise we need to update the indexes whose columns are set in the SET clause, + // or if the colunns used in the partial index WHERE clause are being updated indexes .iter() .filter_map(|idx| { @@ -390,20 +391,20 @@ pub fn prepare_update_plan( if !needs { if let Some(w) = &idx.where_clause { - // Bind once so names→positions are resolved exactly like execution. let mut where_copy = w.as_ref().clone(); let mut param = ParamState::disallow(); let mut tr = TableReferences::new(table_references.joined_tables().to_vec(), vec![]); - bind_and_rewrite_expr( + let _ = bind_and_rewrite_expr( &mut where_copy, Some(&mut tr), None, connection, &mut param, - ) - .expect("bind where"); + ); let cols_used = collect_cols_used_in_expr(&where_copy); + // if any of the columns used in the partial index WHERE clause is being + // updated, we need to update this index needs = cols_used.iter().any(|c| updated_cols.contains(c)); } }