Merge 'Enhance robusteness of optimization for Binary expressions' from Diego Reis

fix #1318

Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #1322
This commit is contained in:
Jussi Saurio
2025-04-13 17:01:53 +03:00
2 changed files with 26 additions and 4 deletions

View File

@@ -4,7 +4,7 @@ use limbo_sqlite3_parser::ast::{self, UnaryOperator};
use crate::function::JsonFunc;
use crate::function::{Func, FuncCtx, MathFuncArity, ScalarFunc, VectorFunc};
use crate::schema::{Table, Type};
use crate::util::normalize_ident;
use crate::util::{exprs_are_equivalent, normalize_ident};
use crate::vdbe::{
builder::ProgramBuilder,
insn::{CmpInsFlags, Insn},
@@ -494,8 +494,8 @@ pub fn translate_expr(
match expr {
ast::Expr::Between { .. } => todo!(),
ast::Expr::Binary(e1, op, e2) => {
// Check if both sides of the expression are identical and reuse the same register if so
if e1 == e2 {
// Check if both sides of the expression are equivalent and reuse the same register if so
if exprs_are_equivalent(e1, e2) {
let shared_reg = program.alloc_register();
translate_expr(program, referenced_tables, e1, shared_reg, resolver)?;

View File

@@ -399,7 +399,11 @@ pub fn exprs_are_equivalent(expr1: &Expr, expr2: &Expr) -> bool {
(Expr::Unary(op1, expr1), Expr::Unary(op2, expr2)) => {
op1 == op2 && exprs_are_equivalent(expr1, expr2)
}
(Expr::Variable(var1), Expr::Variable(var2)) => var1 == var2,
// Variables that are not bound to a specific value, are treated as NULL
// https://sqlite.org/lang_expr.html#varparam
(Expr::Variable(var), Expr::Variable(var2)) if var == "" && var2 == "" => false,
// Named variables can be compared by their name
(Expr::Variable(val), Expr::Variable(val2)) => val == val2,
(Expr::Parenthesized(exprs1), Expr::Parenthesized(exprs2)) => {
exprs1.len() == exprs2.len()
&& exprs1
@@ -945,6 +949,24 @@ pub mod tests {
assert_eq!(normalize_ident("\"foo\""), "foo");
}
#[test]
fn test_anonymous_variable_comparison() {
let expr1 = Expr::Variable("".to_string());
let expr2 = Expr::Variable("".to_string());
assert!(!exprs_are_equivalent(&expr1, &expr2));
}
#[test]
fn test_named_variable_comparison() {
let expr1 = Expr::Variable("1".to_string());
let expr2 = Expr::Variable("1".to_string());
assert!(exprs_are_equivalent(&expr1, &expr2));
let expr1 = Expr::Variable("1".to_string());
let expr2 = Expr::Variable("2".to_string());
assert!(!exprs_are_equivalent(&expr1, &expr2));
}
#[test]
fn test_basic_addition_exprs_are_equivalent() {
let expr1 = Expr::Binary(