From c6ef4898b0770404c11ff3efa5ec2b0fa737e071 Mon Sep 17 00:00:00 2001 From: meteorgan Date: Tue, 24 Jun 2025 22:05:55 +0800 Subject: [PATCH] fix: IdxDelete shouldn't raise error if P5 == 0 --- core/translate/compound_select.rs | 2 +- core/translate/emitter.rs | 2 ++ core/translate/result_row.rs | 1 + core/vdbe/execute.rs | 10 ++++------ core/vdbe/explain.rs | 3 ++- core/vdbe/insn.rs | 5 +++++ 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/translate/compound_select.rs b/core/translate/compound_select.rs index f5c004c73..58dcd5372 100644 --- a/core/translate/compound_select.rs +++ b/core/translate/compound_select.rs @@ -255,7 +255,7 @@ fn emit_compound_select( } => (cursor_id, index), _ => { new_index = true; - create_dedupe_index(program, &right_most)? + create_dedupe_index(program, &right_most, schema)? } }; plan.query_destination = QueryDestination::EphemeralIndex { diff --git a/core/translate/emitter.rs b/core/translate/emitter.rs index c0f98f101..0b50c40a6 100644 --- a/core/translate/emitter.rs +++ b/core/translate/emitter.rs @@ -565,6 +565,7 @@ fn emit_delete_insns( start_reg, num_regs, cursor_id: index_cursor_id, + raise_error_if_no_matching_entry: true, }); } } @@ -1083,6 +1084,7 @@ fn emit_update_insns( start_reg, num_regs, cursor_id: idx_cursor_id, + raise_error_if_no_matching_entry: true, }); // Insert new index key (filled further above with values from set_clauses) diff --git a/core/translate/result_row.rs b/core/translate/result_row.rs index 70fc4e5ff..62c6bc96a 100644 --- a/core/translate/result_row.rs +++ b/core/translate/result_row.rs @@ -92,6 +92,7 @@ pub fn emit_result_row_and_limit( start_reg: result_columns_start_reg, num_regs: plan.result_columns.len(), cursor_id: *index_cursor_id, + raise_error_if_no_matching_entry: false, }); } else { let record_reg = program.alloc_register(); diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 592070d52..9e77a9afd 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4362,6 +4362,7 @@ pub fn op_idx_delete( cursor_id, start_reg, num_regs, + raise_error_if_no_matching_entry, } = insn else { unreachable!("unexpected Insn {:?}", insn) @@ -4399,12 +4400,9 @@ pub fn op_idx_delete( return_if_io!(cursor.rowid()) }; - if rowid.is_none() { - // If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error if no matching - // index entry is found. This happens when running an UPDATE or DELETE statement and the - // index entry to be updated or deleted is not found. For some uses of IdxDelete - // (example: the EXCEPT operator) it does not matter that no matching entry is found. - // For those cases, P5 is zero. Also, do not raise this (self-correcting and non-critical) error if in writable_schema mode. + // If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found + // Also, do not raise this (self-correcting and non-critical) error if in writable_schema mode. + if rowid.is_none() && *raise_error_if_no_matching_entry { return Err(LimboError::Corrupt(format!( "IdxDelete: no matching index entry found for record {:?}", make_record(&state.registers, start_reg, num_regs) diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index 933b82ee2..9a464fdab 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1120,13 +1120,14 @@ pub fn insn_to_str( cursor_id, start_reg, num_regs, + raise_error_if_no_matching_entry } => ( "IdxDelete", *cursor_id as i32, *start_reg as i32, *num_regs as i32, Value::build_text(""), - 0, + *raise_error_if_no_matching_entry as u16, "".to_string(), ), Insn::NewRowid { diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 41ad4e30c..1cb1740e3 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -742,10 +742,15 @@ pub enum Insn { cursor_id: CursorID, }, + /// If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error if no matching index entry + /// is found. This happens when running an UPDATE or DELETE statement and the index entry to + /// be updated or deleted is not found. For some uses of IdxDelete (example: the EXCEPT operator) + /// it does not matter that no matching entry is found. For those cases, P5 is zero. IdxDelete { start_reg: usize, num_regs: usize, cursor_id: CursorID, + raise_error_if_no_matching_entry: bool, // P5 }, NewRowid {