Unify comparison function to reduce code duplication

This commit is contained in:
krishvishal
2025-06-07 17:08:10 +05:30
committed by Krishna Vishal
parent 5837f7329f
commit 5a1da026e6
2 changed files with 165 additions and 706 deletions

View File

@@ -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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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<Pager>,
mv_store: Option<&Rc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
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;
}

View File

@@ -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,