diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 1d05f1bd7..efe276ca5 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -5,6 +5,7 @@ use crate::storage::database::FileMemoryStorage; use crate::storage::page_cache::DumbLruPageCache; use crate::storage::pager::CreateBTreeFlags; use crate::storage::wal::DummyWAL; +use crate::translate::collate::CollationSeq; use crate::types::ImmutableRecord; use crate::{ error::{LimboError, SQLITE_CONSTRAINT, SQLITE_CONSTRAINT_PRIMARYKEY}, @@ -531,38 +532,176 @@ pub fn op_not_null( Ok(InsnFunctionStepResult::Step) } -pub fn op_eq( +#[derive(Debug, Clone, Copy, PartialEq)] +enum ComparisonOp { + Eq, + Ne, + Lt, + Le, + Gt, + Ge, +} + +impl ComparisonOp { + fn compare(&self, lhs: &Value, rhs: &Value, collation: &CollationSeq) -> bool { + match (lhs, rhs) { + (Value::Text(lhs_text), Value::Text(rhs_text)) => { + let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); + match self { + ComparisonOp::Eq => order.is_eq(), + ComparisonOp::Ne => order.is_ne(), + ComparisonOp::Lt => order.is_lt(), + ComparisonOp::Le => order.is_le(), + ComparisonOp::Gt => order.is_gt(), + ComparisonOp::Ge => order.is_ge(), + } + } + (_, _) => match self { + ComparisonOp::Eq => *lhs == *rhs, + ComparisonOp::Ne => *lhs != *rhs, + ComparisonOp::Lt => *lhs < *rhs, + ComparisonOp::Le => *lhs <= *rhs, + ComparisonOp::Gt => *lhs > *rhs, + ComparisonOp::Ge => *lhs >= *rhs, + }, + } + } + + fn compare_integers(&self, lhs: &Value, rhs: &Value) -> bool { + match self { + ComparisonOp::Eq => lhs == rhs, + ComparisonOp::Ne => lhs != rhs, + ComparisonOp::Lt => lhs < rhs, + ComparisonOp::Le => lhs <= rhs, + ComparisonOp::Gt => lhs > rhs, + ComparisonOp::Ge => lhs >= rhs, + } + } + + fn handle_nulls(&self, lhs: &Value, rhs: &Value, null_eq: bool, jump_if_null: bool) -> bool { + match self { + ComparisonOp::Eq => { + let both_null = lhs == rhs; + (null_eq && both_null) || (!null_eq && jump_if_null) + } + ComparisonOp::Ne => { + let at_least_one_null = lhs != rhs; + (null_eq && at_least_one_null) || (!null_eq && jump_if_null) + } + ComparisonOp::Lt | ComparisonOp::Le | ComparisonOp::Gt | ComparisonOp::Ge => { + jump_if_null + } + } + } +} + +pub fn op_comparison( program: &Program, state: &mut ProgramState, insn: &Insn, pager: &Rc, mv_store: Option<&Rc>, ) -> Result { - let Insn::Eq { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn {:?}", insn) + let (lhs, rhs, target_pc, flags, collation, op) = match insn { + Insn::Eq { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Eq, + ), + Insn::Ne { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Ne, + ), + Insn::Lt { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Lt, + ), + Insn::Le { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Le, + ), + Insn::Gt { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Gt, + ), + Insn::Ge { + lhs, + rhs, + target_pc, + flags, + collation, + } => ( + *lhs, + *rhs, + *target_pc, + *flags, + collation.unwrap_or_default(), + ComparisonOp::Ge, + ), + _ => unreachable!("unexpected Insn {:?}", insn), }; + assert!(target_pc.is_offset()); - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; + let nulleq = flags.has_nulleq(); let jump_if_null = flags.has_jump_if_null(); let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); let lhs_value = state.registers[lhs].get_owned_value(); let rhs_value = state.registers[rhs].get_owned_value(); // Fast path for integers if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value == rhs_value { + if op.compare_integers(lhs_value, rhs_value) { state.pc = target_pc.to_offset_int(); } else { state.pc += 1; @@ -572,8 +711,7 @@ pub fn op_eq( // Handle NULL values if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - let cond = lhs_value == rhs_value; // Both NULL - if (nulleq && cond) || (!nulleq && jump_if_null) { + if op.handle_nulls(lhs_value, rhs_value, nulleq, jump_if_null) { state.pc = target_pc.to_offset_int(); } else { state.pc += 1; @@ -587,6 +725,7 @@ pub fn op_eq( let mut lhs_converted = false; let mut rhs_converted = false; + // Apply affinity conversions match affinity { Affinity::Numeric | Affinity::Integer => { let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); @@ -640,696 +779,16 @@ pub fn op_eq( Affinity::Blob => {} // Do nothing for blob affinity. } - let should_jump = match ( + let should_jump = op.compare( lhs_temp_reg.get_owned_value(), rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_eq() - } - (lhs, rhs) => *lhs == *rhs, - }; + &collation, + ); if lhs_converted { state.registers[lhs] = lhs_temp_reg; } - if rhs_converted { - state.registers[rhs] = rhs_temp_reg; - } - if should_jump { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - - Ok(InsnFunctionStepResult::Step) -} - -pub fn op_ne( - program: &Program, - state: &mut ProgramState, - insn: &Insn, - pager: &Rc, - mv_store: Option<&Rc>, -) -> Result { - let Insn::Ne { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn {:?}", insn) - }; - assert!(target_pc.is_offset()); - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; - let nulleq = flags.has_nulleq(); - let jump_if_null = flags.has_jump_if_null(); - let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); - - let lhs_value = state.registers[lhs].get_owned_value(); - let rhs_value = state.registers[rhs].get_owned_value(); - - // Fast path for integers - if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value != rhs_value { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - // Handle NULL values - if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - let cond = lhs_value != rhs_value; // At least one NULL - if (nulleq && cond) || (!nulleq && jump_if_null) { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - let mut lhs_temp_reg = state.registers[lhs].clone(); - let mut rhs_temp_reg = state.registers[rhs].clone(); - - let mut lhs_converted = false; - let mut rhs_converted = false; - - match affinity { - Affinity::Numeric | Affinity::Integer => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if lhs_is_text { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if rhs_is_text { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - } - } - - Affinity::Text => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if is_numeric_value(&lhs_temp_reg) { - lhs_converted = stringify_register(&mut lhs_temp_reg); - } - - if is_numeric_value(&rhs_temp_reg) { - rhs_converted = stringify_register(&mut rhs_temp_reg); - } - } - } - - Affinity::Real => { - if matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)) { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - - if matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)) { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - - if let Value::Integer(i) = lhs_temp_reg.get_owned_value() { - lhs_temp_reg = Register::Value(Value::Float(*i as f64)); - lhs_converted = true; - } - - if let Value::Integer(i) = rhs_temp_reg.get_owned_value() { - rhs_temp_reg = Register::Value(Value::Float(*i as f64)); - rhs_converted = true; - } - } - - Affinity::Blob => {} // Do nothing for blob affinity. - } - - let should_jump = match ( - lhs_temp_reg.get_owned_value(), - rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_ne() - } - (lhs, rhs) => *lhs != *rhs, - }; - - if lhs_converted { - state.registers[lhs] = lhs_temp_reg; - } - if rhs_converted { - state.registers[rhs] = rhs_temp_reg; - } - - if should_jump { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - - Ok(InsnFunctionStepResult::Step) -} - -pub fn op_lt( - program: &Program, - state: &mut ProgramState, - insn: &Insn, - pager: &Rc, - mv_store: Option<&Rc>, -) -> Result { - let Insn::Lt { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn {:?}", insn) - }; - assert!(target_pc.is_offset()); - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; - let jump_if_null = flags.has_jump_if_null(); - let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); - - let lhs_value = state.registers[lhs].get_owned_value(); - let rhs_value = state.registers[rhs].get_owned_value(); - - // Fast path for integers - if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value < rhs_value { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - // Handle NULL values - if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - if jump_if_null { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - let mut lhs_temp_reg = state.registers[lhs].clone(); - let mut rhs_temp_reg = state.registers[rhs].clone(); - - let mut lhs_converted = false; - let mut rhs_converted = false; - - match affinity { - Affinity::Numeric | Affinity::Integer => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if lhs_is_text { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if rhs_is_text { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - } - } - - Affinity::Text => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if is_numeric_value(&lhs_temp_reg) { - lhs_converted = stringify_register(&mut lhs_temp_reg); - } - - if is_numeric_value(&rhs_temp_reg) { - rhs_converted = stringify_register(&mut rhs_temp_reg); - } - } - } - - Affinity::Real => { - if matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)) { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - - if matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)) { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - - if let Value::Integer(i) = lhs_temp_reg.get_owned_value() { - lhs_temp_reg = Register::Value(Value::Float(*i as f64)); - lhs_converted = true; - } - - if let Value::Integer(i) = rhs_temp_reg.get_owned_value() { - rhs_temp_reg = Register::Value(Value::Float(*i as f64)); - rhs_converted = true; - } - } - - Affinity::Blob => {} // Do nothing for blob affinity. - } - - let should_jump = match ( - lhs_temp_reg.get_owned_value(), - rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_lt() - } - (lhs, rhs) => *lhs < *rhs, - }; - - if lhs_converted { - state.registers[lhs] = lhs_temp_reg; - } - if rhs_converted { - state.registers[rhs] = rhs_temp_reg; - } - - if should_jump { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - - Ok(InsnFunctionStepResult::Step) -} - -pub fn op_le( - program: &Program, - state: &mut ProgramState, - insn: &Insn, - pager: &Rc, - mv_store: Option<&Rc>, -) -> Result { - let Insn::Le { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn {:?}", insn) - }; - assert!(target_pc.is_offset()); - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; - let jump_if_null = flags.has_jump_if_null(); - let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); - - let lhs_value = state.registers[lhs].get_owned_value(); - let rhs_value = state.registers[rhs].get_owned_value(); - - // Fast path for integers - if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value <= rhs_value { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - // Handle NULL values - if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - if jump_if_null { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - let mut lhs_temp_reg = state.registers[lhs].clone(); - let mut rhs_temp_reg = state.registers[rhs].clone(); - - let mut lhs_converted = false; - let mut rhs_converted = false; - - match affinity { - Affinity::Numeric | Affinity::Integer => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if lhs_is_text { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if rhs_is_text { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - } - } - - Affinity::Text => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if is_numeric_value(&lhs_temp_reg) { - lhs_converted = stringify_register(&mut lhs_temp_reg); - } - - if is_numeric_value(&rhs_temp_reg) { - rhs_converted = stringify_register(&mut rhs_temp_reg); - } - } - } - - Affinity::Real => { - if matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)) { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - - if matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)) { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - - if let Value::Integer(i) = lhs_temp_reg.get_owned_value() { - lhs_temp_reg = Register::Value(Value::Float(*i as f64)); - lhs_converted = true; - } - - if let Value::Integer(i) = rhs_temp_reg.get_owned_value() { - rhs_temp_reg = Register::Value(Value::Float(*i as f64)); - rhs_converted = true; - } - } - - Affinity::Blob => {} // Do nothing for blob affinity. - } - - let should_jump = match ( - lhs_temp_reg.get_owned_value(), - rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_le() - } - (lhs, rhs) => *lhs <= *rhs, - }; - - if lhs_converted { - state.registers[lhs] = lhs_temp_reg; - } - if rhs_converted { - state.registers[rhs] = rhs_temp_reg; - } - - if should_jump { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - - Ok(InsnFunctionStepResult::Step) -} - -pub fn op_gt( - program: &Program, - state: &mut ProgramState, - insn: &Insn, - pager: &Rc, - mv_store: Option<&Rc>, -) -> Result { - let Insn::Gt { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn {:?}", insn) - }; - assert!(target_pc.is_offset()); - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; - let jump_if_null = flags.has_jump_if_null(); - let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); - - let lhs_value = state.registers[lhs].get_owned_value(); - let rhs_value = state.registers[rhs].get_owned_value(); - - // Fast path for integers - if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value > rhs_value { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - // Handle NULL values - if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - if jump_if_null { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - let mut lhs_temp_reg = state.registers[lhs].clone(); - let mut rhs_temp_reg = state.registers[rhs].clone(); - - let mut lhs_converted = false; - let mut rhs_converted = false; - - match affinity { - Affinity::Numeric | Affinity::Integer => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if lhs_is_text { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if rhs_is_text { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - } - } - - Affinity::Text => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if is_numeric_value(&lhs_temp_reg) { - lhs_converted = stringify_register(&mut lhs_temp_reg); - } - - if is_numeric_value(&rhs_temp_reg) { - rhs_converted = stringify_register(&mut rhs_temp_reg); - } - } - } - - Affinity::Real => { - if matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)) { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)) { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - - if let Value::Integer(i) = lhs_temp_reg.get_owned_value() { - lhs_temp_reg = Register::Value(Value::Float(*i as f64)); - lhs_converted = true; - } - - if let Value::Integer(i) = rhs_temp_reg.get_owned_value() { - rhs_temp_reg = Register::Value(Value::Float(*i as f64)); - rhs_converted = true; - } - } - - Affinity::Blob => {} // Do nothing for blob affinity. - } - - let should_jump = match ( - lhs_temp_reg.get_owned_value(), - rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_gt() - } - (lhs, rhs) => *lhs > *rhs, - }; - - if lhs_converted { - state.registers[lhs] = lhs_temp_reg; - } - if rhs_converted { - state.registers[rhs] = rhs_temp_reg; - } - - if should_jump { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - Ok(InsnFunctionStepResult::Step) -} - -pub fn op_ge( - program: &Program, - state: &mut ProgramState, - insn: &Insn, - pager: &Rc, - mv_store: Option<&Rc>, -) -> Result { - let Insn::Ge { - lhs, - rhs, - target_pc, - flags, - collation, - } = insn - else { - unreachable!("unexpected Insn: {:?}", insn) - }; - - assert!(target_pc.is_offset()); - - let lhs = *lhs; - let rhs = *rhs; - let target_pc = *target_pc; - let jump_if_null = flags.has_jump_if_null(); - let affinity = flags.get_affinity(); - let collation = collation.unwrap_or_default(); - - let lhs_value = state.registers[lhs].get_owned_value(); - let rhs_value = state.registers[rhs].get_owned_value(); - - if matches!(lhs_value, Value::Integer(_)) && matches!(rhs_value, Value::Integer(_)) { - if lhs_value >= rhs_value { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - if matches!(lhs_value, Value::Null) || matches!(rhs_value, Value::Null) { - if jump_if_null { - state.pc = target_pc.to_offset_int(); - } else { - state.pc += 1; - } - return Ok(InsnFunctionStepResult::Step); - } - - let mut lhs_temp_reg = state.registers[lhs].clone(); - let mut rhs_temp_reg = state.registers[rhs].clone(); - - let mut lhs_converted = false; - let mut rhs_converted = false; - - match affinity { - Affinity::Numeric | Affinity::Integer => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if lhs_is_text { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if rhs_is_text { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - } - } - - Affinity::Text => { - let lhs_is_text = matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)); - let rhs_is_text = matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)); - - if lhs_is_text || rhs_is_text { - if is_numeric_value(&lhs_temp_reg) { - lhs_converted = stringify_register(&mut lhs_temp_reg); - } - - if is_numeric_value(&rhs_temp_reg) { - rhs_converted = stringify_register(&mut rhs_temp_reg); - } - } - } - - Affinity::Real => { - if matches!(lhs_temp_reg.get_owned_value(), Value::Text(_)) { - lhs_converted = apply_numeric_affinity(&mut lhs_temp_reg, false); - } - if matches!(rhs_temp_reg.get_owned_value(), Value::Text(_)) { - rhs_converted = apply_numeric_affinity(&mut rhs_temp_reg, false); - } - - if let Value::Integer(i) = lhs_temp_reg.get_owned_value() { - lhs_temp_reg = Register::Value(Value::Float(*i as f64)); - lhs_converted = true; - } - - if let Value::Integer(i) = rhs_temp_reg.get_owned_value() { - rhs_temp_reg = Register::Value(Value::Float(*i as f64)); - rhs_converted = true; - } - } - - Affinity::Blob => {} // Do nothing for blob affinity. - } - - let should_jump = match ( - lhs_temp_reg.get_owned_value(), - rhs_temp_reg.get_owned_value(), - ) { - (Value::Text(lhs_text), Value::Text(rhs_text)) => { - let order = collation.compare_strings(lhs_text.as_str(), rhs_text.as_str()); - order.is_ge() - } - - (lhs, rhs) => { - if *lhs >= *rhs { - true - } else { - false - } - } - }; - - if lhs_converted { - state.registers[lhs] = lhs_temp_reg; - } if rhs_converted { state.registers[rhs] = rhs_temp_reg; } diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 11632e96f..59f875423 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -951,12 +951,12 @@ impl Insn { Insn::Move { .. } => execute::op_move, Insn::IfPos { .. } => execute::op_if_pos, Insn::NotNull { .. } => execute::op_not_null, - Insn::Eq { .. } => execute::op_eq, - Insn::Ne { .. } => execute::op_ne, - Insn::Lt { .. } => execute::op_lt, - Insn::Le { .. } => execute::op_le, - Insn::Gt { .. } => execute::op_gt, - Insn::Ge { .. } => execute::op_ge, + Insn::Eq { .. } + | Insn::Ne { .. } + | Insn::Lt { .. } + | Insn::Le { .. } + | Insn::Gt { .. } + | Insn::Ge { .. } => execute::op_comparison, Insn::If { .. } => execute::op_if, Insn::IfNot { .. } => execute::op_if_not, Insn::OpenRead { .. } => execute::op_open_read,