alopex_sql/executor/evaluator/
mod.rs1pub(crate) mod binary_op;
8mod case_expr;
9mod column_ref;
10pub(crate) mod conditional;
11mod context;
12pub(crate) mod datetime;
13mod function_call;
14pub(crate) mod hash;
15mod is_null;
16mod literal;
17pub(crate) mod numeric;
18pub(crate) mod pattern;
19pub mod registry;
20pub(crate) mod string;
21mod timestamp;
22pub(crate) mod type_fn;
23mod unary_op;
24pub mod vector_ops;
25
26pub use vector_ops::{VectorError, VectorMetric, vector_distance, vector_similarity};
27
28pub use context::EvalContext;
29pub(crate) use context::begin_statement;
30pub(crate) use timestamp::coerce_value;
31
32use crate::executor::{EvaluationError, ExecutorError, Result};
33use crate::planner::typed_expr::TypedExpr;
34use crate::planner::typed_expr::TypedExprKind;
35use crate::storage::SqlValue;
36
37pub fn evaluate(expr: &TypedExpr, ctx: &EvalContext<'_>) -> Result<SqlValue> {
39 match &expr.kind {
40 TypedExprKind::Literal(lit) => literal::eval_literal(lit, &expr.resolved_type),
41 TypedExprKind::ColumnRef { column_index, .. } => {
42 column_ref::eval_column_ref(*column_index, ctx)
43 }
44 TypedExprKind::BinaryOp { left, op, right } => {
45 binary_op::eval_binary_op(op, left, right, ctx)
46 }
47 TypedExprKind::UnaryOp { op, operand } => unary_op::eval_unary_op(op, operand, ctx),
48 TypedExprKind::Case {
49 operand,
50 branches,
51 else_expr,
52 } => case_expr::evaluate_case(operand.as_deref(), branches, else_expr.as_deref(), ctx),
53 TypedExprKind::IsNull { expr, negated } => is_null::eval_is_null(expr, *negated, ctx),
54 TypedExprKind::VectorLiteral(values) => {
55 Ok(SqlValue::Vector(values.iter().map(|v| *v as f32).collect()))
56 }
57 TypedExprKind::FunctionCall {
58 name,
59 args,
60 distinct,
61 star,
62 over,
63 } => {
64 if over.is_some() {
65 return Err(ExecutorError::InvalidOperation {
66 operation: "evaluate window function as scalar expression".into(),
67 reason: "window expressions must be evaluated by the Window operator".into(),
68 });
69 }
70 function_call::evaluate_function_call(name, args, *distinct, *star, ctx)
71 }
72 TypedExprKind::Cast { expr, target_type } => {
73 timestamp::evaluate_cast(expr, target_type, ctx)
74 }
75 TypedExprKind::Like {
76 expr,
77 pattern,
78 escape,
79 negated,
80 kind,
81 } => pattern::evaluate_pattern(expr, pattern, escape.as_deref(), *negated, *kind, ctx),
82 TypedExprKind::Between {
83 expr,
84 low,
85 high,
86 negated,
87 } => evaluate_between(expr, low, high, *negated, ctx),
88 TypedExprKind::InList {
89 expr,
90 list,
91 negated,
92 } => evaluate_in_list(expr, list, *negated, ctx),
93 other => Err(ExecutorError::Evaluation(
95 EvaluationError::UnsupportedExpression(format!("{other:?}")),
96 )),
97 }
98}
99
100fn evaluate_between(
101 expr: &TypedExpr,
102 low: &TypedExpr,
103 high: &TypedExpr,
104 negated: bool,
105 ctx: &EvalContext<'_>,
106) -> Result<SqlValue> {
107 let value = evaluate(expr, ctx)?;
108 let lower = binary_op::eval_binary_values(
109 &crate::ast::expr::BinaryOp::GtEq,
110 value.clone(),
111 evaluate(low, ctx)?,
112 )?;
113 let upper = binary_op::eval_binary_values(
114 &crate::ast::expr::BinaryOp::LtEq,
115 value,
116 evaluate(high, ctx)?,
117 )?;
118 let result = binary_op::eval_binary_values(&crate::ast::expr::BinaryOp::And, lower, upper)?;
119 negate_predicate(result, negated)
120}
121
122fn evaluate_in_list(
123 expr: &TypedExpr,
124 list: &[TypedExpr],
125 negated: bool,
126 ctx: &EvalContext<'_>,
127) -> Result<SqlValue> {
128 let value = evaluate(expr, ctx)?;
129 let mut unknown = false;
130
131 for item in list {
132 match binary_op::eval_binary_values(
133 &crate::ast::expr::BinaryOp::Eq,
134 value.clone(),
135 evaluate(item, ctx)?,
136 )? {
137 SqlValue::Boolean(true) => return Ok(SqlValue::Boolean(!negated)),
138 SqlValue::Boolean(false) => {}
139 SqlValue::Null => unknown = true,
140 other => {
141 return Err(ExecutorError::Evaluation(EvaluationError::TypeMismatch {
142 expected: "Boolean".into(),
143 actual: other.type_name().into(),
144 }));
145 }
146 }
147 }
148
149 if unknown {
150 Ok(SqlValue::Null)
151 } else {
152 Ok(SqlValue::Boolean(negated))
153 }
154}
155
156fn negate_predicate(value: SqlValue, negated: bool) -> Result<SqlValue> {
157 if !negated {
158 return Ok(value);
159 }
160 match value {
161 SqlValue::Boolean(value) => Ok(SqlValue::Boolean(!value)),
162 SqlValue::Null => Ok(SqlValue::Null),
163 other => Err(ExecutorError::Evaluation(EvaluationError::TypeMismatch {
164 expected: "Boolean".into(),
165 actual: other.type_name().into(),
166 })),
167 }
168}