From e616bd5361908b0bcaf37df7a4fc60f8dc613f08 Mon Sep 17 00:00:00 2001 From: psvri Date: Mon, 20 Jan 2025 00:21:23 +0530 Subject: [PATCH] Implement Not --- COMPAT.md | 2 +- core/translate/expr.rs | 10 +++++++++- core/vdbe/explain.rs | 9 +++++++++ core/vdbe/insn.rs | 18 ++++++++++++++++++ core/vdbe/mod.rs | 8 ++++++-- testing/math.test | 16 ++++++++++++++++ 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index d7d059264..3a413bf70 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -398,7 +398,7 @@ Modifiers: | NextAsync | Yes | | NextAwait | Yes | | Noop | No | -| Not | No | +| Not | Yes | | NotExists | Yes | | NotFound | No | | NotNull | Yes | diff --git a/core/translate/expr.rs b/core/translate/expr.rs index 3d07459cb..4bcea2e18 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -1748,7 +1748,15 @@ pub fn translate_expr( }); Ok(target_register) } - _ => todo!(), + (UnaryOperator::Not, _) => { + let reg = program.alloc_register(); + translate_expr(program, referenced_tables, expr, reg, resolver)?; + program.emit_insn(Insn::Not { + reg, + dest: target_register, + }); + Ok(target_register) + } }, ast::Expr::Variable(name) => { let index = program.parameters.push(name); diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index 8ab330f24..62cda81bb 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1083,6 +1083,15 @@ pub fn insn_to_str( rg1, rg2, dest, dest ), ), + Insn::Not { reg, dest } => ( + "Not", + *reg as i32, + *dest as i32, + 0, + OwnedValue::build_text(Rc::new("".to_string())), + 0, + format!("r[{}]=!r[{}]", dest, reg), + ), }; format!( "{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}", diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 8d812846b..2e1abb2c1 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -516,6 +516,11 @@ pub enum Insn { rg2: usize, dest: usize, }, + /// Interpret the value in reg as boolean and store its compliment in destination + Not { + reg: usize, + dest: usize, + }, } fn cast_text_to_numerical(value: &str) -> OwnedValue { @@ -845,3 +850,16 @@ fn compute_shr(lhs: i64, rhs: i64) -> i64 { lhs >> rhs } } + +pub fn exec_boolean_not(mut reg: &OwnedValue) -> OwnedValue { + if let OwnedValue::Agg(agg) = reg { + reg = agg.final_value(); + } + match reg { + OwnedValue::Null => OwnedValue::Null, + OwnedValue::Integer(i) => OwnedValue::Integer((*i == 0) as i64), + OwnedValue::Float(f) => OwnedValue::Integer((*f == 0.0) as i64), + OwnedValue::Text(text) => exec_boolean_not(&cast_text_to_numerical(&text.value)), + _ => todo!(), + } +} diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 6e134a6bc..ad281a244 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_divide, exec_multiply, exec_remainder, - exec_shift_left, exec_shift_right, exec_subtract, + exec_add, exec_bit_and, exec_bit_not, exec_bit_or, exec_boolean_not, 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}; @@ -2265,6 +2265,10 @@ impl Program { } state.pc += 1; } + Insn::Not { reg, dest } => { + state.registers[*dest] = exec_boolean_not(&state.registers[*reg]); + state.pc += 1; + } } } } diff --git a/testing/math.test b/testing/math.test index f404d9901..cec5f9a63 100644 --- a/testing/math.test +++ b/testing/math.test @@ -615,6 +615,22 @@ do_execsql_test bitwise-not-zero { SELECT ~0 } {-1} +foreach {testname lhs ans} { + int-1 1 0 + int-2 2 0 + int-3 0 1 + float-1 1.0 0 + float-2 2.0 0 + float-3 0.0 1 + text 'a' 1 + text-int-1 '0' 1 + text-int-2 '1' 0 + text-float-1 '1.0' 0 + text-float-2 '0.0' 1 + null NULL {} +} { + do_execsql_test boolean-not "SELECT not $lhs" $::ans +} do_execsql_test_tolerance pi { SELECT pi()