diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 2eafed217..7b151c093 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4472,6 +4472,53 @@ pub fn op_once( Ok(InsnFunctionStepResult::Step) } +pub fn op_not_found( + program: &Program, + state: &mut ProgramState, + insn: &Insn, + pager: &Rc, + mv_store: Option<&Rc>, +) -> Result { + let Insn::NotFound { + cursor_id, + target_pc, + record_reg, + num_regs, + } = insn + else { + unreachable!("unexpected Insn {:?}", insn) + }; + + let found = { + let mut cursor = state.get_cursor(*cursor_id); + let cursor = cursor.as_btree_mut(); + + if *num_regs == 0 { + let record = match &state.registers[*record_reg] { + Register::Record(r) => r, + _ => { + return Err(LimboError::InternalError( + "NotFound: exepected a record in the register".into(), + )); + } + }; + + return_if_io!(cursor.seek(SeekKey::IndexKey(&record), SeekOp::EQ)) + } else { + let record = make_record(&state.registers, record_reg, num_regs); + return_if_io!(cursor.seek(SeekKey::IndexKey(&record), SeekOp::EQ)) + } + }; + + if found { + state.pc += 1; + } else { + state.pc = target_pc.to_offset_int(); + } + + Ok(InsnFunctionStepResult::Step) +} + fn exec_lower(reg: &OwnedValue) -> Option { match reg { OwnedValue::Text(t) => Some(OwnedValue::build_text(&t.as_str().to_lowercase())), diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index a0ddd6701..8149b4ba6 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1361,6 +1361,24 @@ pub fn insn_to_str( format!("r[{}..{}]=NULL", dest, end) }), ), + Insn::NotFound { + cursor_id, + target_pc, + record_reg, + .. + } => ( + "NotFound", + *cursor_id as i32, + target_pc.to_debug_int(), + *record_reg as i32, + OwnedValue::build_text(""), + 0, + format!( + "if (r[{}] != NULL) goto {}", + record_reg, + target_pc.to_debug_int() + ), + ), }; format!( "{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}", diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index b748706e7..8f1fbe580 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -802,6 +802,13 @@ pub enum Insn { Once { target_pc_when_reentered: BranchOffset, }, + /// Search for record in the index cusor, if exists is a no-op otherwise go to target_pc + NotFound { + cursor_id: CursorID, + target_pc: BranchOffset, + record_reg: usize, + num_regs: usize, + }, } impl Insn { @@ -916,6 +923,7 @@ impl Insn { Insn::ReadCookie { .. } => execute::op_read_cookie, Insn::OpenEphemeral { .. } | Insn::OpenAutoindex { .. } => execute::op_open_ephemeral, Insn::Once { .. } => execute::op_once, + Insn::NotFound { .. } => execute::op_not_found, } } }