From aff454b5f6318b874b0f5366b6b2e0387d50828b Mon Sep 17 00:00:00 2001 From: Diego Reis Date: Sat, 25 Jan 2025 02:12:50 -0300 Subject: [PATCH] Implement And bytecode Take the logical AND of the values in registers P1 and P2 and write the result into register P3. If either P1 or P2 is 0 (false) then the result is 0 even if the other input is NULL. A NULL and true or two NULLs give a NULL output. --- COMPAT.md | 2 +- core/translate/expr.rs | 7 +++++ core/vdbe/explain.rs | 9 +++++++ core/vdbe/insn.rs | 58 ++++++++++++++++++++++++++++++++++++++++++ core/vdbe/mod.rs | 9 +++++-- 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 17ce24568..b476bc3f0 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -400,7 +400,7 @@ Modifiers: | AggFinal | Yes | | AggStep | Yes | | AggStep | Yes | -| And | No | +| And | Yes | | AutoCommit | No | | BitAnd | Yes | | BitNot | Yes | diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 476b78d77..d522ddec2 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -605,6 +605,13 @@ pub fn translate_expr( dest: target_register, }); } + ast::Operator::And => { + program.emit_insn(Insn::And { + lhs: e1_reg, + rhs: e2_reg, + dest: target_register, + }); + } ast::Operator::BitwiseAnd => { program.emit_insn(Insn::BitAnd { lhs: e1_reg, diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index 80f419ed7..40d6f25e9 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1120,6 +1120,15 @@ pub fn insn_to_str( 0, format!("r[{}]=r[{}] + r[{}]", dest, lhs, rhs), ), + Insn::And { lhs, rhs, dest } => ( + "And", + *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} {}", diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index f3f5e36a7..4e393116c 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -551,6 +551,12 @@ pub enum Insn { rhs: usize, dest: usize, }, + /// Take the logical AND of the values in registers P1 and P2 and write the result into register P3. + And { + lhs: usize, + rhs: usize, + dest: usize, + }, } fn cast_text_to_numerical(value: &str) -> OwnedValue { @@ -955,3 +961,55 @@ pub fn exec_concat(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue { (OwnedValue::Record(_), _) | (_, OwnedValue::Record(_)) => unreachable!(), } } + +pub fn exec_and(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::Integer(0)) + | (OwnedValue::Integer(0), _) + | (_, OwnedValue::Float(0.0)) + | (OwnedValue::Float(0.0), _) => OwnedValue::Integer(0), + (OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null, + _ => OwnedValue::Integer(1), + } +} + +#[cfg(test)] +mod tests { + use crate::types::OwnedValue; + + use super::exec_and; + + #[test] + fn test_exec_and() { + 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)), + ]; + let outpus = vec![ + OwnedValue::Integer(0), + OwnedValue::Null, + OwnedValue::Null, + OwnedValue::Integer(0), + OwnedValue::Integer(1), + ]; + + assert_eq!( + inputs.len(), + outpus.len(), + "Inputs and Outputs should have same size" + ); + for (i, (lhs, rhs)) in inputs.iter().enumerate() { + assert_eq!(exec_and(lhs, rhs), outpus[i]); + } + } +} diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 98b328b71..24eb7657c 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -46,8 +46,8 @@ use crate::{ use crate::{resolve_ext_path, Connection, Result, Rows, TransactionState, DATABASE_VERSION}; use datetime::{exec_date, exec_datetime_full, exec_julianday, exec_time, exec_unixepoch}; use insn::{ - exec_add, 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_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, }; use likeop::{construct_like_escape_arg, exec_glob, exec_like_with_escape}; use rand::distributions::{Distribution, Uniform}; @@ -2346,6 +2346,11 @@ impl Program { exec_concat(&state.registers[*lhs], &state.registers[*rhs]); state.pc += 1; } + Insn::And { lhs, rhs, dest } => { + state.registers[*dest] = + exec_and(&state.registers[*lhs], &state.registers[*rhs]); + state.pc += 1; + } } } }