diff --git a/COMPAT.md b/COMPAT.md index eebc6581b..eba9e9f90 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -415,7 +415,7 @@ Modifiers: | Opcode | Status | Comment | |----------------|--------|---------| | Add | Yes | | -| AddImm | No | | +| AddImm | Yes | | | Affinity | No | | | AggFinal | Yes | | | AggStep | Yes | | diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 4f73be5b1..27e721af9 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -6190,6 +6190,37 @@ pub fn op_shift_left( Ok(InsnFunctionStepResult::Step) } +pub fn op_add_imm( + program: &Program, + state: &mut ProgramState, + insn: &Insn, + pager: &Rc, + mv_store: Option<&Rc>, +) -> Result { + let Insn::AddImm { register, value } = insn else { + unreachable!("unexpected Insn {:?}", insn) + }; + + let current = &state.registers[*register]; + let current_value = match current { + Register::Value(val) => val, + Register::Aggregate(_) => &Value::Null, + Register::Record(_) => &Value::Null, + }; + + let int_val = match current_value { + Value::Integer(i) => i + value, + Value::Float(f) => (*f as i64) + value, + Value::Text(s) => s.as_str().parse::().unwrap_or(0) + value, + Value::Blob(_) => *value, // BLOB becomes the added value + Value::Null => *value, // NULL becomes the added value + }; + + state.registers[*register] = Register::Value(Value::Integer(int_val)); + state.pc += 1; + Ok(InsnFunctionStepResult::Step) +} + pub fn op_variable( program: &Program, state: &mut ProgramState, diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index e022b675c..05d47bd98 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1358,6 +1358,15 @@ pub fn insn_to_str( 0, format!("r[{dest}]=r[{lhs}] << r[{rhs}]"), ), + Insn::AddImm { register, value } => ( + "AddImm", + *register as i32, + *value as i32, + 0, + Value::build_text(""), + 0, + format!("r[{register}]=r[{register}]+{value}"), + ), Insn::Variable { index, dest } => ( "Variable", usize::from(*index) as i32, diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index b801caeb8..36be77658 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -877,6 +877,14 @@ pub enum Insn { dest: usize, }, + /// Add immediate value to register and force integer conversion. + /// Add the constant P2 to the value in register P1. The result is always an integer. + /// To force any register to be an integer, just add 0. + AddImm { + register: usize, // P1: target register + value: i64, // P2: immediate value to add + }, + /// Get parameter variable. Variable { index: NonZero, @@ -1106,6 +1114,7 @@ impl Insn { Insn::ParseSchema { .. } => execute::op_parse_schema, Insn::ShiftRight { .. } => execute::op_shift_right, Insn::ShiftLeft { .. } => execute::op_shift_left, + Insn::AddImm { .. } => execute::op_add_imm, Insn::Variable { .. } => execute::op_variable, Insn::ZeroOrNull { .. } => execute::op_zero_or_null, Insn::Not { .. } => execute::op_not,