Add Or bytecode

Take the logical OR of the values in register P1 and P2 and store the answer in register P3. If either P1 or P2 is nonzero (true) then the result is 1 (true) even if the other input is NULL. A NULL and false or two NULLs give a NULL output.
This commit is contained in:
Diego Reis
2025-01-25 02:54:14 -03:00
parent aff454b5f6
commit e7d95399e3
5 changed files with 115 additions and 3 deletions

View File

@@ -493,7 +493,7 @@ Modifiers:
| OpenWrite | No |
| OpenWriteAsync | Yes |
| OpenWriteAwait | Yes |
| Or | No |
| Or | Yes |
| Pagecount | No |
| Param | No |
| ParseSchema | No |

View File

@@ -612,6 +612,13 @@ pub fn translate_expr(
dest: target_register,
});
}
ast::Operator::Or => {
program.emit_insn(Insn::Or {
lhs: e1_reg,
rhs: e2_reg,
dest: target_register,
});
}
ast::Operator::BitwiseAnd => {
program.emit_insn(Insn::BitAnd {
lhs: e1_reg,

View File

@@ -1129,6 +1129,15 @@ pub fn insn_to_str(
0,
format!("r[{}]=(r[{}] && r[{}])", dest, lhs, rhs),
),
Insn::Or { lhs, rhs, dest } => (
"Or",
*rhs as i32,
*lhs as i32,
*dest as i32,
OwnedValue::build_text(Rc::new("".to_string())),
0,
format!("r[{}]=(r[{}] || r[{}])", dest, lhs, rhs),
),
};
format!(
"{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}",

View File

@@ -557,6 +557,12 @@ pub enum Insn {
rhs: usize,
dest: usize,
},
/// Take the logical OR of the values in register P1 and P2 and store the answer in register P3.
Or {
lhs: usize,
rhs: usize,
dest: usize,
},
}
fn cast_text_to_numerical(value: &str) -> OwnedValue {
@@ -980,9 +986,43 @@ pub fn exec_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
if let OwnedValue::Agg(agg) = lhs {
lhs = agg.final_value();
}
if let OwnedValue::Agg(agg) = rhs {
rhs = agg.final_value();
}
match (lhs, rhs) {
(OwnedValue::Null, OwnedValue::Null)
| (OwnedValue::Null, OwnedValue::Float(0.0))
| (OwnedValue::Float(0.0), OwnedValue::Null)
| (OwnedValue::Null, OwnedValue::Integer(0))
| (OwnedValue::Integer(0), OwnedValue::Null) => OwnedValue::Null,
(OwnedValue::Float(0.0), OwnedValue::Integer(0))
| (OwnedValue::Integer(0), OwnedValue::Float(0.0))
| (OwnedValue::Float(0.0), OwnedValue::Float(0.0))
| (OwnedValue::Integer(0), OwnedValue::Integer(0)) => OwnedValue::Integer(0),
(OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_or(
&cast_text_to_numerical(&lhs.value),
&cast_text_to_numerical(&rhs.value),
),
(OwnedValue::Text(text), other) | (other, OwnedValue::Text(text)) => {
exec_or(&cast_text_to_numerical(&text.value), other)
}
_ => OwnedValue::Integer(1),
}
}
#[cfg(test)]
mod tests {
use crate::types::OwnedValue;
use std::rc::Rc;
use crate::{
types::{LimboText, OwnedValue},
vdbe::insn::exec_or,
};
use super::exec_and;
@@ -1012,4 +1052,54 @@ mod tests {
assert_eq!(exec_and(lhs, rhs), outpus[i]);
}
}
#[test]
fn test_exec_or() {
let inputs = vec![
(OwnedValue::Integer(0), OwnedValue::Null),
(OwnedValue::Null, OwnedValue::Integer(1)),
(OwnedValue::Null, OwnedValue::Null),
(OwnedValue::Float(0.0), OwnedValue::Null),
(OwnedValue::Integer(1), OwnedValue::Float(2.2)),
(OwnedValue::Float(0.0), OwnedValue::Integer(0)),
(
OwnedValue::Integer(0),
OwnedValue::Text(LimboText::new(Rc::new("string".to_string()))),
),
(
OwnedValue::Integer(0),
OwnedValue::Text(LimboText::new(Rc::new("1".to_string()))),
),
(
OwnedValue::Integer(0),
OwnedValue::Text(LimboText::new(Rc::new("".to_string()))),
),
];
let outpus = vec![
OwnedValue::Null,
OwnedValue::Integer(1),
OwnedValue::Null,
OwnedValue::Null,
OwnedValue::Integer(1),
OwnedValue::Integer(0),
OwnedValue::Integer(0),
OwnedValue::Integer(1),
OwnedValue::Integer(0),
];
assert_eq!(
inputs.len(),
outpus.len(),
"Inputs and Outputs should have same size"
);
for (i, (lhs, rhs)) in inputs.iter().enumerate() {
assert_eq!(
exec_or(lhs, rhs),
outpus[i],
"Wrong OR for lhs: {}, rhs: {}",
lhs,
rhs
);
}
}
}

View File

@@ -47,7 +47,8 @@ use crate::{resolve_ext_path, Connection, Result, Rows, TransactionState, DATABA
use datetime::{exec_date, exec_datetime_full, exec_julianday, exec_time, exec_unixepoch};
use insn::{
exec_add, exec_and, exec_bit_and, exec_bit_not, exec_bit_or, exec_boolean_not, exec_concat,
exec_divide, exec_multiply, exec_remainder, exec_shift_left, exec_shift_right, exec_subtract,
exec_divide, exec_multiply, exec_or, exec_remainder, exec_shift_left, exec_shift_right,
exec_subtract,
};
use likeop::{construct_like_escape_arg, exec_glob, exec_like_with_escape};
use rand::distributions::{Distribution, Uniform};
@@ -2351,6 +2352,11 @@ impl Program {
exec_and(&state.registers[*lhs], &state.registers[*rhs]);
state.pc += 1;
}
Insn::Or { lhs, rhs, dest } => {
state.registers[*dest] =
exec_or(&state.registers[*lhs], &state.registers[*rhs]);
state.pc += 1;
}
}
}
}