Evaluate a binary operation
(
&self,
op: &crate::ast::Operator,
left: Value,
right: Value,
)
| 5170 | |
| 5171 | /// Evaluate a binary operation |
| 5172 | fn evaluate_binary_op( |
| 5173 | &self, |
| 5174 | op: &crate::ast::Operator, |
| 5175 | left: Value, |
| 5176 | right: Value, |
| 5177 | ) -> Result<Value, ExecutionError> { |
| 5178 | use crate::ast::Operator; |
| 5179 | |
| 5180 | match (op, &left, &right) { |
| 5181 | // Arithmetic operators |
| 5182 | (Operator::Plus, Value::Number(l), Value::Number(r)) => Ok(Value::Number(l + r)), |
| 5183 | (Operator::Minus, Value::Number(l), Value::Number(r)) => Ok(Value::Number(l - r)), |
| 5184 | (Operator::Star, Value::Number(l), Value::Number(r)) => Ok(Value::Number(l * r)), |
| 5185 | (Operator::Slash, Value::Number(l), Value::Number(r)) => { |
| 5186 | if *r == 0.0 { |
| 5187 | Err(ExecutionError::RuntimeError("Division by zero".to_string())) |
| 5188 | } else { |
| 5189 | Ok(Value::Number(l / r)) |
| 5190 | } |
| 5191 | } |
| 5192 | (Operator::Percent, Value::Number(l), Value::Number(r)) => { |
| 5193 | if *r == 0.0 { |
| 5194 | Err(ExecutionError::RuntimeError("Modulo by zero".to_string())) |
| 5195 | } else { |
| 5196 | Ok(Value::Number(l.rem_euclid(*r))) |
| 5197 | } |
| 5198 | } |
| 5199 | |
| 5200 | // COMPARISON OPERATORS - ISO SQL/GQL Three-Valued Logic Implementation |
| 5201 | // |
| 5202 | // According to ISO SQL:2016 Section 8.2 and ISO GQL:2024 Section 12.3.2: |
| 5203 | // - Any comparison with NULL yields NULL (unknown) |
| 5204 | // - NULL in WHERE clause is treated as FALSE (excludes rows) |
| 5205 | // - This implements three-valued logic (TRUE, FALSE, NULL/UNKNOWN) |
| 5206 | // |
| 5207 | // Reference: SQL Standard ISO/IEC 9075-2:2016, Section 8.2: |
| 5208 | // "If either operand of a comparison is the null value, then the result |
| 5209 | // of the comparison is unknown" |
| 5210 | // |
| 5211 | // Reference: GQL Standard ISO/IEC 39075:2024, Section 12.3.2: |
| 5212 | // "If any operand of a comparison operator is null, the result is null" |
| 5213 | |
| 5214 | // Handle comparison operators with NULL-aware logic |
| 5215 | ( |
| 5216 | Operator::GreaterThan |
| 5217 | | Operator::LessThan |
| 5218 | | Operator::GreaterEqual |
| 5219 | | Operator::LessEqual, |
| 5220 | _, |
| 5221 | _, |
| 5222 | ) => { |
| 5223 | // Check for NULL operands first - return NULL if either is NULL |
| 5224 | if left.is_null() || right.is_null() { |
| 5225 | return Ok(Value::Null); |
| 5226 | } |
| 5227 | |
| 5228 | // Try to compare as numbers first (most common case) |
| 5229 | match (&left, &right) { |
no test coverage detected