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