sql_cli/data/
arithmetic_evaluator.rs

1use crate::data::datatable::{DataTable, DataValue};
2use crate::sql::recursive_parser::SqlExpression;
3use anyhow::{anyhow, Result};
4use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, TimeZone, Utc};
5use tracing::debug;
6
7/// Evaluates SQL expressions to compute DataValues (for SELECT clauses)
8/// This is different from RecursiveWhereEvaluator which returns boolean
9pub struct ArithmeticEvaluator<'a> {
10    table: &'a DataTable,
11    date_notation: String,
12}
13
14impl<'a> ArithmeticEvaluator<'a> {
15    pub fn new(table: &'a DataTable) -> Self {
16        Self {
17            table,
18            date_notation: "us".to_string(),
19        }
20    }
21
22    pub fn with_date_notation(table: &'a DataTable, date_notation: String) -> Self {
23        Self {
24            table,
25            date_notation,
26        }
27    }
28
29    /// Find a column name similar to the given name using edit distance
30    fn find_similar_column(&self, name: &str) -> Option<String> {
31        let columns = self.table.column_names();
32        let mut best_match: Option<(String, usize)> = None;
33
34        for col in columns {
35            let distance = self.edit_distance(&col.to_lowercase(), &name.to_lowercase());
36            // Only suggest if distance is small (likely a typo)
37            // Allow up to 3 edits for longer names
38            let max_distance = if name.len() > 10 { 3 } else { 2 };
39            if distance <= max_distance {
40                match &best_match {
41                    None => best_match = Some((col, distance)),
42                    Some((_, best_dist)) if distance < *best_dist => {
43                        best_match = Some((col, distance));
44                    }
45                    _ => {}
46                }
47            }
48        }
49
50        best_match.map(|(name, _)| name)
51    }
52
53    /// Calculate Levenshtein edit distance between two strings
54    fn edit_distance(&self, s1: &str, s2: &str) -> usize {
55        let len1 = s1.len();
56        let len2 = s2.len();
57        let mut matrix = vec![vec![0; len2 + 1]; len1 + 1];
58
59        for i in 0..=len1 {
60            matrix[i][0] = i;
61        }
62        for j in 0..=len2 {
63            matrix[0][j] = j;
64        }
65
66        for (i, c1) in s1.chars().enumerate() {
67            for (j, c2) in s2.chars().enumerate() {
68                let cost = if c1 == c2 { 0 } else { 1 };
69                matrix[i + 1][j + 1] = std::cmp::min(
70                    matrix[i][j + 1] + 1, // deletion
71                    std::cmp::min(
72                        matrix[i + 1][j] + 1, // insertion
73                        matrix[i][j] + cost,  // substitution
74                    ),
75                );
76            }
77        }
78
79        matrix[len1][len2]
80    }
81
82    /// Evaluate an SQL expression to produce a DataValue
83    pub fn evaluate(&self, expr: &SqlExpression, row_index: usize) -> Result<DataValue> {
84        debug!(
85            "ArithmeticEvaluator: evaluating {:?} for row {}",
86            expr, row_index
87        );
88
89        match expr {
90            SqlExpression::Column(column_name) => self.evaluate_column(column_name, row_index),
91            SqlExpression::StringLiteral(s) => Ok(DataValue::String(s.clone())),
92            SqlExpression::NumberLiteral(n) => self.evaluate_number_literal(n),
93            SqlExpression::BinaryOp { left, op, right } => {
94                self.evaluate_binary_op(left, op, right, row_index)
95            }
96            SqlExpression::FunctionCall { name, args } => {
97                self.evaluate_function(name, args, row_index)
98            }
99            SqlExpression::MethodCall {
100                object,
101                method,
102                args,
103            } => self.evaluate_method_call(object, method, args, row_index),
104            SqlExpression::ChainedMethodCall { base, method, args } => {
105                // Evaluate the base expression first, then apply the method
106                let base_value = self.evaluate(base, row_index)?;
107                self.evaluate_method_on_value(&base_value, method, args, row_index)
108            }
109            SqlExpression::CaseExpression {
110                when_branches,
111                else_branch,
112            } => self.evaluate_case_expression(when_branches, else_branch, row_index),
113            _ => Err(anyhow!(
114                "Unsupported expression type for arithmetic evaluation: {:?}",
115                expr
116            )),
117        }
118    }
119
120    /// Evaluate a column reference
121    fn evaluate_column(&self, column_name: &str, row_index: usize) -> Result<DataValue> {
122        let col_index = self.table.get_column_index(column_name).ok_or_else(|| {
123            let suggestion = self.find_similar_column(column_name);
124            match suggestion {
125                Some(similar) => anyhow!(
126                    "Column '{}' not found. Did you mean '{}'?",
127                    column_name,
128                    similar
129                ),
130                None => anyhow!("Column '{}' not found", column_name),
131            }
132        })?;
133
134        if row_index >= self.table.row_count() {
135            return Err(anyhow!("Row index {} out of bounds", row_index));
136        }
137
138        let row = self
139            .table
140            .get_row(row_index)
141            .ok_or_else(|| anyhow!("Row {} not found", row_index))?;
142
143        let value = row
144            .get(col_index)
145            .ok_or_else(|| anyhow!("Column index {} out of bounds for row", col_index))?;
146
147        Ok(value.clone())
148    }
149
150    /// Evaluate a number literal (handles both integers and floats)
151    fn evaluate_number_literal(&self, number_str: &str) -> Result<DataValue> {
152        // Try to parse as integer first
153        if let Ok(int_val) = number_str.parse::<i64>() {
154            return Ok(DataValue::Integer(int_val));
155        }
156
157        // If that fails, try as float
158        if let Ok(float_val) = number_str.parse::<f64>() {
159            return Ok(DataValue::Float(float_val));
160        }
161
162        Err(anyhow!("Invalid number literal: {}", number_str))
163    }
164
165    /// Evaluate a binary operation (arithmetic)
166    fn evaluate_binary_op(
167        &self,
168        left: &SqlExpression,
169        op: &str,
170        right: &SqlExpression,
171        row_index: usize,
172    ) -> Result<DataValue> {
173        let left_val = self.evaluate(left, row_index)?;
174        let right_val = self.evaluate(right, row_index)?;
175
176        debug!(
177            "ArithmeticEvaluator: {} {} {}",
178            self.format_value(&left_val),
179            op,
180            self.format_value(&right_val)
181        );
182
183        match op {
184            "+" => self.add_values(&left_val, &right_val),
185            "-" => self.subtract_values(&left_val, &right_val),
186            "*" => self.multiply_values(&left_val, &right_val),
187            "/" => self.divide_values(&left_val, &right_val),
188            // Comparison operators (return boolean results)
189            ">" => self.compare_values(&left_val, &right_val, |a, b| a > b),
190            "<" => self.compare_values(&left_val, &right_val, |a, b| a < b),
191            ">=" => self.compare_values(&left_val, &right_val, |a, b| a >= b),
192            "<=" => self.compare_values(&left_val, &right_val, |a, b| a <= b),
193            "=" => self.compare_values(&left_val, &right_val, |a, b| a == b),
194            "!=" | "<>" => self.compare_values(&left_val, &right_val, |a, b| a != b),
195            _ => Err(anyhow!("Unsupported arithmetic operator: {}", op)),
196        }
197    }
198
199    /// Add two DataValues with type coercion
200    fn add_values(&self, left: &DataValue, right: &DataValue) -> Result<DataValue> {
201        match (left, right) {
202            (DataValue::Integer(a), DataValue::Integer(b)) => Ok(DataValue::Integer(a + b)),
203            (DataValue::Integer(a), DataValue::Float(b)) => Ok(DataValue::Float(*a as f64 + b)),
204            (DataValue::Float(a), DataValue::Integer(b)) => Ok(DataValue::Float(a + *b as f64)),
205            (DataValue::Float(a), DataValue::Float(b)) => Ok(DataValue::Float(a + b)),
206            _ => Err(anyhow!("Cannot add {:?} and {:?}", left, right)),
207        }
208    }
209
210    /// Subtract two DataValues with type coercion
211    fn subtract_values(&self, left: &DataValue, right: &DataValue) -> Result<DataValue> {
212        match (left, right) {
213            (DataValue::Integer(a), DataValue::Integer(b)) => Ok(DataValue::Integer(a - b)),
214            (DataValue::Integer(a), DataValue::Float(b)) => Ok(DataValue::Float(*a as f64 - b)),
215            (DataValue::Float(a), DataValue::Integer(b)) => Ok(DataValue::Float(a - *b as f64)),
216            (DataValue::Float(a), DataValue::Float(b)) => Ok(DataValue::Float(a - b)),
217            _ => Err(anyhow!("Cannot subtract {:?} and {:?}", left, right)),
218        }
219    }
220
221    /// Multiply two DataValues with type coercion
222    fn multiply_values(&self, left: &DataValue, right: &DataValue) -> Result<DataValue> {
223        match (left, right) {
224            (DataValue::Integer(a), DataValue::Integer(b)) => Ok(DataValue::Integer(a * b)),
225            (DataValue::Integer(a), DataValue::Float(b)) => Ok(DataValue::Float(*a as f64 * b)),
226            (DataValue::Float(a), DataValue::Integer(b)) => Ok(DataValue::Float(a * *b as f64)),
227            (DataValue::Float(a), DataValue::Float(b)) => Ok(DataValue::Float(a * b)),
228            _ => Err(anyhow!("Cannot multiply {:?} and {:?}", left, right)),
229        }
230    }
231
232    /// Divide two DataValues with type coercion
233    fn divide_values(&self, left: &DataValue, right: &DataValue) -> Result<DataValue> {
234        // Check for division by zero first
235        let is_zero = match right {
236            DataValue::Integer(0) => true,
237            DataValue::Float(f) if *f == 0.0 => true, // Only check for exact zero, not epsilon
238            _ => false,
239        };
240
241        if is_zero {
242            return Err(anyhow!("Division by zero"));
243        }
244
245        match (left, right) {
246            (DataValue::Integer(a), DataValue::Integer(b)) => {
247                // Integer division - if result is exact, keep as int, otherwise promote to float
248                if a % b == 0 {
249                    Ok(DataValue::Integer(a / b))
250                } else {
251                    Ok(DataValue::Float(*a as f64 / *b as f64))
252                }
253            }
254            (DataValue::Integer(a), DataValue::Float(b)) => Ok(DataValue::Float(*a as f64 / b)),
255            (DataValue::Float(a), DataValue::Integer(b)) => Ok(DataValue::Float(a / *b as f64)),
256            (DataValue::Float(a), DataValue::Float(b)) => Ok(DataValue::Float(a / b)),
257            _ => Err(anyhow!("Cannot divide {:?} and {:?}", left, right)),
258        }
259    }
260
261    /// Format a DataValue for debug output
262    fn format_value(&self, value: &DataValue) -> String {
263        match value {
264            DataValue::Integer(i) => i.to_string(),
265            DataValue::Float(f) => f.to_string(),
266            DataValue::String(s) => format!("'{}'", s),
267            _ => format!("{:?}", value),
268        }
269    }
270
271    /// Compare two DataValues using the provided comparison function
272    fn compare_values<F>(&self, left: &DataValue, right: &DataValue, op: F) -> Result<DataValue>
273    where
274        F: Fn(f64, f64) -> bool,
275    {
276        debug!(
277            "ArithmeticEvaluator: comparing values {:?} and {:?}",
278            left, right
279        );
280
281        let result = match (left, right) {
282            // Integer comparisons
283            (DataValue::Integer(a), DataValue::Integer(b)) => op(*a as f64, *b as f64),
284            (DataValue::Integer(a), DataValue::Float(b)) => op(*a as f64, *b),
285            (DataValue::Float(a), DataValue::Integer(b)) => op(*a, *b as f64),
286            (DataValue::Float(a), DataValue::Float(b)) => op(*a, *b),
287
288            // String comparisons (lexicographic)
289            (DataValue::String(a), DataValue::String(b)) => {
290                let a_num = a.parse::<f64>();
291                let b_num = b.parse::<f64>();
292                match (a_num, b_num) {
293                    (Ok(a_val), Ok(b_val)) => op(a_val, b_val), // Both are numbers
294                    _ => op(a.len() as f64, b.len() as f64),    // Fallback to length comparison
295                }
296            }
297            (DataValue::InternedString(a), DataValue::InternedString(b)) => {
298                let a_num = a.parse::<f64>();
299                let b_num = b.parse::<f64>();
300                match (a_num, b_num) {
301                    (Ok(a_val), Ok(b_val)) => op(a_val, b_val), // Both are numbers
302                    _ => op(a.len() as f64, b.len() as f64),    // Fallback to length comparison
303                }
304            }
305            (DataValue::String(a), DataValue::InternedString(b)) => {
306                let a_num = a.parse::<f64>();
307                let b_num = b.parse::<f64>();
308                match (a_num, b_num) {
309                    (Ok(a_val), Ok(b_val)) => op(a_val, b_val), // Both are numbers
310                    _ => op(a.len() as f64, b.len() as f64),    // Fallback to length comparison
311                }
312            }
313            (DataValue::InternedString(a), DataValue::String(b)) => {
314                let a_num = a.parse::<f64>();
315                let b_num = b.parse::<f64>();
316                match (a_num, b_num) {
317                    (Ok(a_val), Ok(b_val)) => op(a_val, b_val), // Both are numbers
318                    _ => op(a.len() as f64, b.len() as f64),    // Fallback to length comparison
319                }
320            }
321
322            // Mixed type comparisons (try to convert to numbers)
323            (DataValue::String(a), DataValue::Integer(b)) => {
324                match a.parse::<f64>() {
325                    Ok(a_val) => op(a_val, *b as f64),
326                    Err(_) => false, // String can't be compared with number
327                }
328            }
329            (DataValue::Integer(a), DataValue::String(b)) => {
330                match b.parse::<f64>() {
331                    Ok(b_val) => op(*a as f64, b_val),
332                    Err(_) => false, // String can't be compared with number
333                }
334            }
335            (DataValue::String(a), DataValue::Float(b)) => match a.parse::<f64>() {
336                Ok(a_val) => op(a_val, *b),
337                Err(_) => false,
338            },
339            (DataValue::Float(a), DataValue::String(b)) => match b.parse::<f64>() {
340                Ok(b_val) => op(*a, b_val),
341                Err(_) => false,
342            },
343
344            // NULL comparisons
345            (DataValue::Null, _) | (_, DataValue::Null) => false,
346
347            // Boolean comparisons
348            (DataValue::Boolean(a), DataValue::Boolean(b)) => {
349                op(if *a { 1.0 } else { 0.0 }, if *b { 1.0 } else { 0.0 })
350            }
351
352            _ => {
353                debug!(
354                    "ArithmeticEvaluator: unsupported comparison between {:?} and {:?}",
355                    left, right
356                );
357                false
358            }
359        };
360
361        debug!("ArithmeticEvaluator: comparison result: {}", result);
362        Ok(DataValue::Boolean(result))
363    }
364
365    /// Evaluate a function call
366    fn evaluate_function(
367        &self,
368        name: &str,
369        args: &[SqlExpression],
370        row_index: usize,
371    ) -> Result<DataValue> {
372        // Convert function name to uppercase for case-insensitive matching
373        match name.to_uppercase().as_str() {
374            "ROUND" => {
375                if args.is_empty() || args.len() > 2 {
376                    return Err(anyhow!("ROUND requires 1 or 2 arguments"));
377                }
378
379                // Evaluate the value to round
380                let value = self.evaluate(&args[0], row_index)?;
381
382                // Get decimal places (default to 0 if not specified)
383                let decimals = if args.len() == 2 {
384                    match self.evaluate(&args[1], row_index)? {
385                        DataValue::Integer(n) => n as i32,
386                        DataValue::Float(f) => f as i32,
387                        _ => return Err(anyhow!("ROUND precision must be a number")),
388                    }
389                } else {
390                    0
391                };
392
393                // Perform rounding
394                match value {
395                    DataValue::Integer(n) => Ok(DataValue::Integer(n)), // Already an integer
396                    DataValue::Float(f) => {
397                        if decimals >= 0 {
398                            let multiplier = 10_f64.powi(decimals);
399                            let rounded = (f * multiplier).round() / multiplier;
400                            if decimals == 0 {
401                                // Return as integer if rounding to 0 decimals
402                                Ok(DataValue::Integer(rounded as i64))
403                            } else {
404                                Ok(DataValue::Float(rounded))
405                            }
406                        } else {
407                            // Negative decimals round to left of decimal point
408                            let divisor = 10_f64.powi(-decimals);
409                            let rounded = (f / divisor).round() * divisor;
410                            Ok(DataValue::Float(rounded))
411                        }
412                    }
413                    _ => Err(anyhow!("ROUND can only be applied to numeric values")),
414                }
415            }
416            "ABS" => {
417                if args.len() != 1 {
418                    return Err(anyhow!("ABS requires exactly 1 argument"));
419                }
420
421                let value = self.evaluate(&args[0], row_index)?;
422                match value {
423                    DataValue::Integer(n) => Ok(DataValue::Integer(n.abs())),
424                    DataValue::Float(f) => Ok(DataValue::Float(f.abs())),
425                    _ => Err(anyhow!("ABS can only be applied to numeric values")),
426                }
427            }
428            "FLOOR" => {
429                if args.len() != 1 {
430                    return Err(anyhow!("FLOOR requires exactly 1 argument"));
431                }
432
433                let value = self.evaluate(&args[0], row_index)?;
434                match value {
435                    DataValue::Integer(n) => Ok(DataValue::Integer(n)),
436                    DataValue::Float(f) => Ok(DataValue::Integer(f.floor() as i64)),
437                    _ => Err(anyhow!("FLOOR can only be applied to numeric values")),
438                }
439            }
440            "CEILING" | "CEIL" => {
441                if args.len() != 1 {
442                    return Err(anyhow!("CEILING requires exactly 1 argument"));
443                }
444
445                let value = self.evaluate(&args[0], row_index)?;
446                match value {
447                    DataValue::Integer(n) => Ok(DataValue::Integer(n)),
448                    DataValue::Float(f) => Ok(DataValue::Integer(f.ceil() as i64)),
449                    _ => Err(anyhow!("CEILING can only be applied to numeric values")),
450                }
451            }
452            "CONVERT" => {
453                if args.len() != 3 {
454                    return Err(anyhow!(
455                        "CONVERT requires exactly 3 arguments: value, from_unit, to_unit"
456                    ));
457                }
458
459                // Evaluate the value
460                let value = self.evaluate(&args[0], row_index)?;
461                let numeric_value = match value {
462                    DataValue::Integer(n) => n as f64,
463                    DataValue::Float(f) => f,
464                    _ => return Err(anyhow!("CONVERT first argument must be numeric")),
465                };
466
467                // Get unit strings
468                let from_unit = match self.evaluate(&args[1], row_index)? {
469                    DataValue::String(s) => s,
470                    DataValue::InternedString(s) => s.to_string(),
471                    _ => {
472                        return Err(anyhow!(
473                            "CONVERT second argument must be a string (from_unit)"
474                        ))
475                    }
476                };
477
478                let to_unit = match self.evaluate(&args[2], row_index)? {
479                    DataValue::String(s) => s,
480                    DataValue::InternedString(s) => s.to_string(),
481                    _ => return Err(anyhow!("CONVERT third argument must be a string (to_unit)")),
482                };
483
484                // Perform conversion
485                match crate::data::unit_converter::convert_units(
486                    numeric_value,
487                    &from_unit,
488                    &to_unit,
489                ) {
490                    Ok(result) => Ok(DataValue::Float(result)),
491                    Err(e) => Err(anyhow!("Unit conversion error: {}", e)),
492                }
493            }
494            "MOD" => {
495                if args.len() != 2 {
496                    return Err(anyhow!("MOD requires exactly 2 arguments"));
497                }
498
499                let dividend = self.evaluate(&args[0], row_index)?;
500                let divisor = self.evaluate(&args[1], row_index)?;
501
502                match (&dividend, &divisor) {
503                    (DataValue::Integer(n), DataValue::Integer(d)) => {
504                        if *d == 0 {
505                            return Err(anyhow!("Division by zero in MOD"));
506                        }
507                        Ok(DataValue::Integer(n % d))
508                    }
509                    _ => {
510                        // Convert to float for mixed types
511                        let n = match dividend {
512                            DataValue::Integer(i) => i as f64,
513                            DataValue::Float(f) => f,
514                            _ => return Err(anyhow!("MOD requires numeric arguments")),
515                        };
516                        let d = match divisor {
517                            DataValue::Integer(i) => i as f64,
518                            DataValue::Float(f) => f,
519                            _ => return Err(anyhow!("MOD requires numeric arguments")),
520                        };
521                        if d == 0.0 {
522                            return Err(anyhow!("Division by zero in MOD"));
523                        }
524                        Ok(DataValue::Float(n % d))
525                    }
526                }
527            }
528            "QUOTIENT" => {
529                if args.len() != 2 {
530                    return Err(anyhow!("QUOTIENT requires exactly 2 arguments"));
531                }
532
533                let numerator = self.evaluate(&args[0], row_index)?;
534                let denominator = self.evaluate(&args[1], row_index)?;
535
536                match (&numerator, &denominator) {
537                    (DataValue::Integer(n), DataValue::Integer(d)) => {
538                        if *d == 0 {
539                            return Err(anyhow!("Division by zero in QUOTIENT"));
540                        }
541                        Ok(DataValue::Integer(n / d))
542                    }
543                    _ => {
544                        // Convert to float for mixed types
545                        let n = match numerator {
546                            DataValue::Integer(i) => i as f64,
547                            DataValue::Float(f) => f,
548                            _ => return Err(anyhow!("QUOTIENT requires numeric arguments")),
549                        };
550                        let d = match denominator {
551                            DataValue::Integer(i) => i as f64,
552                            DataValue::Float(f) => f,
553                            _ => return Err(anyhow!("QUOTIENT requires numeric arguments")),
554                        };
555                        if d == 0.0 {
556                            return Err(anyhow!("Division by zero in QUOTIENT"));
557                        }
558                        Ok(DataValue::Integer((n / d).trunc() as i64))
559                    }
560                }
561            }
562            "POWER" | "POW" => {
563                if args.len() != 2 {
564                    return Err(anyhow!("POWER requires exactly 2 arguments"));
565                }
566
567                let base = self.evaluate(&args[0], row_index)?;
568                let exponent = self.evaluate(&args[1], row_index)?;
569
570                match (&base, &exponent) {
571                    (DataValue::Integer(b), DataValue::Integer(e)) => {
572                        if *e >= 0 && *e <= i32::MAX as i64 {
573                            Ok(DataValue::Float((*b as f64).powi(*e as i32)))
574                        } else {
575                            Ok(DataValue::Float((*b as f64).powf(*e as f64)))
576                        }
577                    }
578                    _ => {
579                        // Convert to float for mixed types or floats
580                        let b = match base {
581                            DataValue::Integer(i) => i as f64,
582                            DataValue::Float(f) => f,
583                            _ => return Err(anyhow!("POWER requires numeric arguments")),
584                        };
585                        let e = match exponent {
586                            DataValue::Integer(i) => i as f64,
587                            DataValue::Float(f) => f,
588                            _ => return Err(anyhow!("POWER requires numeric arguments")),
589                        };
590                        Ok(DataValue::Float(b.powf(e)))
591                    }
592                }
593            }
594            "SQRT" => {
595                if args.len() != 1 {
596                    return Err(anyhow!("SQRT requires exactly 1 argument"));
597                }
598
599                let value = self.evaluate(&args[0], row_index)?;
600                match value {
601                    DataValue::Integer(n) => {
602                        if n < 0 {
603                            return Err(anyhow!("SQRT of negative number"));
604                        }
605                        Ok(DataValue::Float((n as f64).sqrt()))
606                    }
607                    DataValue::Float(f) => {
608                        if f < 0.0 {
609                            return Err(anyhow!("SQRT of negative number"));
610                        }
611                        Ok(DataValue::Float(f.sqrt()))
612                    }
613                    _ => Err(anyhow!("SQRT can only be applied to numeric values")),
614                }
615            }
616            "EXP" => {
617                if args.len() != 1 {
618                    return Err(anyhow!("EXP requires exactly 1 argument"));
619                }
620
621                let value = self.evaluate(&args[0], row_index)?;
622                match value {
623                    DataValue::Integer(n) => Ok(DataValue::Float((n as f64).exp())),
624                    DataValue::Float(f) => Ok(DataValue::Float(f.exp())),
625                    _ => Err(anyhow!("EXP can only be applied to numeric values")),
626                }
627            }
628            "LN" => {
629                if args.len() != 1 {
630                    return Err(anyhow!("LN requires exactly 1 argument"));
631                }
632
633                let value = self.evaluate(&args[0], row_index)?;
634                match value {
635                    DataValue::Integer(n) => {
636                        if n <= 0 {
637                            return Err(anyhow!("LN of non-positive number"));
638                        }
639                        Ok(DataValue::Float((n as f64).ln()))
640                    }
641                    DataValue::Float(f) => {
642                        if f <= 0.0 {
643                            return Err(anyhow!("LN of non-positive number"));
644                        }
645                        Ok(DataValue::Float(f.ln()))
646                    }
647                    _ => Err(anyhow!("LN can only be applied to numeric values")),
648                }
649            }
650            "LOG" | "LOG10" => {
651                if name == "LOG" && args.len() == 2 {
652                    // LOG with custom base
653                    let value = self.evaluate(&args[0], row_index)?;
654                    let base = self.evaluate(&args[1], row_index)?;
655
656                    let n = match value {
657                        DataValue::Integer(i) => i as f64,
658                        DataValue::Float(f) => f,
659                        _ => return Err(anyhow!("LOG requires numeric arguments")),
660                    };
661                    let b = match base {
662                        DataValue::Integer(i) => i as f64,
663                        DataValue::Float(f) => f,
664                        _ => return Err(anyhow!("LOG requires numeric arguments")),
665                    };
666
667                    if n <= 0.0 {
668                        return Err(anyhow!("LOG of non-positive number"));
669                    }
670                    if b <= 0.0 || b == 1.0 {
671                        return Err(anyhow!("Invalid LOG base"));
672                    }
673                    Ok(DataValue::Float(n.log(b)))
674                } else if (name == "LOG" && args.len() == 1) || name == "LOG10" {
675                    // LOG10 or LOG with default base 10
676                    if args.len() != 1 {
677                        return Err(anyhow!("{} requires exactly 1 argument", name));
678                    }
679
680                    let value = self.evaluate(&args[0], row_index)?;
681                    match value {
682                        DataValue::Integer(n) => {
683                            if n <= 0 {
684                                return Err(anyhow!("LOG10 of non-positive number"));
685                            }
686                            Ok(DataValue::Float((n as f64).log10()))
687                        }
688                        DataValue::Float(f) => {
689                            if f <= 0.0 {
690                                return Err(anyhow!("LOG10 of non-positive number"));
691                            }
692                            Ok(DataValue::Float(f.log10()))
693                        }
694                        _ => Err(anyhow!("LOG10 can only be applied to numeric values")),
695                    }
696                } else {
697                    Err(anyhow!("LOG requires 1 or 2 arguments"))
698                }
699            }
700            "PI" => {
701                if !args.is_empty() {
702                    return Err(anyhow!("PI takes no arguments"));
703                }
704                Ok(DataValue::Float(std::f64::consts::PI))
705            }
706            "DATEDIFF" => {
707                if args.len() != 3 {
708                    return Err(anyhow!(
709                        "DATEDIFF requires exactly 3 arguments: unit, date1, date2"
710                    ));
711                }
712
713                // First argument: unit (day, month, year, hour, minute, second)
714                let unit = match self.evaluate(&args[0], row_index)? {
715                    DataValue::String(s) => s.to_lowercase(),
716                    DataValue::InternedString(s) => s.to_lowercase(),
717                    _ => return Err(anyhow!("DATEDIFF unit must be a string")),
718                };
719
720                // Helper function to parse date/datetime strings
721                let date_notation = self.date_notation.clone();
722                let parse_datetime = move |value: DataValue| -> Result<DateTime<Utc>> {
723                    let parse_string = |s: &str| -> Result<DateTime<Utc>> {
724                        // Try various date/datetime formats
725
726                        // ISO formats (most common and unambiguous)
727                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
728                            return Ok(Utc.from_utc_datetime(&dt));
729                        }
730                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
731                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
732                        }
733
734                        // Try date notation preference first for ambiguous formats
735                        if date_notation == "european" {
736                            // European format: DD/MM/YYYY or DD-MM-YYYY (try first)
737                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d/%m/%Y") {
738                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
739                            }
740                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%m-%Y") {
741                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
742                            }
743                            // US format: MM/DD/YYYY or MM-DD-YYYY (fallback)
744                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m/%d/%Y") {
745                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
746                            }
747                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m-%d-%Y") {
748                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
749                            }
750                        } else {
751                            // US format: MM/DD/YYYY or MM-DD-YYYY (default, try first)
752                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m/%d/%Y") {
753                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
754                            }
755                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m-%d-%Y") {
756                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
757                            }
758                            // European format: DD/MM/YYYY or DD-MM-YYYY (fallback)
759                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d/%m/%Y") {
760                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
761                            }
762                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%m-%Y") {
763                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
764                            }
765                        }
766
767                        // Excel/Windows format: DD-MMM-YYYY (e.g., 15-Jan-2024)
768                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%b-%Y") {
769                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
770                        }
771
772                        // Full month names: January 15, 2024 or 15 January 2024
773                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%B %d, %Y") {
774                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
775                        }
776                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%d %B %Y") {
777                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
778                        }
779
780                        // With time: MM/DD/YYYY HH:MM:SS
781                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%m/%d/%Y %H:%M:%S") {
782                            return Ok(Utc.from_utc_datetime(&dt));
783                        }
784                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%d/%m/%Y %H:%M:%S") {
785                            return Ok(Utc.from_utc_datetime(&dt));
786                        }
787
788                        // ISO 8601 / RFC3339
789                        if let Ok(dt) = s.parse::<DateTime<Utc>>() {
790                            return Ok(dt);
791                        }
792
793                        Err(anyhow!("Could not parse date: {}. Supported formats: YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, DD-MMM-YYYY", s))
794                    };
795
796                    match value {
797                        DataValue::String(s) | DataValue::DateTime(s) => parse_string(&s),
798                        DataValue::InternedString(s) => parse_string(s.as_str()),
799                        _ => Err(anyhow!("DATEDIFF requires date/datetime values")),
800                    }
801                };
802
803                // Parse both dates
804                let date1 = parse_datetime(self.evaluate(&args[1], row_index)?)?;
805                let date2 = parse_datetime(self.evaluate(&args[2], row_index)?)?;
806
807                // Calculate difference based on unit
808                let diff = match unit.as_str() {
809                    "day" | "days" => {
810                        let duration = date2.signed_duration_since(date1);
811                        duration.num_days()
812                    }
813                    "month" | "months" => {
814                        // Approximate months as 30.44 days
815                        let duration = date2.signed_duration_since(date1);
816                        duration.num_days() / 30
817                    }
818                    "year" | "years" => {
819                        // Approximate years as 365.25 days
820                        let duration = date2.signed_duration_since(date1);
821                        duration.num_days() / 365
822                    }
823                    "hour" | "hours" => {
824                        let duration = date2.signed_duration_since(date1);
825                        duration.num_hours()
826                    }
827                    "minute" | "minutes" => {
828                        let duration = date2.signed_duration_since(date1);
829                        duration.num_minutes()
830                    }
831                    "second" | "seconds" => {
832                        let duration = date2.signed_duration_since(date1);
833                        duration.num_seconds()
834                    }
835                    _ => {
836                        return Err(anyhow!(
837                        "Unknown DATEDIFF unit: {}. Use: day, month, year, hour, minute, second",
838                        unit
839                    ))
840                    }
841                };
842
843                Ok(DataValue::Integer(diff))
844            }
845            "NOW" => {
846                if !args.is_empty() {
847                    return Err(anyhow!("NOW takes no arguments"));
848                }
849                let now = Utc::now();
850                Ok(DataValue::DateTime(
851                    now.format("%Y-%m-%d %H:%M:%S").to_string(),
852                ))
853            }
854            "TODAY" => {
855                if !args.is_empty() {
856                    return Err(anyhow!("TODAY takes no arguments"));
857                }
858                let today = Utc::now().date_naive();
859                Ok(DataValue::String(today.format("%Y-%m-%d").to_string()))
860            }
861            "DATEADD" => {
862                if args.len() != 3 {
863                    return Err(anyhow!(
864                        "DATEADD requires exactly 3 arguments: unit, number, date"
865                    ));
866                }
867
868                // First argument: unit (day, month, year, hour, minute, second)
869                let unit = match self.evaluate(&args[0], row_index)? {
870                    DataValue::String(s) => s.to_lowercase(),
871                    DataValue::InternedString(s) => s.to_lowercase(),
872                    _ => return Err(anyhow!("DATEADD unit must be a string")),
873                };
874
875                // Second argument: number to add (can be negative for subtraction)
876                let amount = match self.evaluate(&args[1], row_index)? {
877                    DataValue::Integer(i) => i,
878                    DataValue::Float(f) => f as i64,
879                    _ => return Err(anyhow!("DATEADD amount must be a number")),
880                };
881
882                // Third argument: base date
883                let base_date_value = self.evaluate(&args[2], row_index)?;
884
885                // Reuse the parse_datetime function from DATEDIFF
886                let date_notation = self.date_notation.clone();
887                let parse_datetime = move |value: DataValue| -> Result<DateTime<Utc>> {
888                    let parse_string = |s: &str| -> Result<DateTime<Utc>> {
889                        // Try various date/datetime formats (same as DATEDIFF)
890
891                        // ISO formats (most common and unambiguous)
892                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
893                            return Ok(Utc.from_utc_datetime(&dt));
894                        }
895                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
896                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
897                        }
898
899                        // Try date notation preference first for ambiguous formats
900                        if date_notation == "european" {
901                            // European format: DD/MM/YYYY or DD-MM-YYYY (try first)
902                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d/%m/%Y") {
903                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
904                            }
905                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%m-%Y") {
906                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
907                            }
908                            // US format: MM/DD/YYYY or MM-DD-YYYY (fallback)
909                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m/%d/%Y") {
910                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
911                            }
912                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m-%d-%Y") {
913                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
914                            }
915                        } else {
916                            // US format: MM/DD/YYYY or MM-DD-YYYY (default, try first)
917                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m/%d/%Y") {
918                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
919                            }
920                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%m-%d-%Y") {
921                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
922                            }
923                            // European format: DD/MM/YYYY or DD-MM-YYYY (fallback)
924                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d/%m/%Y") {
925                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
926                            }
927                            if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%m-%Y") {
928                                return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
929                            }
930                        }
931
932                        // Excel/Windows format: DD-MMM-YYYY (e.g., 15-Jan-2024)
933                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%d-%b-%Y") {
934                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
935                        }
936
937                        // Full month names: January 15, 2024 or 15 January 2024
938                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%B %d, %Y") {
939                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
940                        }
941                        if let Ok(dt) = NaiveDate::parse_from_str(s, "%d %B %Y") {
942                            return Ok(Utc.from_utc_datetime(&dt.and_hms_opt(0, 0, 0).unwrap()));
943                        }
944
945                        // With time: MM/DD/YYYY HH:MM:SS
946                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%m/%d/%Y %H:%M:%S") {
947                            return Ok(Utc.from_utc_datetime(&dt));
948                        }
949                        if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%d/%m/%Y %H:%M:%S") {
950                            return Ok(Utc.from_utc_datetime(&dt));
951                        }
952
953                        // ISO 8601 / RFC3339
954                        if let Ok(dt) = s.parse::<DateTime<Utc>>() {
955                            return Ok(dt);
956                        }
957
958                        Err(anyhow!("Could not parse date: {}. Supported formats: YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, DD-MMM-YYYY", s))
959                    };
960
961                    match value {
962                        DataValue::String(s) | DataValue::DateTime(s) => parse_string(&s),
963                        DataValue::InternedString(s) => parse_string(s.as_str()),
964                        _ => Err(anyhow!("DATEADD requires date/datetime values")),
965                    }
966                };
967
968                // Parse the base date
969                let base_date = parse_datetime(base_date_value)?;
970
971                // Add the specified amount based on unit
972                let result_date = match unit.as_str() {
973                    "day" | "days" => base_date + chrono::Duration::days(amount),
974                    "month" | "months" => {
975                        // For months, we need to be careful about month boundaries
976                        let mut year = base_date.year();
977                        let mut month = base_date.month() as i32;
978                        let day = base_date.day();
979
980                        month += amount as i32;
981
982                        // Handle month overflow/underflow
983                        while month > 12 {
984                            month -= 12;
985                            year += 1;
986                        }
987                        while month < 1 {
988                            month += 12;
989                            year -= 1;
990                        }
991
992                        // Create new date, handling day overflow (e.g., Jan 31 + 1 month = Feb 28/29)
993                        let target_date = NaiveDate::from_ymd_opt(year, month as u32, day)
994                            .unwrap_or_else(|| {
995                                // If day doesn't exist in target month, use the last day of that month
996                                // Try decreasing days until we find a valid one
997                                for test_day in (1..=day).rev() {
998                                    if let Some(date) =
999                                        NaiveDate::from_ymd_opt(year, month as u32, test_day)
1000                                    {
1001                                        return date;
1002                                    }
1003                                }
1004                                // This should never happen, but fallback to day 28 as safety
1005                                NaiveDate::from_ymd_opt(year, month as u32, 28).unwrap()
1006                            });
1007
1008                        Utc.from_utc_datetime(&target_date.and_time(base_date.time()))
1009                    }
1010                    "year" | "years" => {
1011                        let new_year = base_date.year() + amount as i32;
1012                        let target_date =
1013                            NaiveDate::from_ymd_opt(new_year, base_date.month(), base_date.day())
1014                                .unwrap_or_else(|| {
1015                                    // Handle Feb 29 in non-leap years
1016                                    NaiveDate::from_ymd_opt(new_year, base_date.month(), 28)
1017                                        .unwrap()
1018                                });
1019                        Utc.from_utc_datetime(&target_date.and_time(base_date.time()))
1020                    }
1021                    "hour" | "hours" => base_date + chrono::Duration::hours(amount),
1022                    "minute" | "minutes" => base_date + chrono::Duration::minutes(amount),
1023                    "second" | "seconds" => base_date + chrono::Duration::seconds(amount),
1024                    _ => {
1025                        return Err(anyhow!(
1026                            "Unknown DATEADD unit: {}. Use: day, month, year, hour, minute, second",
1027                            unit
1028                        ))
1029                    }
1030                };
1031
1032                // Return as datetime string
1033                Ok(DataValue::DateTime(
1034                    result_date.format("%Y-%m-%d %H:%M:%S").to_string(),
1035                ))
1036            }
1037            "TEXTJOIN" => {
1038                if args.len() < 3 {
1039                    return Err(anyhow!("TEXTJOIN requires at least 3 arguments: delimiter, ignore_empty, text1, [text2, ...]"));
1040                }
1041
1042                // First argument: delimiter
1043                let delimiter = match self.evaluate(&args[0], row_index)? {
1044                    DataValue::String(s) => s,
1045                    DataValue::InternedString(s) => s.to_string(),
1046                    DataValue::Integer(n) => n.to_string(),
1047                    DataValue::Float(f) => f.to_string(),
1048                    DataValue::Boolean(b) => b.to_string(),
1049                    DataValue::Null => String::new(),
1050                    _ => String::new(),
1051                };
1052
1053                // Second argument: ignore_empty (treat as boolean - 0 is false, anything else is true)
1054                let ignore_empty = match self.evaluate(&args[1], row_index)? {
1055                    DataValue::Integer(n) => n != 0,
1056                    DataValue::Float(f) => f != 0.0,
1057                    DataValue::Boolean(b) => b,
1058                    DataValue::String(s) => {
1059                        !s.is_empty() && s != "0" && s.to_lowercase() != "false"
1060                    }
1061                    DataValue::InternedString(s) => {
1062                        !s.is_empty() && s.as_str() != "0" && s.to_lowercase() != "false"
1063                    }
1064                    DataValue::Null => false,
1065                    _ => true,
1066                };
1067
1068                // Remaining arguments: values to join
1069                let mut values = Vec::new();
1070                for i in 2..args.len() {
1071                    let value = self.evaluate(&args[i], row_index)?;
1072                    let string_value = match value {
1073                        DataValue::String(s) => Some(s),
1074                        DataValue::InternedString(s) => Some(s.to_string()),
1075                        DataValue::Integer(n) => Some(n.to_string()),
1076                        DataValue::Float(f) => Some(f.to_string()),
1077                        DataValue::Boolean(b) => Some(b.to_string()),
1078                        DataValue::DateTime(dt) => Some(dt),
1079                        DataValue::Null => {
1080                            if ignore_empty {
1081                                None
1082                            } else {
1083                                Some(String::new())
1084                            }
1085                        }
1086                        _ => {
1087                            if ignore_empty {
1088                                None
1089                            } else {
1090                                Some(String::new())
1091                            }
1092                        }
1093                    };
1094
1095                    if let Some(s) = string_value {
1096                        if !ignore_empty || !s.is_empty() {
1097                            values.push(s);
1098                        }
1099                    }
1100                }
1101
1102                Ok(DataValue::String(values.join(&delimiter)))
1103            }
1104            "PI" => {
1105                // PI constant - no arguments
1106                if !args.is_empty() {
1107                    return Err(anyhow!("PI() takes no arguments"));
1108                }
1109                Ok(DataValue::Float(std::f64::consts::PI))
1110            }
1111            "EULER" => {
1112                // Euler's number constant - no arguments
1113                if !args.is_empty() {
1114                    return Err(anyhow!("EULER() takes no arguments"));
1115                }
1116                Ok(DataValue::Float(std::f64::consts::E))
1117            }
1118            "TAU" => {
1119                // Tau constant (2*PI) - no arguments
1120                if !args.is_empty() {
1121                    return Err(anyhow!("TAU() takes no arguments"));
1122                }
1123                Ok(DataValue::Float(std::f64::consts::TAU))
1124            }
1125            "PHI" => {
1126                // Golden ratio constant - no arguments
1127                if !args.is_empty() {
1128                    return Err(anyhow!("PHI() takes no arguments"));
1129                }
1130                Ok(DataValue::Float(1.618033988749895))
1131            }
1132            "SQRT2" => {
1133                // Square root of 2 constant - no arguments
1134                if !args.is_empty() {
1135                    return Err(anyhow!("SQRT2() takes no arguments"));
1136                }
1137                Ok(DataValue::Float(std::f64::consts::SQRT_2))
1138            }
1139            "LN2" => {
1140                // Natural logarithm of 2 - no arguments
1141                if !args.is_empty() {
1142                    return Err(anyhow!("LN2() takes no arguments"));
1143                }
1144                Ok(DataValue::Float(std::f64::consts::LN_2))
1145            }
1146            "LN10" => {
1147                // Natural logarithm of 10 - no arguments
1148                if !args.is_empty() {
1149                    return Err(anyhow!("LN10() takes no arguments"));
1150                }
1151                Ok(DataValue::Float(std::f64::consts::LN_10))
1152            }
1153            // Physics Constants - Fundamental Constants
1154            "C" | "SPEED_OF_LIGHT" => {
1155                // Speed of light in vacuum (m/s)
1156                if !args.is_empty() {
1157                    return Err(anyhow!("C() takes no arguments"));
1158                }
1159                Ok(DataValue::Float(299792458.0))
1160            }
1161            "G" | "GRAVITATIONAL_CONSTANT" => {
1162                // Gravitational constant (m^3 kg^-1 s^-2)
1163                if !args.is_empty() {
1164                    return Err(anyhow!("G() takes no arguments"));
1165                }
1166                Ok(DataValue::Float(6.67430e-11))
1167            }
1168            "H" | "PLANCK" => {
1169                // Planck constant (J⋅s)
1170                if !args.is_empty() {
1171                    return Err(anyhow!("PLANCK() takes no arguments"));
1172                }
1173                Ok(DataValue::Float(6.62607015e-34))
1174            }
1175            "HBAR" => {
1176                // Reduced Planck constant ℏ = h/(2π) (J⋅s)
1177                if !args.is_empty() {
1178                    return Err(anyhow!("HBAR() takes no arguments"));
1179                }
1180                Ok(DataValue::Float(1.054571817e-34))
1181            }
1182            "K" | "BOLTZMANN" => {
1183                // Boltzmann constant (J/K)
1184                if !args.is_empty() {
1185                    return Err(anyhow!("BOLTZMANN() takes no arguments"));
1186                }
1187                Ok(DataValue::Float(1.380649e-23))
1188            }
1189            "NA" | "AVOGADRO" => {
1190                // Avogadro's number (mol^-1)
1191                if !args.is_empty() {
1192                    return Err(anyhow!("AVOGADRO() takes no arguments"));
1193                }
1194                Ok(DataValue::Float(6.02214076e23))
1195            }
1196            "R" | "GAS_CONSTANT" => {
1197                // Universal gas constant (J mol^-1 K^-1)
1198                if !args.is_empty() {
1199                    return Err(anyhow!("R() takes no arguments"));
1200                }
1201                Ok(DataValue::Float(8.314462618))
1202            }
1203            // Physics Constants - Electromagnetic
1204            "E0" | "EPSILON0" | "PERMITTIVITY" => {
1205                // Electric permittivity of vacuum (F/m)
1206                if !args.is_empty() {
1207                    return Err(anyhow!("E0() takes no arguments"));
1208                }
1209                Ok(DataValue::Float(8.8541878128e-12))
1210            }
1211            "MU0" | "PERMEABILITY" => {
1212                // Magnetic permeability of vacuum (N/A^2)
1213                if !args.is_empty() {
1214                    return Err(anyhow!("MU0() takes no arguments"));
1215                }
1216                Ok(DataValue::Float(1.25663706212e-6))
1217            }
1218            "QE" | "ELEMENTARY_CHARGE" => {
1219                // Elementary charge (C)
1220                if !args.is_empty() {
1221                    return Err(anyhow!("QE() takes no arguments"));
1222                }
1223                Ok(DataValue::Float(1.602176634e-19))
1224            }
1225            // Physics Constants - Particle Masses
1226            "ME" | "MASS_ELECTRON" => {
1227                // Electron mass (kg)
1228                if !args.is_empty() {
1229                    return Err(anyhow!("ME() takes no arguments"));
1230                }
1231                Ok(DataValue::Float(9.1093837015e-31))
1232            }
1233            "MP" | "MASS_PROTON" => {
1234                // Proton mass (kg)
1235                if !args.is_empty() {
1236                    return Err(anyhow!("MP() takes no arguments"));
1237                }
1238                Ok(DataValue::Float(1.67262192369e-27))
1239            }
1240            "MN" | "MASS_NEUTRON" => {
1241                // Neutron mass (kg)
1242                if !args.is_empty() {
1243                    return Err(anyhow!("MN() takes no arguments"));
1244                }
1245                Ok(DataValue::Float(1.67492749804e-27))
1246            }
1247            "AMU" | "ATOMIC_MASS_UNIT" => {
1248                // Atomic mass unit (kg)
1249                if !args.is_empty() {
1250                    return Err(anyhow!("AMU() takes no arguments"));
1251                }
1252                Ok(DataValue::Float(1.66053906660e-27))
1253            }
1254            // Physics Constants - Other
1255            "ALPHA" | "FINE_STRUCTURE" => {
1256                // Fine structure constant (dimensionless)
1257                if !args.is_empty() {
1258                    return Err(anyhow!("ALPHA() takes no arguments"));
1259                }
1260                Ok(DataValue::Float(7.2973525693e-3))
1261            }
1262            "RY" | "RYDBERG" => {
1263                // Rydberg constant (m^-1)
1264                if !args.is_empty() {
1265                    return Err(anyhow!("RYDBERG() takes no arguments"));
1266                }
1267                Ok(DataValue::Float(10973731.568160))
1268            }
1269            "SIGMA" | "STEFAN_BOLTZMANN" => {
1270                // Stefan-Boltzmann constant (W m^-2 K^-4)
1271                if !args.is_empty() {
1272                    return Err(anyhow!("SIGMA() takes no arguments"));
1273                }
1274                Ok(DataValue::Float(5.670374419e-8))
1275            }
1276            // Particle Radii Constants
1277            "RE" | "RADIUS_ELECTRON" => {
1278                // Classical electron radius (m)
1279                if !args.is_empty() {
1280                    return Err(anyhow!("RE() takes no arguments"));
1281                }
1282                Ok(DataValue::Float(2.8179403262e-15))
1283            }
1284            "RP" | "RADIUS_PROTON" => {
1285                // Proton radius (m) - CODATA 2018 value
1286                if !args.is_empty() {
1287                    return Err(anyhow!("RP() takes no arguments"));
1288                }
1289                Ok(DataValue::Float(8.414e-16))
1290            }
1291            "RN" | "RADIUS_NEUTRON" => {
1292                // Neutron radius (m) - approximate
1293                if !args.is_empty() {
1294                    return Err(anyhow!("RN() takes no arguments"));
1295                }
1296                Ok(DataValue::Float(8.4e-16))
1297            }
1298            // Astronomical Constants - Solar System
1299            "MASS_SUN" | "MSUN" => {
1300                // Solar mass (kg)
1301                if !args.is_empty() {
1302                    return Err(anyhow!("MASS_SUN() takes no arguments"));
1303                }
1304                Ok(DataValue::Float(1.98892e30))
1305            }
1306            "RADIUS_SUN" | "RSUN" => {
1307                // Solar radius (m)
1308                if !args.is_empty() {
1309                    return Err(anyhow!("RADIUS_SUN() takes no arguments"));
1310                }
1311                Ok(DataValue::Float(6.96342e8))
1312            }
1313            "MASS_EARTH" | "MEARTH" => {
1314                // Earth mass (kg)
1315                if !args.is_empty() {
1316                    return Err(anyhow!("MASS_EARTH() takes no arguments"));
1317                }
1318                Ok(DataValue::Float(5.97237e24))
1319            }
1320            "RADIUS_EARTH" | "REARTH" => {
1321                // Earth mean radius (m)
1322                if !args.is_empty() {
1323                    return Err(anyhow!("RADIUS_EARTH() takes no arguments"));
1324                }
1325                Ok(DataValue::Float(6.371e6))
1326            }
1327            "MASS_MOON" | "MMOON" => {
1328                // Moon mass (kg)
1329                if !args.is_empty() {
1330                    return Err(anyhow!("MASS_MOON() takes no arguments"));
1331                }
1332                Ok(DataValue::Float(7.342e22))
1333            }
1334            "RADIUS_MOON" | "RMOON" => {
1335                // Moon mean radius (m)
1336                if !args.is_empty() {
1337                    return Err(anyhow!("RADIUS_MOON() takes no arguments"));
1338                }
1339                Ok(DataValue::Float(1.7374e6))
1340            }
1341            // Planets
1342            "MASS_MERCURY" => {
1343                // Mercury mass (kg)
1344                if !args.is_empty() {
1345                    return Err(anyhow!("MASS_MERCURY() takes no arguments"));
1346                }
1347                Ok(DataValue::Float(3.3011e23))
1348            }
1349            "MASS_VENUS" => {
1350                // Venus mass (kg)
1351                if !args.is_empty() {
1352                    return Err(anyhow!("MASS_VENUS() takes no arguments"));
1353                }
1354                Ok(DataValue::Float(4.8675e24))
1355            }
1356            "MASS_MARS" => {
1357                // Mars mass (kg)
1358                if !args.is_empty() {
1359                    return Err(anyhow!("MASS_MARS() takes no arguments"));
1360                }
1361                Ok(DataValue::Float(6.4171e23))
1362            }
1363            "MASS_JUPITER" => {
1364                // Jupiter mass (kg)
1365                if !args.is_empty() {
1366                    return Err(anyhow!("MASS_JUPITER() takes no arguments"));
1367                }
1368                Ok(DataValue::Float(1.8982e27))
1369            }
1370            "MASS_SATURN" => {
1371                // Saturn mass (kg)
1372                if !args.is_empty() {
1373                    return Err(anyhow!("MASS_SATURN() takes no arguments"));
1374                }
1375                Ok(DataValue::Float(5.6834e26))
1376            }
1377            "MASS_URANUS" => {
1378                // Uranus mass (kg)
1379                if !args.is_empty() {
1380                    return Err(anyhow!("MASS_URANUS() takes no arguments"));
1381                }
1382                Ok(DataValue::Float(8.6810e25))
1383            }
1384            "MASS_NEPTUNE" => {
1385                // Neptune mass (kg)
1386                if !args.is_empty() {
1387                    return Err(anyhow!("MASS_NEPTUNE() takes no arguments"));
1388                }
1389                Ok(DataValue::Float(1.02413e26))
1390            }
1391            // Orbital distances (mean distance from Sun in meters)
1392            "DIST_MERCURY" | "AU_MERCURY" => {
1393                // Mercury mean distance from Sun (m)
1394                if !args.is_empty() {
1395                    return Err(anyhow!("DIST_MERCURY() takes no arguments"));
1396                }
1397                Ok(DataValue::Float(5.791e10))
1398            }
1399            "DIST_VENUS" | "AU_VENUS" => {
1400                // Venus mean distance from Sun (m)
1401                if !args.is_empty() {
1402                    return Err(anyhow!("DIST_VENUS() takes no arguments"));
1403                }
1404                Ok(DataValue::Float(1.082e11))
1405            }
1406            "DIST_EARTH" | "AU_EARTH" | "AU" => {
1407                // Earth mean distance from Sun = 1 AU (m)
1408                if !args.is_empty() {
1409                    return Err(anyhow!("AU() takes no arguments"));
1410                }
1411                Ok(DataValue::Float(1.495978707e11))
1412            }
1413            "DIST_MARS" | "AU_MARS" => {
1414                // Mars mean distance from Sun (m)
1415                if !args.is_empty() {
1416                    return Err(anyhow!("DIST_MARS() takes no arguments"));
1417                }
1418                Ok(DataValue::Float(2.279e11))
1419            }
1420            "DIST_JUPITER" | "AU_JUPITER" => {
1421                // Jupiter mean distance from Sun (m)
1422                if !args.is_empty() {
1423                    return Err(anyhow!("DIST_JUPITER() takes no arguments"));
1424                }
1425                Ok(DataValue::Float(7.786e11))
1426            }
1427            "DIST_SATURN" | "AU_SATURN" => {
1428                // Saturn mean distance from Sun (m)
1429                if !args.is_empty() {
1430                    return Err(anyhow!("DIST_SATURN() takes no arguments"));
1431                }
1432                Ok(DataValue::Float(1.4335e12))
1433            }
1434            "DIST_URANUS" | "AU_URANUS" => {
1435                // Uranus mean distance from Sun (m)
1436                if !args.is_empty() {
1437                    return Err(anyhow!("DIST_URANUS() takes no arguments"));
1438                }
1439                Ok(DataValue::Float(2.8725e12))
1440            }
1441            "DIST_NEPTUNE" | "AU_NEPTUNE" => {
1442                // Neptune mean distance from Sun (m)
1443                if !args.is_empty() {
1444                    return Err(anyhow!("DIST_NEPTUNE() takes no arguments"));
1445                }
1446                Ok(DataValue::Float(4.4951e12))
1447            }
1448            // Other useful astronomical constants
1449            "PARSEC" | "PC" => {
1450                // Parsec in meters
1451                if !args.is_empty() {
1452                    return Err(anyhow!("PARSEC() takes no arguments"));
1453                }
1454                Ok(DataValue::Float(3.0857e16))
1455            }
1456            "LIGHTYEAR" | "LY" => {
1457                // Light year in meters
1458                if !args.is_empty() {
1459                    return Err(anyhow!("LIGHTYEAR() takes no arguments"));
1460                }
1461                Ok(DataValue::Float(9.4607e15))
1462            }
1463            // Angle conversion functions (demonstrating easy extensibility)
1464            "DEGREES" => {
1465                // Convert radians to degrees
1466                if args.len() != 1 {
1467                    return Err(anyhow!("DEGREES requires exactly 1 argument"));
1468                }
1469                let radians = match self.evaluate(&args[0], row_index)? {
1470                    DataValue::Integer(n) => n as f64,
1471                    DataValue::Float(f) => f,
1472                    _ => return Err(anyhow!("DEGREES requires a numeric argument")),
1473                };
1474                Ok(DataValue::Float(radians * 180.0 / std::f64::consts::PI))
1475            }
1476            "RADIANS" => {
1477                // Convert degrees to radians
1478                if args.len() != 1 {
1479                    return Err(anyhow!("RADIANS requires exactly 1 argument"));
1480                }
1481                let degrees = match self.evaluate(&args[0], row_index)? {
1482                    DataValue::Integer(n) => n as f64,
1483                    DataValue::Float(f) => f,
1484                    _ => return Err(anyhow!("RADIANS requires a numeric argument")),
1485                };
1486                Ok(DataValue::Float(degrees * std::f64::consts::PI / 180.0))
1487            }
1488            "MID" => {
1489                // MID(text, start_position, length) - Excel-compatible, 1-based indexing
1490                if args.len() != 3 {
1491                    return Err(anyhow!(
1492                        "MID requires exactly 3 arguments: text, start_position, length"
1493                    ));
1494                }
1495
1496                let text = match self.evaluate(&args[0], row_index)? {
1497                    DataValue::String(s) => s,
1498                    DataValue::InternedString(s) => s.to_string(),
1499                    DataValue::Integer(n) => n.to_string(),
1500                    DataValue::Float(f) => f.to_string(),
1501                    DataValue::Null => String::new(),
1502                    _ => return Err(anyhow!("MID first argument must be convertible to text")),
1503                };
1504
1505                let start_pos = match self.evaluate(&args[1], row_index)? {
1506                    DataValue::Integer(n) => n,
1507                    DataValue::Float(f) => f as i64,
1508                    _ => return Err(anyhow!("MID start_position must be a number")),
1509                };
1510
1511                let length = match self.evaluate(&args[2], row_index)? {
1512                    DataValue::Integer(n) => n,
1513                    DataValue::Float(f) => f as i64,
1514                    _ => return Err(anyhow!("MID length must be a number")),
1515                };
1516
1517                // Excel MID uses 1-based indexing
1518                if start_pos < 1 {
1519                    return Err(anyhow!("MID start_position must be >= 1"));
1520                }
1521                if length < 0 {
1522                    return Err(anyhow!("MID length must be >= 0"));
1523                }
1524
1525                // Convert to 0-based index
1526                let start_idx = (start_pos - 1) as usize;
1527                let chars: Vec<char> = text.chars().collect();
1528
1529                // If start position is beyond string length, return empty string
1530                if start_idx >= chars.len() {
1531                    return Ok(DataValue::String(String::new()));
1532                }
1533
1534                // Extract substring
1535                let end_idx = std::cmp::min(start_idx + length as usize, chars.len());
1536                let result: String = chars[start_idx..end_idx].iter().collect();
1537
1538                Ok(DataValue::String(result))
1539            }
1540            "UPPER" => {
1541                if args.len() != 1 {
1542                    return Err(anyhow!("UPPER requires exactly 1 argument"));
1543                }
1544
1545                let text = match self.evaluate(&args[0], row_index)? {
1546                    DataValue::String(s) => s,
1547                    DataValue::InternedString(s) => s.to_string(),
1548                    DataValue::Integer(n) => n.to_string(),
1549                    DataValue::Float(f) => f.to_string(),
1550                    DataValue::Null => String::new(),
1551                    _ => return Err(anyhow!("UPPER argument must be convertible to text")),
1552                };
1553
1554                Ok(DataValue::String(text.to_uppercase()))
1555            }
1556            "LOWER" => {
1557                if args.len() != 1 {
1558                    return Err(anyhow!("LOWER requires exactly 1 argument"));
1559                }
1560
1561                let text = match self.evaluate(&args[0], row_index)? {
1562                    DataValue::String(s) => s,
1563                    DataValue::InternedString(s) => s.to_string(),
1564                    DataValue::Integer(n) => n.to_string(),
1565                    DataValue::Float(f) => f.to_string(),
1566                    DataValue::Null => String::new(),
1567                    _ => return Err(anyhow!("LOWER argument must be convertible to text")),
1568                };
1569
1570                Ok(DataValue::String(text.to_lowercase()))
1571            }
1572            "TRIM" => {
1573                if args.len() != 1 {
1574                    return Err(anyhow!("TRIM requires exactly 1 argument"));
1575                }
1576
1577                let text = match self.evaluate(&args[0], row_index)? {
1578                    DataValue::String(s) => s,
1579                    DataValue::InternedString(s) => s.to_string(),
1580                    DataValue::Integer(n) => n.to_string(),
1581                    DataValue::Float(f) => f.to_string(),
1582                    DataValue::Null => String::new(),
1583                    _ => return Err(anyhow!("TRIM argument must be convertible to text")),
1584                };
1585
1586                Ok(DataValue::String(text.trim().to_string()))
1587            }
1588            _ => Err(anyhow!("Unknown function: {}", name)),
1589        }
1590    }
1591
1592    /// Evaluate a method call on a column (e.g., column.Trim())
1593    fn evaluate_method_call(
1594        &self,
1595        object: &str,
1596        method: &str,
1597        args: &[SqlExpression],
1598        row_index: usize,
1599    ) -> Result<DataValue> {
1600        // Get column value
1601        let col_index = self.table.get_column_index(object).ok_or_else(|| {
1602            let suggestion = self.find_similar_column(object);
1603            match suggestion {
1604                Some(similar) => {
1605                    anyhow!("Column '{}' not found. Did you mean '{}'?", object, similar)
1606                }
1607                None => anyhow!("Column '{}' not found", object),
1608            }
1609        })?;
1610
1611        let cell_value = self.table.get_value(row_index, col_index).cloned();
1612
1613        self.evaluate_method_on_value(
1614            &cell_value.unwrap_or(DataValue::Null),
1615            method,
1616            args,
1617            row_index,
1618        )
1619    }
1620
1621    /// Evaluate a method on a value
1622    fn evaluate_method_on_value(
1623        &self,
1624        value: &DataValue,
1625        method: &str,
1626        args: &[SqlExpression],
1627        row_index: usize,
1628    ) -> Result<DataValue> {
1629        match method.to_lowercase().as_str() {
1630            "trim" | "trimstart" | "trimend" => {
1631                if !args.is_empty() {
1632                    return Err(anyhow!("{} takes no arguments", method));
1633                }
1634
1635                // Convert value to string and apply trim
1636                let str_val = match value {
1637                    DataValue::String(s) => s.clone(),
1638                    DataValue::InternedString(s) => s.to_string(),
1639                    DataValue::Integer(n) => n.to_string(),
1640                    DataValue::Float(f) => f.to_string(),
1641                    DataValue::Boolean(b) => b.to_string(),
1642                    DataValue::DateTime(dt) => dt.clone(),
1643                    DataValue::Null => return Ok(DataValue::Null),
1644                };
1645
1646                let result = match method.to_lowercase().as_str() {
1647                    "trim" => str_val.trim().to_string(),
1648                    "trimstart" => str_val.trim_start().to_string(),
1649                    "trimend" => str_val.trim_end().to_string(),
1650                    _ => unreachable!(),
1651                };
1652
1653                Ok(DataValue::String(result))
1654            }
1655            "length" => {
1656                if !args.is_empty() {
1657                    return Err(anyhow!("Length takes no arguments"));
1658                }
1659
1660                // Get string length
1661                let len = match value {
1662                    DataValue::String(s) => s.len(),
1663                    DataValue::InternedString(s) => s.len(),
1664                    DataValue::Integer(n) => n.to_string().len(),
1665                    DataValue::Float(f) => f.to_string().len(),
1666                    DataValue::Boolean(b) => b.to_string().len(),
1667                    DataValue::DateTime(dt) => dt.len(),
1668                    DataValue::Null => return Ok(DataValue::Integer(0)),
1669                };
1670
1671                Ok(DataValue::Integer(len as i64))
1672            }
1673            "indexof" => {
1674                if args.len() != 1 {
1675                    return Err(anyhow!("IndexOf requires exactly 1 argument"));
1676                }
1677
1678                // Get the search string from args
1679                let search_str = match self.evaluate(&args[0], row_index)? {
1680                    DataValue::String(s) => s,
1681                    DataValue::InternedString(s) => s.to_string(),
1682                    DataValue::Integer(n) => n.to_string(),
1683                    DataValue::Float(f) => f.to_string(),
1684                    _ => return Err(anyhow!("IndexOf argument must be a string")),
1685                };
1686
1687                // Convert value to string and find index
1688                let str_val = match value {
1689                    DataValue::String(s) => s.clone(),
1690                    DataValue::InternedString(s) => s.to_string(),
1691                    DataValue::Integer(n) => n.to_string(),
1692                    DataValue::Float(f) => f.to_string(),
1693                    DataValue::Boolean(b) => b.to_string(),
1694                    DataValue::DateTime(dt) => dt.clone(),
1695                    DataValue::Null => return Ok(DataValue::Integer(-1)),
1696                };
1697
1698                let index = str_val.find(&search_str).map(|i| i as i64).unwrap_or(-1);
1699
1700                Ok(DataValue::Integer(index))
1701            }
1702            "contains" => {
1703                if args.len() != 1 {
1704                    return Err(anyhow!("Contains requires exactly 1 argument"));
1705                }
1706
1707                // Get the search string from args
1708                let search_str = match self.evaluate(&args[0], row_index)? {
1709                    DataValue::String(s) => s,
1710                    DataValue::InternedString(s) => s.to_string(),
1711                    DataValue::Integer(n) => n.to_string(),
1712                    DataValue::Float(f) => f.to_string(),
1713                    _ => return Err(anyhow!("Contains argument must be a string")),
1714                };
1715
1716                // Convert value to string and check contains
1717                let str_val = match value {
1718                    DataValue::String(s) => s.clone(),
1719                    DataValue::InternedString(s) => s.to_string(),
1720                    DataValue::Integer(n) => n.to_string(),
1721                    DataValue::Float(f) => f.to_string(),
1722                    DataValue::Boolean(b) => b.to_string(),
1723                    DataValue::DateTime(dt) => dt.clone(),
1724                    DataValue::Null => return Ok(DataValue::Boolean(false)),
1725                };
1726
1727                // Case-insensitive search
1728                let result = str_val.to_lowercase().contains(&search_str.to_lowercase());
1729                Ok(DataValue::Boolean(result))
1730            }
1731            "startswith" => {
1732                if args.len() != 1 {
1733                    return Err(anyhow!("StartsWith requires exactly 1 argument"));
1734                }
1735
1736                // Get the prefix from args
1737                let prefix = match self.evaluate(&args[0], row_index)? {
1738                    DataValue::String(s) => s,
1739                    DataValue::InternedString(s) => s.to_string(),
1740                    DataValue::Integer(n) => n.to_string(),
1741                    DataValue::Float(f) => f.to_string(),
1742                    _ => return Err(anyhow!("StartsWith argument must be a string")),
1743                };
1744
1745                // Convert value to string and check starts_with
1746                let str_val = match value {
1747                    DataValue::String(s) => s.clone(),
1748                    DataValue::InternedString(s) => s.to_string(),
1749                    DataValue::Integer(n) => n.to_string(),
1750                    DataValue::Float(f) => f.to_string(),
1751                    DataValue::Boolean(b) => b.to_string(),
1752                    DataValue::DateTime(dt) => dt.clone(),
1753                    DataValue::Null => return Ok(DataValue::Boolean(false)),
1754                };
1755
1756                // Case-insensitive check
1757                let result = str_val.to_lowercase().starts_with(&prefix.to_lowercase());
1758                Ok(DataValue::Boolean(result))
1759            }
1760            "endswith" => {
1761                if args.len() != 1 {
1762                    return Err(anyhow!("EndsWith requires exactly 1 argument"));
1763                }
1764
1765                // Get the suffix from args
1766                let suffix = match self.evaluate(&args[0], row_index)? {
1767                    DataValue::String(s) => s,
1768                    DataValue::InternedString(s) => s.to_string(),
1769                    DataValue::Integer(n) => n.to_string(),
1770                    DataValue::Float(f) => f.to_string(),
1771                    _ => return Err(anyhow!("EndsWith argument must be a string")),
1772                };
1773
1774                // Convert value to string and check ends_with
1775                let str_val = match value {
1776                    DataValue::String(s) => s.clone(),
1777                    DataValue::InternedString(s) => s.to_string(),
1778                    DataValue::Integer(n) => n.to_string(),
1779                    DataValue::Float(f) => f.to_string(),
1780                    DataValue::Boolean(b) => b.to_string(),
1781                    DataValue::DateTime(dt) => dt.clone(),
1782                    DataValue::Null => return Ok(DataValue::Boolean(false)),
1783                };
1784
1785                // Case-insensitive check
1786                let result = str_val.to_lowercase().ends_with(&suffix.to_lowercase());
1787                Ok(DataValue::Boolean(result))
1788            }
1789            _ => Err(anyhow!("Unsupported method: {}", method)),
1790        }
1791    }
1792
1793    /// Evaluate a CASE expression
1794    fn evaluate_case_expression(
1795        &self,
1796        when_branches: &[crate::sql::recursive_parser::WhenBranch],
1797        else_branch: &Option<Box<SqlExpression>>,
1798        row_index: usize,
1799    ) -> Result<DataValue> {
1800        debug!(
1801            "ArithmeticEvaluator: evaluating CASE expression for row {}",
1802            row_index
1803        );
1804
1805        // Evaluate each WHEN condition in order
1806        for branch in when_branches {
1807            // Evaluate the condition as a boolean
1808            let condition_result = self.evaluate_condition_as_bool(&branch.condition, row_index)?;
1809
1810            if condition_result {
1811                debug!("CASE: WHEN condition matched, evaluating result expression");
1812                return self.evaluate(&branch.result, row_index);
1813            }
1814        }
1815
1816        // If no WHEN condition matched, evaluate ELSE clause (or return NULL)
1817        match else_branch {
1818            Some(else_expr) => {
1819                debug!("CASE: No WHEN matched, evaluating ELSE expression");
1820                self.evaluate(else_expr, row_index)
1821            }
1822            None => {
1823                debug!("CASE: No WHEN matched and no ELSE, returning NULL");
1824                Ok(DataValue::Null)
1825            }
1826        }
1827    }
1828
1829    /// Helper method to evaluate an expression as a boolean (for CASE WHEN conditions)
1830    fn evaluate_condition_as_bool(&self, expr: &SqlExpression, row_index: usize) -> Result<bool> {
1831        let value = self.evaluate(expr, row_index)?;
1832
1833        match value {
1834            DataValue::Boolean(b) => Ok(b),
1835            DataValue::Integer(i) => Ok(i != 0),
1836            DataValue::Float(f) => Ok(f != 0.0),
1837            DataValue::Null => Ok(false),
1838            DataValue::String(s) => Ok(!s.is_empty()),
1839            DataValue::InternedString(s) => Ok(!s.is_empty()),
1840            _ => Ok(true), // Other types are considered truthy
1841        }
1842    }
1843}
1844
1845#[cfg(test)]
1846mod tests {
1847    use super::*;
1848    use crate::data::datatable::{DataColumn, DataRow};
1849
1850    fn create_test_table() -> DataTable {
1851        let mut table = DataTable::new("test");
1852        table.add_column(DataColumn::new("a"));
1853        table.add_column(DataColumn::new("b"));
1854        table.add_column(DataColumn::new("c"));
1855
1856        table
1857            .add_row(DataRow::new(vec![
1858                DataValue::Integer(10),
1859                DataValue::Float(2.5),
1860                DataValue::Integer(4),
1861            ]))
1862            .unwrap();
1863
1864        table
1865    }
1866
1867    #[test]
1868    fn test_evaluate_column() {
1869        let table = create_test_table();
1870        let evaluator = ArithmeticEvaluator::new(&table);
1871
1872        let expr = SqlExpression::Column("a".to_string());
1873        let result = evaluator.evaluate(&expr, 0).unwrap();
1874        assert_eq!(result, DataValue::Integer(10));
1875    }
1876
1877    #[test]
1878    fn test_evaluate_number_literal() {
1879        let table = create_test_table();
1880        let evaluator = ArithmeticEvaluator::new(&table);
1881
1882        let expr = SqlExpression::NumberLiteral("42".to_string());
1883        let result = evaluator.evaluate(&expr, 0).unwrap();
1884        assert_eq!(result, DataValue::Integer(42));
1885
1886        let expr = SqlExpression::NumberLiteral("3.14".to_string());
1887        let result = evaluator.evaluate(&expr, 0).unwrap();
1888        assert_eq!(result, DataValue::Float(3.14));
1889    }
1890
1891    #[test]
1892    fn test_add_values() {
1893        let table = create_test_table();
1894        let evaluator = ArithmeticEvaluator::new(&table);
1895
1896        // Integer + Integer
1897        let result = evaluator
1898            .add_values(&DataValue::Integer(5), &DataValue::Integer(3))
1899            .unwrap();
1900        assert_eq!(result, DataValue::Integer(8));
1901
1902        // Integer + Float
1903        let result = evaluator
1904            .add_values(&DataValue::Integer(5), &DataValue::Float(2.5))
1905            .unwrap();
1906        assert_eq!(result, DataValue::Float(7.5));
1907    }
1908
1909    #[test]
1910    fn test_multiply_values() {
1911        let table = create_test_table();
1912        let evaluator = ArithmeticEvaluator::new(&table);
1913
1914        // Integer * Float
1915        let result = evaluator
1916            .multiply_values(&DataValue::Integer(4), &DataValue::Float(2.5))
1917            .unwrap();
1918        assert_eq!(result, DataValue::Float(10.0));
1919    }
1920
1921    #[test]
1922    fn test_divide_values() {
1923        let table = create_test_table();
1924        let evaluator = ArithmeticEvaluator::new(&table);
1925
1926        // Exact division
1927        let result = evaluator
1928            .divide_values(&DataValue::Integer(10), &DataValue::Integer(2))
1929            .unwrap();
1930        assert_eq!(result, DataValue::Integer(5));
1931
1932        // Non-exact division
1933        let result = evaluator
1934            .divide_values(&DataValue::Integer(10), &DataValue::Integer(3))
1935            .unwrap();
1936        assert_eq!(result, DataValue::Float(10.0 / 3.0));
1937    }
1938
1939    #[test]
1940    fn test_division_by_zero() {
1941        let table = create_test_table();
1942        let evaluator = ArithmeticEvaluator::new(&table);
1943
1944        let result = evaluator.divide_values(&DataValue::Integer(10), &DataValue::Integer(0));
1945        assert!(result.is_err());
1946        assert!(result.unwrap_err().to_string().contains("Division by zero"));
1947    }
1948
1949    #[test]
1950    fn test_binary_op_expression() {
1951        let table = create_test_table();
1952        let evaluator = ArithmeticEvaluator::new(&table);
1953
1954        // a * b where a=10, b=2.5
1955        let expr = SqlExpression::BinaryOp {
1956            left: Box::new(SqlExpression::Column("a".to_string())),
1957            op: "*".to_string(),
1958            right: Box::new(SqlExpression::Column("b".to_string())),
1959        };
1960
1961        let result = evaluator.evaluate(&expr, 0).unwrap();
1962        assert_eq!(result, DataValue::Float(25.0));
1963    }
1964}