1use crate::data::arithmetic_evaluator::ArithmeticEvaluator;
2use crate::data::datatable::{DataTable, DataValue};
3use crate::sql::recursive_parser::{Condition, LogicalOp, SqlExpression, WhereClause};
4use anyhow::{anyhow, Result};
5use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
6use tracing::debug;
7
8pub struct RecursiveWhereEvaluator<'a> {
10 table: &'a DataTable,
11 case_insensitive: bool,
12 date_notation: String,
13}
14
15impl<'a> RecursiveWhereEvaluator<'a> {
16 pub fn new(table: &'a DataTable) -> Self {
17 Self {
18 table,
19 case_insensitive: false,
20 date_notation: "us".to_string(),
21 }
22 }
23
24 pub fn with_date_notation(table: &'a DataTable, date_notation: String) -> Self {
25 Self {
26 table,
27 case_insensitive: false,
28 date_notation,
29 }
30 }
31
32 fn find_similar_column(&self, name: &str) -> Option<String> {
34 let columns = self.table.column_names();
35 let mut best_match: Option<(String, usize)> = None;
36
37 for col in columns {
38 let distance = self.edit_distance(&col.to_lowercase(), &name.to_lowercase());
39 let max_distance = if name.len() > 10 { 3 } else { 2 };
42 if distance <= max_distance {
43 match &best_match {
44 None => best_match = Some((col, distance)),
45 Some((_, best_dist)) if distance < *best_dist => {
46 best_match = Some((col, distance));
47 }
48 _ => {}
49 }
50 }
51 }
52
53 best_match.map(|(name, _)| name)
54 }
55
56 fn edit_distance(&self, s1: &str, s2: &str) -> usize {
58 let len1 = s1.len();
59 let len2 = s2.len();
60 let mut matrix = vec![vec![0; len2 + 1]; len1 + 1];
61
62 for i in 0..=len1 {
63 matrix[i][0] = i;
64 }
65 for j in 0..=len2 {
66 matrix[0][j] = j;
67 }
68
69 for (i, c1) in s1.chars().enumerate() {
70 for (j, c2) in s2.chars().enumerate() {
71 let cost = if c1 == c2 { 0 } else { 1 };
72 matrix[i + 1][j + 1] = std::cmp::min(
73 matrix[i][j + 1] + 1, std::cmp::min(
75 matrix[i + 1][j] + 1, matrix[i][j] + cost, ),
78 );
79 }
80 }
81
82 matrix[len1][len2]
83 }
84
85 pub fn with_case_insensitive(table: &'a DataTable, case_insensitive: bool) -> Self {
86 Self {
87 table,
88 case_insensitive,
89 date_notation: "us".to_string(),
90 }
91 }
92
93 pub fn with_config(
94 table: &'a DataTable,
95 case_insensitive: bool,
96 date_notation: String,
97 ) -> Self {
98 Self {
99 table,
100 case_insensitive,
101 date_notation,
102 }
103 }
104
105 fn compare_datetime(op: &str, left: &DateTime<Utc>, right: &DateTime<Utc>) -> bool {
107 match op {
108 "=" => left == right,
109 "!=" | "<>" => left != right,
110 ">" => left > right,
111 ">=" => left >= right,
112 "<" => left < right,
113 "<=" => left <= right,
114 _ => false,
115 }
116 }
117
118 fn evaluate_length(
120 &self,
121 object: &str,
122 row_index: usize,
123 ) -> Result<(Option<DataValue>, String)> {
124 let col_index = self.table.get_column_index(object).ok_or_else(|| {
125 let suggestion = self.find_similar_column(object);
126 match suggestion {
127 Some(similar) => {
128 anyhow!("Column '{}' not found. Did you mean '{}'?", object, similar)
129 }
130 None => anyhow!("Column '{}' not found", object),
131 }
132 })?;
133
134 let value = self.table.get_value(row_index, col_index);
135 let length_value = match value {
136 Some(DataValue::String(s)) => Some(DataValue::Integer(s.len() as i64)),
137 Some(DataValue::InternedString(s)) => Some(DataValue::Integer(s.len() as i64)),
138 Some(DataValue::Integer(n)) => Some(DataValue::Integer(n.to_string().len() as i64)),
139 Some(DataValue::Float(f)) => Some(DataValue::Integer(f.to_string().len() as i64)),
140 _ => Some(DataValue::Integer(0)),
141 };
142 Ok((length_value, format!("{}.Length()", object)))
143 }
144
145 fn evaluate_indexof(
147 &self,
148 object: &str,
149 search_str: &str,
150 row_index: usize,
151 ) -> Result<(Option<DataValue>, String)> {
152 let col_index = self.table.get_column_index(object).ok_or_else(|| {
153 let suggestion = self.find_similar_column(object);
154 match suggestion {
155 Some(similar) => {
156 anyhow!("Column '{}' not found. Did you mean '{}'?", object, similar)
157 }
158 None => anyhow!("Column '{}' not found", object),
159 }
160 })?;
161
162 let value = self.table.get_value(row_index, col_index);
163 let index_value = match value {
164 Some(DataValue::String(s)) => {
165 let pos = s
167 .to_lowercase()
168 .find(&search_str.to_lowercase())
169 .map(|idx| idx as i64)
170 .unwrap_or(-1);
171 Some(DataValue::Integer(pos))
172 }
173 Some(DataValue::InternedString(s)) => {
174 let pos = s
175 .to_lowercase()
176 .find(&search_str.to_lowercase())
177 .map(|idx| idx as i64)
178 .unwrap_or(-1);
179 Some(DataValue::Integer(pos))
180 }
181 Some(DataValue::Integer(n)) => {
182 let str_val = n.to_string();
183 let pos = str_val.find(search_str).map(|idx| idx as i64).unwrap_or(-1);
184 Some(DataValue::Integer(pos))
185 }
186 Some(DataValue::Float(f)) => {
187 let str_val = f.to_string();
188 let pos = str_val.find(search_str).map(|idx| idx as i64).unwrap_or(-1);
189 Some(DataValue::Integer(pos))
190 }
191 _ => Some(DataValue::Integer(-1)), };
193
194 if row_index < 3 {
195 debug!(
196 "RecursiveWhereEvaluator: Row {} IndexOf('{}') = {:?}",
197 row_index, search_str, index_value
198 );
199 }
200 Ok((index_value, format!("{}.IndexOf('{}')", object, search_str)))
201 }
202
203 fn apply_trim<'b>(s: &'b str, trim_type: &str) -> &'b str {
205 match trim_type {
206 "trim" => s.trim(),
207 "trimstart" => s.trim_start(),
208 "trimend" => s.trim_end(),
209 _ => s,
210 }
211 }
212
213 fn evaluate_trim(
215 &self,
216 object: &str,
217 row_index: usize,
218 trim_type: &str,
219 ) -> Result<(Option<DataValue>, String)> {
220 let col_index = self.table.get_column_index(object).ok_or_else(|| {
221 let suggestion = self.find_similar_column(object);
222 match suggestion {
223 Some(similar) => {
224 anyhow!("Column '{}' not found. Did you mean '{}'?", object, similar)
225 }
226 None => anyhow!("Column '{}' not found", object),
227 }
228 })?;
229
230 let value = self.table.get_value(row_index, col_index);
231 let trimmed_value = match value {
232 Some(DataValue::String(s)) => Some(DataValue::String(
233 Self::apply_trim(&s, trim_type).to_string(),
234 )),
235 Some(DataValue::InternedString(s)) => Some(DataValue::String(
236 Self::apply_trim(&s, trim_type).to_string(),
237 )),
238 Some(DataValue::Integer(n)) => {
239 let str_val = n.to_string();
240 Some(DataValue::String(
241 Self::apply_trim(&str_val, trim_type).to_string(),
242 ))
243 }
244 Some(DataValue::Float(f)) => {
245 let str_val = f.to_string();
246 Some(DataValue::String(
247 Self::apply_trim(&str_val, trim_type).to_string(),
248 ))
249 }
250 _ => Some(DataValue::String(String::new())),
251 };
252
253 let method_name = match trim_type {
254 "trim" => "Trim",
255 "trimstart" => "TrimStart",
256 "trimend" => "TrimEnd",
257 _ => "Trim",
258 };
259 Ok((trimmed_value, format!("{}.{}()", object, method_name)))
260 }
261
262 pub fn evaluate(&self, where_clause: &WhereClause, row_index: usize) -> Result<bool> {
264 if row_index < 3 {
266 debug!(
267 "RecursiveWhereEvaluator: evaluate() ENTRY - row {}, {} conditions, case_insensitive={}",
268 row_index,
269 where_clause.conditions.len(),
270 self.case_insensitive
271 );
272 }
273
274 if where_clause.conditions.is_empty() {
275 if row_index < 3 {
276 debug!("RecursiveWhereEvaluator: evaluate() EXIT - no conditions, returning true");
277 }
278 return Ok(true);
279 }
280
281 if row_index < 3 {
283 debug!(
284 "RecursiveWhereEvaluator: evaluate() - evaluating first condition for row {}",
285 row_index
286 );
287 }
288 let mut result = self.evaluate_condition(&where_clause.conditions[0], row_index)?;
289
290 for i in 1..where_clause.conditions.len() {
292 let next_result = self.evaluate_condition(&where_clause.conditions[i], row_index)?;
293
294 if let Some(connector) = &where_clause.conditions[i - 1].connector {
296 result = match connector {
297 LogicalOp::And => result && next_result,
298 LogicalOp::Or => result || next_result,
299 };
300 }
301 }
302
303 Ok(result)
304 }
305
306 fn evaluate_condition(&self, condition: &Condition, row_index: usize) -> Result<bool> {
307 if row_index < 3 {
309 debug!(
310 "RecursiveWhereEvaluator: evaluate_condition() ENTRY - row {}",
311 row_index
312 );
313 }
314 let result = self.evaluate_expression(&condition.expr, row_index);
315 if row_index < 3 {
316 debug!(
317 "RecursiveWhereEvaluator: evaluate_condition() EXIT - row {}, result = {:?}",
318 row_index, result
319 );
320 }
321 result
322 }
323
324 fn evaluate_expression(&self, expr: &SqlExpression, row_index: usize) -> Result<bool> {
325 if row_index < 3 {
327 debug!(
328 "RecursiveWhereEvaluator: evaluate_expression() ENTRY - row {}, expr = {:?}",
329 row_index, expr
330 );
331 }
332
333 let result = match expr {
334 SqlExpression::BinaryOp { left, op, right } => {
335 self.evaluate_binary_op(left, op, right, row_index)
336 }
337 SqlExpression::InList { expr, values } => {
338 self.evaluate_in_list(expr, values, row_index, false)
339 }
340 SqlExpression::NotInList { expr, values } => {
341 let in_result = self.evaluate_in_list(expr, values, row_index, false)?;
342 Ok(!in_result)
343 }
344 SqlExpression::Between { expr, lower, upper } => {
345 self.evaluate_between(expr, lower, upper, row_index)
346 }
347 SqlExpression::Not { expr } => {
348 let inner_result = self.evaluate_expression(expr, row_index)?;
349 Ok(!inner_result)
350 }
351 SqlExpression::MethodCall {
352 object,
353 method,
354 args,
355 } => {
356 if row_index < 3 {
357 debug!("RecursiveWhereEvaluator: evaluate_expression() - found MethodCall, delegating to evaluate_method_call");
358 }
359 self.evaluate_method_call(object, method, args, row_index)
360 }
361 SqlExpression::CaseExpression {
362 when_branches,
363 else_branch,
364 } => {
365 if row_index < 3 {
366 debug!("RecursiveWhereEvaluator: evaluate_expression() - found CaseExpression, evaluating");
367 }
368 self.evaluate_case_expression_as_bool(when_branches, else_branch, row_index)
369 }
370 _ => {
371 if row_index < 3 {
372 debug!("RecursiveWhereEvaluator: evaluate_expression() - unsupported expression type, returning false");
373 }
374 Ok(false) }
376 };
377
378 if row_index < 3 {
379 debug!(
380 "RecursiveWhereEvaluator: evaluate_expression() EXIT - row {}, result = {:?}",
381 row_index, result
382 );
383 }
384 result
385 }
386
387 fn evaluate_binary_op(
388 &self,
389 left: &SqlExpression,
390 op: &str,
391 right: &SqlExpression,
392 row_index: usize,
393 ) -> Result<bool> {
394 if row_index < 3 {
396 debug!(
397 "RecursiveWhereEvaluator: evaluate_binary_op() ENTRY - row {}, op = '{}'",
398 row_index, op
399 );
400 }
401
402 let (cell_value, column_name) = match left {
404 SqlExpression::MethodCall {
405 object,
406 method,
407 args,
408 } => {
409 match method.to_lowercase().as_str() {
411 "length" => {
412 if !args.is_empty() {
413 return Err(anyhow::anyhow!("Length() takes no arguments"));
414 }
415 self.evaluate_length(object, row_index)?
416 }
417 "indexof" => {
418 if args.len() != 1 {
419 return Err(anyhow::anyhow!("IndexOf() requires exactly 1 argument"));
420 }
421 let search_str = self.extract_string_value(&args[0])?;
422 self.evaluate_indexof(object, &search_str, row_index)?
423 }
424 "trim" => {
425 if !args.is_empty() {
426 return Err(anyhow::anyhow!("Trim() takes no arguments"));
427 }
428 self.evaluate_trim(object, row_index, "trim")?
429 }
430 "trimstart" => {
431 if !args.is_empty() {
432 return Err(anyhow::anyhow!("TrimStart() takes no arguments"));
433 }
434 self.evaluate_trim(object, row_index, "trimstart")?
435 }
436 "trimend" => {
437 if !args.is_empty() {
438 return Err(anyhow::anyhow!("TrimEnd() takes no arguments"));
439 }
440 self.evaluate_trim(object, row_index, "trimend")?
441 }
442 _ => {
443 return Err(anyhow::anyhow!(
444 "Method '{}' cannot be used in comparisons",
445 method
446 ));
447 }
448 }
449 }
450 SqlExpression::BinaryOp {
451 left: _expr_left,
452 op: arith_op,
453 right: _expr_right,
454 } if matches!(arith_op.as_str(), "+" | "-" | "*" | "/") => {
455 let evaluator =
457 ArithmeticEvaluator::with_date_notation(self.table, self.date_notation.clone());
458 let computed_value = evaluator.evaluate(left, row_index)?;
459 if row_index < 3 {
460 debug!(
461 "RecursiveWhereEvaluator: evaluate_binary_op() - computed arithmetic expression = {:?}",
462 computed_value
463 );
464 }
465 (Some(computed_value), "computed_expression".to_string())
466 }
467 SqlExpression::FunctionCall { name, .. } => {
468 let evaluator =
470 ArithmeticEvaluator::with_date_notation(self.table, self.date_notation.clone());
471 let computed_value = evaluator.evaluate(left, row_index)?;
472 if row_index < 3 {
473 debug!(
474 "RecursiveWhereEvaluator: evaluate_binary_op() - computed function {} = {:?}",
475 name, computed_value
476 );
477 }
478 (Some(computed_value), format!("{}()", name))
479 }
480 _ => {
481 let column_name = self.extract_column_name(left)?;
483 if row_index < 3 {
484 debug!(
485 "RecursiveWhereEvaluator: evaluate_binary_op() - column_name = '{}'",
486 column_name
487 );
488 }
489
490 let col_index = self.table.get_column_index(&column_name).ok_or_else(|| {
491 let suggestion = self.find_similar_column(&column_name);
492 match suggestion {
493 Some(similar) => anyhow!(
494 "Column '{}' not found. Did you mean '{}'?",
495 column_name,
496 similar
497 ),
498 None => anyhow!("Column '{}' not found", column_name),
499 }
500 })?;
501
502 let cell_value = self.table.get_value(row_index, col_index).cloned();
503 (cell_value, column_name)
504 }
505 };
506
507 if row_index < 3 {
508 debug!(
509 "RecursiveWhereEvaluator: evaluate_binary_op() - row {} column '{}' value = {:?}",
510 row_index, column_name, cell_value
511 );
512 }
513
514 let compare_value = self.extract_value(right)?;
516
517 match (cell_value, op.to_uppercase().as_str(), &compare_value) {
519 (Some(DataValue::String(ref a)), "=", ExprValue::String(b)) => {
520 if row_index < 3 {
521 debug!(
522 "RecursiveWhereEvaluator: String comparison '{}' = '{}' (case_insensitive={})",
523 a, b, self.case_insensitive
524 );
525 }
526 if self.case_insensitive {
527 Ok(a.to_lowercase() == b.to_lowercase())
528 } else {
529 Ok(a == b)
530 }
531 }
532 (Some(DataValue::InternedString(ref a)), "=", ExprValue::String(b)) => {
533 if row_index < 3 {
534 debug!(
535 "RecursiveWhereEvaluator: InternedString comparison '{}' = '{}' (case_insensitive={})",
536 a, b, self.case_insensitive
537 );
538 }
539 if self.case_insensitive {
540 Ok(a.to_lowercase() == b.to_lowercase())
541 } else {
542 Ok(a.as_ref() == b)
543 }
544 }
545 (Some(DataValue::String(ref a)), "!=", ExprValue::String(b))
546 | (Some(DataValue::String(ref a)), "<>", ExprValue::String(b)) => {
547 if row_index < 3 {
548 debug!(
549 "RecursiveWhereEvaluator: String comparison '{}' != '{}' (case_insensitive={})",
550 a, b, self.case_insensitive
551 );
552 }
553 if self.case_insensitive {
554 Ok(a.to_lowercase() != b.to_lowercase())
555 } else {
556 Ok(a != b)
557 }
558 }
559 (Some(DataValue::InternedString(ref a)), "!=", ExprValue::String(b))
560 | (Some(DataValue::InternedString(ref a)), "<>", ExprValue::String(b)) => {
561 if row_index < 3 {
562 debug!(
563 "RecursiveWhereEvaluator: InternedString comparison '{}' != '{}' (case_insensitive={})",
564 a, b, self.case_insensitive
565 );
566 }
567 if self.case_insensitive {
568 Ok(a.to_lowercase() != b.to_lowercase())
569 } else {
570 Ok(a.as_ref() != b)
571 }
572 }
573 (Some(DataValue::String(ref a)), ">", ExprValue::String(b)) => {
574 if self.case_insensitive {
575 Ok(a.to_lowercase() > b.to_lowercase())
576 } else {
577 Ok(a > b)
578 }
579 }
580 (Some(DataValue::InternedString(ref a)), ">", ExprValue::String(b)) => {
581 if self.case_insensitive {
582 Ok(a.to_lowercase() > b.to_lowercase())
583 } else {
584 Ok(a.as_ref() > b)
585 }
586 }
587 (Some(DataValue::String(ref a)), ">=", ExprValue::String(b)) => {
588 if self.case_insensitive {
589 Ok(a.to_lowercase() >= b.to_lowercase())
590 } else {
591 Ok(a >= b)
592 }
593 }
594 (Some(DataValue::InternedString(ref a)), ">=", ExprValue::String(b)) => {
595 if self.case_insensitive {
596 Ok(a.to_lowercase() >= b.to_lowercase())
597 } else {
598 Ok(a.as_ref() >= b)
599 }
600 }
601 (Some(DataValue::String(ref a)), "<", ExprValue::String(b)) => {
602 if self.case_insensitive {
603 Ok(a.to_lowercase() < b.to_lowercase())
604 } else {
605 Ok(a < b)
606 }
607 }
608 (Some(DataValue::InternedString(ref a)), "<", ExprValue::String(b)) => {
609 if self.case_insensitive {
610 Ok(a.to_lowercase() < b.to_lowercase())
611 } else {
612 Ok(a.as_ref() < b)
613 }
614 }
615 (Some(DataValue::String(ref a)), "<=", ExprValue::String(b)) => {
616 if self.case_insensitive {
617 Ok(a.to_lowercase() <= b.to_lowercase())
618 } else {
619 Ok(a <= b)
620 }
621 }
622 (Some(DataValue::InternedString(ref a)), "<=", ExprValue::String(b)) => {
623 if self.case_insensitive {
624 Ok(a.to_lowercase() <= b.to_lowercase())
625 } else {
626 Ok(a.as_ref() <= b)
627 }
628 }
629
630 (Some(DataValue::Integer(a)), "=", ExprValue::Number(b)) => Ok(a as f64 == *b),
631 (Some(DataValue::Integer(a)), "!=", ExprValue::Number(b))
632 | (Some(DataValue::Integer(a)), "<>", ExprValue::Number(b)) => Ok(a as f64 != *b),
633 (Some(DataValue::Integer(a)), ">", ExprValue::Number(b)) => Ok(a as f64 > *b),
634 (Some(DataValue::Integer(a)), ">=", ExprValue::Number(b)) => Ok(a as f64 >= *b),
635 (Some(DataValue::Integer(a)), "<", ExprValue::Number(b)) => Ok((a as f64) < *b),
636 (Some(DataValue::Integer(a)), "<=", ExprValue::Number(b)) => Ok(a as f64 <= *b),
637
638 (Some(DataValue::Float(a)), "=", ExprValue::Number(b)) => {
639 Ok((a - b).abs() < f64::EPSILON)
640 }
641 (Some(DataValue::Float(a)), "!=", ExprValue::Number(b))
642 | (Some(DataValue::Float(a)), "<>", ExprValue::Number(b)) => {
643 Ok((a - b).abs() >= f64::EPSILON)
644 }
645 (Some(DataValue::Float(a)), ">", ExprValue::Number(b)) => Ok(a > *b),
646 (Some(DataValue::Float(a)), ">=", ExprValue::Number(b)) => Ok(a >= *b),
647 (Some(DataValue::Float(a)), "<", ExprValue::Number(b)) => Ok(a < *b),
648 (Some(DataValue::Float(a)), "<=", ExprValue::Number(b)) => Ok(a <= *b),
649
650 (Some(DataValue::String(ref text)), "LIKE", ExprValue::String(pattern)) => {
652 let regex_pattern = pattern.replace('%', ".*").replace('_', ".");
653 let regex = regex::RegexBuilder::new(&format!("^{}$", regex_pattern))
654 .case_insensitive(true)
655 .build()
656 .map_err(|e| anyhow::anyhow!("Invalid LIKE pattern: {}", e))?;
657 Ok(regex.is_match(text))
658 }
659 (Some(DataValue::InternedString(ref text)), "LIKE", ExprValue::String(pattern)) => {
660 let regex_pattern = pattern.replace('%', ".*").replace('_', ".");
661 let regex = regex::RegexBuilder::new(&format!("^{}$", regex_pattern))
662 .case_insensitive(true)
663 .build()
664 .map_err(|e| anyhow::anyhow!("Invalid LIKE pattern: {}", e))?;
665 Ok(regex.is_match(text.as_ref()))
666 }
667
668 (None, "IS", ExprValue::Null) | (Some(DataValue::Null), "IS", ExprValue::Null) => {
670 Ok(true)
671 }
672 (Some(_), "IS", ExprValue::Null) => Ok(false),
673 (None, "IS NOT", ExprValue::Null)
674 | (Some(DataValue::Null), "IS NOT", ExprValue::Null) => Ok(false),
675 (Some(_), "IS NOT", ExprValue::Null) => Ok(true),
676
677 (Some(DataValue::String(ref date_str)), op_str, ExprValue::DateTime(dt)) => {
679 if row_index < 3 {
680 debug!(
681 "RecursiveWhereEvaluator: DateTime comparison '{}' {} '{}' - attempting parse",
682 date_str,
683 op_str,
684 dt.format("%Y-%m-%d %H:%M:%S")
685 );
686 }
687
688 if let Ok(parsed_dt) = date_str.parse::<DateTime<Utc>>() {
690 let result = Self::compare_datetime(op_str, &parsed_dt, dt);
691 if row_index < 3 {
692 debug!(
693 "RecursiveWhereEvaluator: DateTime parsed as UTC: '{}' {} '{}' = {}",
694 parsed_dt.format("%Y-%m-%d %H:%M:%S"),
695 op_str,
696 dt.format("%Y-%m-%d %H:%M:%S"),
697 result
698 );
699 }
700 Ok(result)
701 }
702 else if let Ok(parsed_dt) =
704 NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S")
705 {
706 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
707 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
708 if row_index < 3 {
709 debug!(
710 "RecursiveWhereEvaluator: DateTime parsed as ISO 8601: '{}' {} '{}' = {}",
711 parsed_utc.format("%Y-%m-%d %H:%M:%S"),
712 op_str,
713 dt.format("%Y-%m-%d %H:%M:%S"),
714 result
715 );
716 }
717 Ok(result)
718 }
719 else if let Ok(parsed_dt) =
721 NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%d %H:%M:%S")
722 {
723 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
724 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
725 if row_index < 3 {
726 debug!(
727 "RecursiveWhereEvaluator: DateTime parsed as standard format: '{}' {} '{}' = {}",
728 parsed_utc.format("%Y-%m-%d %H:%M:%S"), op_str, dt.format("%Y-%m-%d %H:%M:%S"), result
729 );
730 }
731 Ok(result)
732 }
733 else if let Ok(parsed_date) = NaiveDate::parse_from_str(&date_str, "%Y-%m-%d") {
735 let parsed_dt =
736 NaiveDateTime::new(parsed_date, NaiveTime::from_hms_opt(0, 0, 0).unwrap());
737 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
738 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
739 if row_index < 3 {
740 debug!(
741 "RecursiveWhereEvaluator: DateTime parsed as date-only: '{}' {} '{}' = {}",
742 parsed_utc.format("%Y-%m-%d %H:%M:%S"),
743 op_str,
744 dt.format("%Y-%m-%d %H:%M:%S"),
745 result
746 );
747 }
748 Ok(result)
749 } else {
750 if row_index < 3 {
751 debug!(
752 "RecursiveWhereEvaluator: DateTime parse FAILED for '{}' - no matching format",
753 date_str
754 );
755 }
756 Ok(false)
757 }
758 }
759 (Some(DataValue::InternedString(ref date_str)), op_str, ExprValue::DateTime(dt)) => {
760 if row_index < 3 {
761 debug!(
762 "RecursiveWhereEvaluator: DateTime comparison (interned) '{}' {} '{}' - attempting parse",
763 date_str,
764 op_str,
765 dt.format("%Y-%m-%d %H:%M:%S")
766 );
767 }
768
769 if let Ok(parsed_dt) = date_str.parse::<DateTime<Utc>>() {
771 let result = Self::compare_datetime(op_str, &parsed_dt, dt);
772 if row_index < 3 {
773 debug!(
774 "RecursiveWhereEvaluator: DateTime parsed as UTC: '{}' {} '{}' = {}",
775 parsed_dt.format("%Y-%m-%d %H:%M:%S"),
776 op_str,
777 dt.format("%Y-%m-%d %H:%M:%S"),
778 result
779 );
780 }
781 Ok(result)
782 }
783 else if let Ok(parsed_dt) =
785 NaiveDateTime::parse_from_str(date_str.as_ref(), "%Y-%m-%dT%H:%M:%S")
786 {
787 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
788 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
789 if row_index < 3 {
790 debug!(
791 "RecursiveWhereEvaluator: DateTime parsed as ISO 8601: '{}' {} '{}' = {}",
792 parsed_utc.format("%Y-%m-%d %H:%M:%S"),
793 op_str,
794 dt.format("%Y-%m-%d %H:%M:%S"),
795 result
796 );
797 }
798 Ok(result)
799 }
800 else if let Ok(parsed_dt) =
802 NaiveDateTime::parse_from_str(date_str.as_ref(), "%Y-%m-%d %H:%M:%S")
803 {
804 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
805 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
806 if row_index < 3 {
807 debug!(
808 "RecursiveWhereEvaluator: DateTime parsed as standard format: '{}' {} '{}' = {}",
809 parsed_utc.format("%Y-%m-%d %H:%M:%S"), op_str, dt.format("%Y-%m-%d %H:%M:%S"), result
810 );
811 }
812 Ok(result)
813 }
814 else if let Ok(parsed_date) =
816 NaiveDate::parse_from_str(date_str.as_ref(), "%Y-%m-%d")
817 {
818 let parsed_dt =
819 NaiveDateTime::new(parsed_date, NaiveTime::from_hms_opt(0, 0, 0).unwrap());
820 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
821 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
822 if row_index < 3 {
823 debug!(
824 "RecursiveWhereEvaluator: DateTime parsed as date-only: '{}' {} '{}' = {}",
825 parsed_utc.format("%Y-%m-%d %H:%M:%S"),
826 op_str,
827 dt.format("%Y-%m-%d %H:%M:%S"),
828 result
829 );
830 }
831 Ok(result)
832 } else {
833 if row_index < 3 {
834 debug!(
835 "RecursiveWhereEvaluator: DateTime parse FAILED for '{}' - no matching format",
836 date_str
837 );
838 }
839 Ok(false)
840 }
841 }
842
843 (Some(DataValue::DateTime(ref date_str)), op_str, ExprValue::DateTime(dt)) => {
845 if row_index < 3 {
846 debug!(
847 "RecursiveWhereEvaluator: DateTime vs DateTime comparison '{}' {} '{}' - direct comparison",
848 date_str, op_str, dt.format("%Y-%m-%d %H:%M:%S")
849 );
850 }
851
852 if let Ok(parsed_dt) = date_str.parse::<DateTime<Utc>>() {
854 let result = Self::compare_datetime(op_str, &parsed_dt, dt);
855 if row_index < 3 {
856 debug!(
857 "RecursiveWhereEvaluator: DateTime vs DateTime parsed successfully: '{}' {} '{}' = {}",
858 parsed_dt.format("%Y-%m-%d %H:%M:%S"), op_str, dt.format("%Y-%m-%d %H:%M:%S"), result
859 );
860 }
861 Ok(result)
862 }
863 else if let Ok(parsed_dt) =
865 NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S")
866 {
867 let parsed_utc = Utc.from_utc_datetime(&parsed_dt);
868 let result = Self::compare_datetime(op_str, &parsed_utc, dt);
869 if row_index < 3 {
870 debug!(
871 "RecursiveWhereEvaluator: DateTime vs DateTime ISO 8601: '{}' {} '{}' = {}",
872 parsed_utc.format("%Y-%m-%d %H:%M:%S"),
873 op_str,
874 dt.format("%Y-%m-%d %H:%M:%S"),
875 result
876 );
877 }
878 Ok(result)
879 } else {
880 if row_index < 3 {
881 debug!(
882 "RecursiveWhereEvaluator: DateTime vs DateTime parse FAILED for '{}' - no matching format",
883 date_str
884 );
885 }
886 Ok(false)
887 }
888 }
889
890 _ => Ok(false),
891 }
892 }
893
894 fn evaluate_in_list(
895 &self,
896 expr: &SqlExpression,
897 values: &[SqlExpression],
898 row_index: usize,
899 _ignore_case: bool,
900 ) -> Result<bool> {
901 let column_name = self.extract_column_name(expr)?;
902 let col_index = self
903 .table
904 .get_column_index(&column_name)
905 .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column_name))?;
906
907 let cell_value = self.table.get_value(row_index, col_index).cloned();
908
909 for value_expr in values {
910 let compare_value = self.extract_value(value_expr)?;
911 let matches = match (cell_value.as_ref(), &compare_value) {
912 (Some(DataValue::String(a)), ExprValue::String(b)) => {
913 if self.case_insensitive {
914 if row_index < 3 {
915 debug!("RecursiveWhereEvaluator: IN list string comparison '{}' in '{}' (case_insensitive={})", a, b, self.case_insensitive);
916 }
917 a.to_lowercase() == b.to_lowercase()
918 } else {
919 a == b
920 }
921 }
922 (Some(DataValue::InternedString(a)), ExprValue::String(b)) => {
923 if self.case_insensitive {
924 if row_index < 3 {
925 debug!("RecursiveWhereEvaluator: IN list interned string comparison '{}' in '{}' (case_insensitive={})", a, b, self.case_insensitive);
926 }
927 a.to_lowercase() == b.to_lowercase()
928 } else {
929 a.as_ref() == b
930 }
931 }
932 (Some(DataValue::Integer(a)), ExprValue::Number(b)) => *a as f64 == *b,
933 (Some(DataValue::Float(a)), ExprValue::Number(b)) => (*a - b).abs() < f64::EPSILON,
934 _ => false,
935 };
936
937 if matches {
938 return Ok(true);
939 }
940 }
941
942 Ok(false)
943 }
944
945 fn evaluate_between(
946 &self,
947 expr: &SqlExpression,
948 lower: &SqlExpression,
949 upper: &SqlExpression,
950 row_index: usize,
951 ) -> Result<bool> {
952 let column_name = self.extract_column_name(expr)?;
953 let col_index = self
954 .table
955 .get_column_index(&column_name)
956 .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column_name))?;
957
958 let cell_value = self.table.get_value(row_index, col_index).cloned();
959 let lower_value = self.extract_value(lower)?;
960 let upper_value = self.extract_value(upper)?;
961
962 match (cell_value, &lower_value, &upper_value) {
963 (Some(DataValue::Integer(n)), ExprValue::Number(l), ExprValue::Number(u)) => {
964 Ok(n as f64 >= *l && n as f64 <= *u)
965 }
966 (Some(DataValue::Float(n)), ExprValue::Number(l), ExprValue::Number(u)) => {
967 Ok(n >= *l && n <= *u)
968 }
969 (Some(DataValue::String(ref s)), ExprValue::String(l), ExprValue::String(u)) => {
970 Ok(s >= l && s <= u)
971 }
972 (
973 Some(DataValue::InternedString(ref s)),
974 ExprValue::String(l),
975 ExprValue::String(u),
976 ) => Ok(s.as_ref() >= l && s.as_ref() <= u),
977 _ => Ok(false),
978 }
979 }
980
981 fn evaluate_method_call(
982 &self,
983 object: &str,
984 method: &str,
985 args: &[SqlExpression],
986 row_index: usize,
987 ) -> Result<bool> {
988 if row_index < 3 {
989 debug!(
990 "RecursiveWhereEvaluator: evaluate_method_call - object='{}', method='{}', row={}",
991 object, method, row_index
992 );
993 }
994
995 let col_index = self.table.get_column_index(object).ok_or_else(|| {
997 let suggestion = self.find_similar_column(object);
998 match suggestion {
999 Some(similar) => {
1000 anyhow!("Column '{}' not found. Did you mean '{}'?", object, similar)
1001 }
1002 None => anyhow!("Column '{}' not found", object),
1003 }
1004 })?;
1005
1006 let cell_value = self.table.get_value(row_index, col_index).cloned();
1007 if row_index < 3 {
1008 debug!(
1009 "RecursiveWhereEvaluator: Row {} column '{}' value = {:?}",
1010 row_index, object, cell_value
1011 );
1012 }
1013
1014 match method.to_lowercase().as_str() {
1015 "contains" => {
1016 if args.len() != 1 {
1017 return Err(anyhow::anyhow!("Contains requires exactly 1 argument"));
1018 }
1019 let search_str = self.extract_string_value(&args[0])?;
1020 let search_lower = search_str.to_lowercase();
1022
1023 match cell_value {
1025 Some(DataValue::String(ref s)) => {
1026 let result = s.to_lowercase().contains(&search_lower);
1027 if row_index < 3 {
1029 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on '{}' = {} (case-insensitive)", row_index, search_str, s, result);
1030 }
1031 Ok(result)
1032 }
1033 Some(DataValue::InternedString(ref s)) => {
1034 let result = s.to_lowercase().contains(&search_lower);
1035 if row_index < 3 {
1037 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on interned '{}' = {} (case-insensitive)", row_index, search_str, s, result);
1038 }
1039 Ok(result)
1040 }
1041 Some(DataValue::Integer(n)) => {
1042 let str_val = n.to_string();
1043 let result = str_val.contains(&search_str);
1044 if row_index < 3 {
1045 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on integer '{}' = {}", row_index, search_str, str_val, result);
1046 }
1047 Ok(result)
1048 }
1049 Some(DataValue::Float(f)) => {
1050 let str_val = f.to_string();
1051 let result = str_val.contains(&search_str);
1052 if row_index < 3 {
1053 debug!(
1054 "RecursiveWhereEvaluator: Row {} contains('{}') on float '{}' = {}",
1055 row_index, search_str, str_val, result
1056 );
1057 }
1058 Ok(result)
1059 }
1060 Some(DataValue::Boolean(b)) => {
1061 let str_val = b.to_string();
1062 let result = str_val.contains(&search_str);
1063 if row_index < 3 {
1064 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on boolean '{}' = {}", row_index, search_str, str_val, result);
1065 }
1066 Ok(result)
1067 }
1068 Some(DataValue::DateTime(dt)) => {
1069 let result = dt.contains(&search_str);
1071 if row_index < 3 {
1072 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on datetime '{}' = {}", row_index, search_str, dt, result);
1073 }
1074 Ok(result)
1075 }
1076 _ => {
1077 if row_index < 3 {
1078 debug!("RecursiveWhereEvaluator: Row {} contains('{}') on null/empty value = false", row_index, search_str);
1079 }
1080 Ok(false)
1081 }
1082 }
1083 }
1084 "startswith" => {
1085 if args.len() != 1 {
1086 return Err(anyhow::anyhow!("StartsWith requires exactly 1 argument"));
1087 }
1088 let prefix = self.extract_string_value(&args[0])?;
1089
1090 match cell_value {
1092 Some(DataValue::String(ref s)) => {
1093 Ok(s.to_lowercase().starts_with(&prefix.to_lowercase()))
1094 }
1095 Some(DataValue::InternedString(ref s)) => {
1096 Ok(s.to_lowercase().starts_with(&prefix.to_lowercase()))
1097 }
1098 Some(DataValue::Integer(n)) => Ok(n.to_string().starts_with(&prefix)),
1099 Some(DataValue::Float(f)) => Ok(f.to_string().starts_with(&prefix)),
1100 Some(DataValue::Boolean(b)) => Ok(b.to_string().starts_with(&prefix)),
1101 Some(DataValue::DateTime(dt)) => Ok(dt.starts_with(&prefix)),
1102 _ => Ok(false),
1103 }
1104 }
1105 "endswith" => {
1106 if args.len() != 1 {
1107 return Err(anyhow::anyhow!("EndsWith requires exactly 1 argument"));
1108 }
1109 let suffix = self.extract_string_value(&args[0])?;
1110
1111 match cell_value {
1113 Some(DataValue::String(ref s)) => {
1114 Ok(s.to_lowercase().ends_with(&suffix.to_lowercase()))
1115 }
1116 Some(DataValue::InternedString(ref s)) => {
1117 Ok(s.to_lowercase().ends_with(&suffix.to_lowercase()))
1118 }
1119 Some(DataValue::Integer(n)) => Ok(n.to_string().ends_with(&suffix)),
1120 Some(DataValue::Float(f)) => Ok(f.to_string().ends_with(&suffix)),
1121 Some(DataValue::Boolean(b)) => Ok(b.to_string().ends_with(&suffix)),
1122 Some(DataValue::DateTime(dt)) => Ok(dt.ends_with(&suffix)),
1123 _ => Ok(false),
1124 }
1125 }
1126 _ => Err(anyhow::anyhow!("Unsupported method: {}", method)),
1127 }
1128 }
1129
1130 fn extract_column_name(&self, expr: &SqlExpression) -> Result<String> {
1131 match expr {
1132 SqlExpression::Column(name) => Ok(name.clone()),
1133 _ => Err(anyhow::anyhow!("Expected column name, got: {:?}", expr)),
1134 }
1135 }
1136
1137 fn extract_string_value(&self, expr: &SqlExpression) -> Result<String> {
1138 match expr {
1139 SqlExpression::StringLiteral(s) => Ok(s.clone()),
1140 _ => Err(anyhow::anyhow!("Expected string literal, got: {:?}", expr)),
1141 }
1142 }
1143
1144 fn extract_value(&self, expr: &SqlExpression) -> Result<ExprValue> {
1145 match expr {
1146 SqlExpression::StringLiteral(s) => Ok(ExprValue::String(s.clone())),
1147 SqlExpression::NumberLiteral(n) => {
1148 if let Ok(num) = n.parse::<f64>() {
1149 Ok(ExprValue::Number(num))
1150 } else {
1151 Ok(ExprValue::String(n.clone()))
1152 }
1153 }
1154 SqlExpression::DateTimeConstructor {
1155 year,
1156 month,
1157 day,
1158 hour,
1159 minute,
1160 second,
1161 } => {
1162 let naive_date = NaiveDate::from_ymd_opt(*year, *month, *day)
1164 .ok_or_else(|| anyhow::anyhow!("Invalid date: {}-{}-{}", year, month, day))?;
1165 let naive_time = NaiveTime::from_hms_opt(
1166 hour.unwrap_or(0),
1167 minute.unwrap_or(0),
1168 second.unwrap_or(0),
1169 )
1170 .ok_or_else(|| anyhow::anyhow!("Invalid time"))?;
1171 let naive_datetime = NaiveDateTime::new(naive_date, naive_time);
1172 let datetime = Utc.from_utc_datetime(&naive_datetime);
1173 Ok(ExprValue::DateTime(datetime))
1174 }
1175 SqlExpression::DateTimeToday {
1176 hour,
1177 minute,
1178 second,
1179 } => {
1180 let today = Local::now().date_naive();
1182 let time = NaiveTime::from_hms_opt(
1183 hour.unwrap_or(0),
1184 minute.unwrap_or(0),
1185 second.unwrap_or(0),
1186 )
1187 .ok_or_else(|| anyhow::anyhow!("Invalid time"))?;
1188 let naive_datetime = NaiveDateTime::new(today, time);
1189 let datetime = Utc.from_utc_datetime(&naive_datetime);
1190 Ok(ExprValue::DateTime(datetime))
1191 }
1192 _ => Ok(ExprValue::Null),
1193 }
1194 }
1195
1196 fn evaluate_case_expression_as_bool(
1198 &self,
1199 when_branches: &[crate::sql::recursive_parser::WhenBranch],
1200 else_branch: &Option<Box<SqlExpression>>,
1201 row_index: usize,
1202 ) -> Result<bool> {
1203 debug!(
1204 "RecursiveWhereEvaluator: evaluating CASE expression as bool for row {}",
1205 row_index
1206 );
1207
1208 for branch in when_branches {
1210 let condition_result = self.evaluate_expression(&branch.condition, row_index)?;
1212
1213 if condition_result {
1214 debug!("CASE: WHEN condition matched, evaluating result expression as bool");
1215 return self.evaluate_expression_as_bool(&branch.result, row_index);
1217 }
1218 }
1219
1220 match else_branch {
1222 Some(else_expr) => {
1223 debug!("CASE: No WHEN matched, evaluating ELSE expression as bool");
1224 self.evaluate_expression_as_bool(else_expr, row_index)
1225 }
1226 None => {
1227 debug!("CASE: No WHEN matched and no ELSE, returning false");
1228 Ok(false)
1229 }
1230 }
1231 }
1232
1233 fn evaluate_expression_as_bool(&self, expr: &SqlExpression, row_index: usize) -> Result<bool> {
1235 match expr {
1236 SqlExpression::BinaryOp { .. }
1238 | SqlExpression::InList { .. }
1239 | SqlExpression::NotInList { .. }
1240 | SqlExpression::Between { .. }
1241 | SqlExpression::Not { .. }
1242 | SqlExpression::MethodCall { .. } => self.evaluate_expression(expr, row_index),
1243 SqlExpression::CaseExpression {
1245 when_branches,
1246 else_branch,
1247 } => self.evaluate_case_expression_as_bool(when_branches, else_branch, row_index),
1248 _ => {
1250 let evaluator =
1252 crate::data::arithmetic_evaluator::ArithmeticEvaluator::with_date_notation(
1253 self.table,
1254 self.date_notation.clone(),
1255 );
1256 let value = evaluator.evaluate(expr, row_index)?;
1257
1258 match value {
1259 crate::data::datatable::DataValue::Boolean(b) => Ok(b),
1260 crate::data::datatable::DataValue::Integer(i) => Ok(i != 0),
1261 crate::data::datatable::DataValue::Float(f) => Ok(f != 0.0),
1262 crate::data::datatable::DataValue::Null => Ok(false),
1263 crate::data::datatable::DataValue::String(s) => Ok(!s.is_empty()),
1264 crate::data::datatable::DataValue::InternedString(s) => Ok(!s.is_empty()),
1265 _ => Ok(true), }
1267 }
1268 }
1269 }
1270}
1271
1272enum ExprValue {
1273 String(String),
1274 Number(f64),
1275 DateTime(DateTime<Utc>),
1276 Null,
1277}