1use crate::error::{QueryError, Result};
4use crate::executor::scan::{ColumnData, RecordBatch};
5use crate::parser::ast::{BinaryOperator, Expr, Literal, UnaryOperator};
6use oxigdal_core::error::OxiGdalError;
7
8pub struct Filter {
10 pub predicate: Expr,
12}
13
14impl Filter {
15 pub fn new(predicate: Expr) -> Self {
17 Self { predicate }
18 }
19
20 pub fn execute(&self, batch: &RecordBatch) -> Result<RecordBatch> {
22 let mut selection = vec![false; batch.num_rows];
23
24 for (row_idx, sel) in selection.iter_mut().enumerate().take(batch.num_rows) {
26 let result = self.evaluate_expr(&self.predicate, batch, row_idx)?;
27 if let Value::Boolean(b) = result {
28 *sel = b;
29 } else {
30 return Err(QueryError::execution(
31 OxiGdalError::invalid_operation_builder(
32 "Filter predicate must evaluate to boolean type",
33 )
34 .with_operation("filter_evaluation")
35 .with_parameter("row_index", row_idx.to_string())
36 .with_parameter("actual_type", format!("{:?}", result))
37 .with_suggestion("Ensure WHERE clause uses comparison or boolean operators")
38 .build()
39 .to_string(),
40 ));
41 }
42 }
43
44 let mut filtered_columns = Vec::new();
46 for column in &batch.columns {
47 filtered_columns.push(self.filter_column(column, &selection));
48 }
49
50 let filtered_rows = selection.iter().filter(|&&b| b).count();
51
52 RecordBatch::new(batch.schema.clone(), filtered_columns, filtered_rows)
53 }
54
55 fn filter_column(&self, column: &ColumnData, selection: &[bool]) -> ColumnData {
57 match column {
58 ColumnData::Boolean(data) => {
59 let filtered: Vec<Option<bool>> = data
60 .iter()
61 .zip(selection)
62 .filter_map(|(v, &sel)| if sel { Some(*v) } else { None })
63 .collect();
64 ColumnData::Boolean(filtered)
65 }
66 ColumnData::Int32(data) => {
67 let filtered: Vec<Option<i32>> = data
68 .iter()
69 .zip(selection)
70 .filter_map(|(v, &sel)| if sel { Some(*v) } else { None })
71 .collect();
72 ColumnData::Int32(filtered)
73 }
74 ColumnData::Int64(data) => {
75 let filtered: Vec<Option<i64>> = data
76 .iter()
77 .zip(selection)
78 .filter_map(|(v, &sel)| if sel { Some(*v) } else { None })
79 .collect();
80 ColumnData::Int64(filtered)
81 }
82 ColumnData::Float32(data) => {
83 let filtered: Vec<Option<f32>> = data
84 .iter()
85 .zip(selection)
86 .filter_map(|(v, &sel)| if sel { Some(*v) } else { None })
87 .collect();
88 ColumnData::Float32(filtered)
89 }
90 ColumnData::Float64(data) => {
91 let filtered: Vec<Option<f64>> = data
92 .iter()
93 .zip(selection)
94 .filter_map(|(v, &sel)| if sel { Some(*v) } else { None })
95 .collect();
96 ColumnData::Float64(filtered)
97 }
98 ColumnData::String(data) => {
99 let filtered: Vec<Option<String>> = data
100 .iter()
101 .zip(selection)
102 .filter_map(|(v, &sel)| if sel { Some(v.clone()) } else { None })
103 .collect();
104 ColumnData::String(filtered)
105 }
106 ColumnData::Binary(data) => {
107 let filtered = data
108 .iter()
109 .zip(selection)
110 .filter_map(|(v, &sel)| if sel { Some(v.clone()) } else { None })
111 .collect();
112 ColumnData::Binary(filtered)
113 }
114 }
115 }
116
117 pub(crate) fn evaluate_expr(
119 &self,
120 expr: &Expr,
121 batch: &RecordBatch,
122 row_idx: usize,
123 ) -> Result<Value> {
124 match expr {
125 Expr::Column { table: _, name } => {
126 let column = batch
127 .column_by_name(name)
128 .ok_or_else(|| QueryError::ColumnNotFound(name.clone()))?;
129 self.get_column_value(column, row_idx)
130 }
131 Expr::Literal(lit) => Ok(Value::from_literal(lit)),
132 Expr::BinaryOp { left, op, right } => {
133 let left_val = self.evaluate_expr(left, batch, row_idx)?;
134 let right_val = self.evaluate_expr(right, batch, row_idx)?;
135 self.evaluate_binary_op(&left_val, *op, &right_val)
136 }
137 Expr::UnaryOp { op, expr } => {
138 let val = self.evaluate_expr(expr, batch, row_idx)?;
139 self.evaluate_unary_op(*op, &val)
140 }
141 Expr::IsNull(expr) => {
142 let val = self.evaluate_expr(expr, batch, row_idx)?;
143 Ok(Value::Boolean(matches!(val, Value::Null)))
144 }
145 Expr::IsNotNull(expr) => {
146 let val = self.evaluate_expr(expr, batch, row_idx)?;
147 Ok(Value::Boolean(!matches!(val, Value::Null)))
148 }
149 Expr::Function { name, args } => {
150 let arg_values: Vec<Value> = args
152 .iter()
153 .map(|a| self.evaluate_expr(a, batch, row_idx))
154 .collect::<Result<Vec<_>>>()?;
155 crate::executor::spatial_funcs::evaluate_spatial_function(name, &arg_values, 2)
158 }
159 _ => Err(QueryError::unsupported(
160 OxiGdalError::not_supported_builder("Unsupported expression type in filter")
161 .with_operation("filter_evaluation")
162 .with_parameter("expression_type", format!("{:?}", expr))
163 .with_suggestion(
164 "Use simpler expressions: columns, literals, binary/unary operators, IS [NOT] NULL",
165 )
166 .build()
167 .to_string(),
168 )),
169 }
170 }
171
172 fn get_column_value(&self, column: &ColumnData, row_idx: usize) -> Result<Value> {
174 match column {
175 ColumnData::Boolean(data) => Ok(data
176 .get(row_idx)
177 .and_then(|v| v.as_ref())
178 .map(|&v| Value::Boolean(v))
179 .unwrap_or(Value::Null)),
180 ColumnData::Int32(data) => Ok(data
181 .get(row_idx)
182 .and_then(|v| v.as_ref())
183 .map(|&v| Value::Int32(v))
184 .unwrap_or(Value::Null)),
185 ColumnData::Int64(data) => Ok(data
186 .get(row_idx)
187 .and_then(|v| v.as_ref())
188 .map(|&v| Value::Int64(v))
189 .unwrap_or(Value::Null)),
190 ColumnData::Float32(data) => Ok(data
191 .get(row_idx)
192 .and_then(|v| v.as_ref())
193 .map(|&v| Value::Float32(v))
194 .unwrap_or(Value::Null)),
195 ColumnData::Float64(data) => Ok(data
196 .get(row_idx)
197 .and_then(|v| v.as_ref())
198 .map(|&v| Value::Float64(v))
199 .unwrap_or(Value::Null)),
200 ColumnData::String(data) => Ok(data
201 .get(row_idx)
202 .and_then(|v| v.as_ref())
203 .map(|v| Value::String(v.clone()))
204 .unwrap_or(Value::Null)),
205 ColumnData::Binary(_) => Err(QueryError::unsupported(
206 OxiGdalError::not_supported_builder(
207 "Binary column type not supported in filter predicates",
208 )
209 .with_operation("column_value_extraction")
210 .with_parameter("row_index", row_idx.to_string())
211 .with_suggestion(
212 "Cast binary columns to supported types or filter at a different stage",
213 )
214 .build()
215 .to_string(),
216 )),
217 }
218 }
219
220 fn evaluate_binary_op(&self, left: &Value, op: BinaryOperator, right: &Value) -> Result<Value> {
222 match (left, right) {
223 (Value::Null, _) | (_, Value::Null) => Ok(Value::Null),
224 (Value::Int32(l), Value::Int64(r)) => {
226 self.evaluate_binary_op(&Value::Int64(*l as i64), op, &Value::Int64(*r))
227 }
228 (Value::Int64(l), Value::Int32(r)) => {
229 self.evaluate_binary_op(&Value::Int64(*l), op, &Value::Int64(*r as i64))
230 }
231 (Value::Int32(l), Value::Int32(r)) => match op {
232 BinaryOperator::Plus => {
236 Ok(l.checked_add(*r).map(Value::Int32).unwrap_or(Value::Null))
237 }
238 BinaryOperator::Minus => {
239 Ok(l.checked_sub(*r).map(Value::Int32).unwrap_or(Value::Null))
240 }
241 BinaryOperator::Multiply => {
242 Ok(l.checked_mul(*r).map(Value::Int32).unwrap_or(Value::Null))
243 }
244 BinaryOperator::Divide => {
245 if *r == 0 {
246 Ok(Value::Null)
247 } else {
248 Ok(Value::Int32(l / r))
249 }
250 }
251 BinaryOperator::Modulo => {
252 if *r == 0 {
253 Ok(Value::Null)
254 } else {
255 Ok(Value::Int32(l % r))
256 }
257 }
258 BinaryOperator::Eq => Ok(Value::Boolean(l == r)),
259 BinaryOperator::NotEq => Ok(Value::Boolean(l != r)),
260 BinaryOperator::Lt => Ok(Value::Boolean(l < r)),
261 BinaryOperator::LtEq => Ok(Value::Boolean(l <= r)),
262 BinaryOperator::Gt => Ok(Value::Boolean(l > r)),
263 BinaryOperator::GtEq => Ok(Value::Boolean(l >= r)),
264 _ => Err(QueryError::unsupported("Unsupported operator for integers")),
265 },
266 (Value::Int64(l), Value::Int64(r)) => match op {
267 BinaryOperator::Plus => {
270 Ok(l.checked_add(*r).map(Value::Int64).unwrap_or(Value::Null))
271 }
272 BinaryOperator::Minus => {
273 Ok(l.checked_sub(*r).map(Value::Int64).unwrap_or(Value::Null))
274 }
275 BinaryOperator::Multiply => {
276 Ok(l.checked_mul(*r).map(Value::Int64).unwrap_or(Value::Null))
277 }
278 BinaryOperator::Divide => {
279 if *r == 0 {
280 Ok(Value::Null)
281 } else {
282 Ok(Value::Int64(l / r))
283 }
284 }
285 BinaryOperator::Modulo => {
286 if *r == 0 {
287 Ok(Value::Null)
288 } else {
289 Ok(Value::Int64(l % r))
290 }
291 }
292 BinaryOperator::Eq => Ok(Value::Boolean(l == r)),
293 BinaryOperator::NotEq => Ok(Value::Boolean(l != r)),
294 BinaryOperator::Lt => Ok(Value::Boolean(l < r)),
295 BinaryOperator::LtEq => Ok(Value::Boolean(l <= r)),
296 BinaryOperator::Gt => Ok(Value::Boolean(l > r)),
297 BinaryOperator::GtEq => Ok(Value::Boolean(l >= r)),
298 _ => Err(QueryError::unsupported("Unsupported operator for integers")),
299 },
300 (Value::Float32(l), Value::Float64(r)) => {
302 self.evaluate_binary_op(&Value::Float64(*l as f64), op, &Value::Float64(*r))
303 }
304 (Value::Float64(l), Value::Float32(r)) => {
305 self.evaluate_binary_op(&Value::Float64(*l), op, &Value::Float64(*r as f64))
306 }
307 (Value::Float32(l), Value::Float32(r)) => match op {
308 BinaryOperator::Plus => Ok(Value::Float32(l + r)),
309 BinaryOperator::Minus => Ok(Value::Float32(l - r)),
310 BinaryOperator::Multiply => Ok(Value::Float32(l * r)),
311 BinaryOperator::Divide => Ok(Value::Float32(l / r)),
312 BinaryOperator::Eq => Ok(Value::Boolean((l - r).abs() < f32::EPSILON)),
313 BinaryOperator::NotEq => Ok(Value::Boolean((l - r).abs() >= f32::EPSILON)),
314 BinaryOperator::Lt => Ok(Value::Boolean(l < r)),
315 BinaryOperator::LtEq => Ok(Value::Boolean(l <= r)),
316 BinaryOperator::Gt => Ok(Value::Boolean(l > r)),
317 BinaryOperator::GtEq => Ok(Value::Boolean(l >= r)),
318 _ => Err(QueryError::unsupported("Unsupported operator for floats")),
319 },
320 (Value::Float64(l), Value::Float64(r)) => match op {
321 BinaryOperator::Plus => Ok(Value::Float64(l + r)),
322 BinaryOperator::Minus => Ok(Value::Float64(l - r)),
323 BinaryOperator::Multiply => Ok(Value::Float64(l * r)),
324 BinaryOperator::Divide => Ok(Value::Float64(l / r)),
325 BinaryOperator::Eq => Ok(Value::Boolean((l - r).abs() < f64::EPSILON)),
326 BinaryOperator::NotEq => Ok(Value::Boolean((l - r).abs() >= f64::EPSILON)),
327 BinaryOperator::Lt => Ok(Value::Boolean(l < r)),
328 BinaryOperator::LtEq => Ok(Value::Boolean(l <= r)),
329 BinaryOperator::Gt => Ok(Value::Boolean(l > r)),
330 BinaryOperator::GtEq => Ok(Value::Boolean(l >= r)),
331 _ => Err(QueryError::unsupported("Unsupported operator for floats")),
332 },
333 (Value::Int32(l), Value::Float64(r)) => {
335 self.evaluate_binary_op(&Value::Float64(*l as f64), op, &Value::Float64(*r))
336 }
337 (Value::Int64(l), Value::Float64(r)) => {
338 self.evaluate_binary_op(&Value::Float64(*l as f64), op, &Value::Float64(*r))
339 }
340 (Value::Float64(l), Value::Int32(r)) => {
341 self.evaluate_binary_op(&Value::Float64(*l), op, &Value::Float64(*r as f64))
342 }
343 (Value::Float64(l), Value::Int64(r)) => {
344 self.evaluate_binary_op(&Value::Float64(*l), op, &Value::Float64(*r as f64))
345 }
346 (Value::Boolean(l), Value::Boolean(r)) => match op {
347 BinaryOperator::And => Ok(Value::Boolean(*l && *r)),
348 BinaryOperator::Or => Ok(Value::Boolean(*l || *r)),
349 BinaryOperator::Eq => Ok(Value::Boolean(l == r)),
350 BinaryOperator::NotEq => Ok(Value::Boolean(l != r)),
351 _ => Err(QueryError::unsupported("Unsupported operator for booleans")),
352 },
353 (Value::String(l), Value::String(r)) => match op {
354 BinaryOperator::Eq => Ok(Value::Boolean(l == r)),
355 BinaryOperator::NotEq => Ok(Value::Boolean(l != r)),
356 BinaryOperator::Concat => Ok(Value::String(format!("{}{}", l, r))),
357 BinaryOperator::Lt => Ok(Value::Boolean(l < r)),
359 BinaryOperator::LtEq => Ok(Value::Boolean(l <= r)),
360 BinaryOperator::Gt => Ok(Value::Boolean(l > r)),
361 BinaryOperator::GtEq => Ok(Value::Boolean(l >= r)),
362 BinaryOperator::Like => Ok(Value::Boolean(crate::executor::like::like_match(
364 l, r, false,
365 ))),
366 BinaryOperator::NotLike => Ok(Value::Boolean(!crate::executor::like::like_match(
367 l, r, false,
368 ))),
369 BinaryOperator::ILike => Ok(Value::Boolean(crate::executor::like::like_match(
370 l, r, true,
371 ))),
372 BinaryOperator::NotILike => Ok(Value::Boolean(!crate::executor::like::like_match(
373 l, r, true,
374 ))),
375 _ => Err(QueryError::unsupported("Unsupported operator for strings")),
376 },
377 _ => Err(QueryError::execution(
378 OxiGdalError::invalid_operation_builder("Type mismatch in binary operation")
379 .with_operation("binary_operator_evaluation")
380 .with_parameter("left_type", format!("{:?}", left))
381 .with_parameter("right_type", format!("{:?}", right))
382 .with_parameter("operator", format!("{:?}", op))
383 .with_suggestion(
384 "Ensure both operands have compatible types or use explicit type casts",
385 )
386 .build()
387 .to_string(),
388 )),
389 }
390 }
391
392 fn evaluate_unary_op(&self, op: UnaryOperator, val: &Value) -> Result<Value> {
394 match (op, val) {
395 (UnaryOperator::Minus, Value::Int64(i)) => Ok(Value::Int64(-i)),
396 (UnaryOperator::Minus, Value::Float64(f)) => Ok(Value::Float64(-f)),
397 (UnaryOperator::Not, Value::Boolean(b)) => Ok(Value::Boolean(!b)),
398 (_, Value::Null) => Ok(Value::Null),
399 _ => Err(QueryError::unsupported("Unsupported unary operation")),
400 }
401 }
402}
403
404pub(crate) fn evaluate_expr_for_row(
411 expr: &Expr,
412 batch: &RecordBatch,
413 row_idx: usize,
414) -> Result<Value> {
415 Filter::new(Expr::Wildcard).evaluate_expr(expr, batch, row_idx)
416}
417
418#[derive(Debug, Clone, PartialEq)]
420pub enum Value {
421 Null,
423 Boolean(bool),
425 Int32(i32),
427 Int64(i64),
429 Float32(f32),
431 Float64(f64),
433 String(String),
435 Geometry(geo::Geometry<f64>),
437}
438
439impl Value {
440 fn from_literal(lit: &Literal) -> Self {
442 match lit {
443 Literal::Null => Value::Null,
444 Literal::Boolean(b) => Value::Boolean(*b),
445 Literal::Integer(i) => Value::Int64(*i),
446 Literal::Float(f) => Value::Float64(*f),
447 Literal::String(s) => Value::String(s.clone()),
448 }
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
455 use crate::executor::scan::{Field, Schema};
456 use std::sync::Arc;
457
458 #[test]
459 fn test_filter_execution() -> Result<()> {
460 let schema = Arc::new(Schema::new(vec![
461 Field::new(
462 "id".to_string(),
463 crate::executor::scan::DataType::Int64,
464 false,
465 ),
466 Field::new(
467 "value".to_string(),
468 crate::executor::scan::DataType::Int64,
469 false,
470 ),
471 ]));
472
473 let columns = vec![
474 ColumnData::Int64(vec![Some(1), Some(2), Some(3), Some(4), Some(5)]),
475 ColumnData::Int64(vec![Some(10), Some(20), Some(30), Some(40), Some(50)]),
476 ];
477
478 let batch = RecordBatch::new(schema, columns, 5)?;
479
480 let predicate = Expr::BinaryOp {
482 left: Box::new(Expr::Column {
483 table: None,
484 name: "value".to_string(),
485 }),
486 op: BinaryOperator::Gt,
487 right: Box::new(Expr::Literal(Literal::Integer(25))),
488 };
489
490 let filter = Filter::new(predicate);
491 let filtered = filter.execute(&batch)?;
492
493 assert_eq!(filtered.num_rows, 3); Ok(())
496 }
497
498 fn string_batch() -> Result<RecordBatch> {
499 let schema = Arc::new(Schema::new(vec![Field::new(
500 "name".to_string(),
501 crate::executor::scan::DataType::String,
502 true,
503 )]));
504 let columns = vec![ColumnData::String(vec![
505 Some("Apple".to_string()),
506 Some("banana".to_string()),
507 Some("Cherry".to_string()),
508 Some("foobar".to_string()),
509 ])];
510 RecordBatch::new(schema, columns, 4)
511 }
512
513 fn name_col(expr_name: &str) -> Expr {
514 Expr::Column {
515 table: None,
516 name: expr_name.to_string(),
517 }
518 }
519
520 #[test]
521 fn test_where_like_case_sensitive() -> Result<()> {
522 let batch = string_batch()?;
523 let predicate = Expr::BinaryOp {
525 left: Box::new(name_col("name")),
526 op: BinaryOperator::Like,
527 right: Box::new(Expr::Literal(Literal::String("%oo%".to_string()))),
528 };
529 let filtered = Filter::new(predicate).execute(&batch)?;
530 assert_eq!(filtered.num_rows, 1);
531
532 let predicate = Expr::BinaryOp {
534 left: Box::new(name_col("name")),
535 op: BinaryOperator::Like,
536 right: Box::new(Expr::Literal(Literal::String("A%".to_string()))),
537 };
538 let filtered = Filter::new(predicate).execute(&batch)?;
539 assert_eq!(filtered.num_rows, 1); let predicate = Expr::BinaryOp {
542 left: Box::new(name_col("name")),
543 op: BinaryOperator::Like,
544 right: Box::new(Expr::Literal(Literal::String("a%".to_string()))),
545 };
546 let filtered = Filter::new(predicate).execute(&batch)?;
547 assert_eq!(filtered.num_rows, 0); Ok(())
549 }
550
551 #[test]
552 fn test_where_not_like() -> Result<()> {
553 let batch = string_batch()?;
554 let predicate = Expr::BinaryOp {
555 left: Box::new(name_col("name")),
556 op: BinaryOperator::NotLike,
557 right: Box::new(Expr::Literal(Literal::String("%oo%".to_string()))),
558 };
559 let filtered = Filter::new(predicate).execute(&batch)?;
560 assert_eq!(filtered.num_rows, 3); Ok(())
562 }
563
564 #[test]
565 fn test_where_ilike_case_insensitive() -> Result<()> {
566 let batch = string_batch()?;
567 let predicate = Expr::BinaryOp {
568 left: Box::new(name_col("name")),
569 op: BinaryOperator::ILike,
570 right: Box::new(Expr::Literal(Literal::String("a%".to_string()))),
571 };
572 let filtered = Filter::new(predicate).execute(&batch)?;
573 assert_eq!(filtered.num_rows, 1); Ok(())
575 }
576
577 #[test]
578 fn test_where_string_ordering() -> Result<()> {
579 let batch = string_batch()?;
580 let predicate = Expr::BinaryOp {
584 left: Box::new(name_col("name")),
585 op: BinaryOperator::Gt,
586 right: Box::new(Expr::Literal(Literal::String("C".to_string()))),
587 };
588 let filtered = Filter::new(predicate).execute(&batch)?;
589 assert_eq!(filtered.num_rows, 3);
590 Ok(())
591 }
592
593 #[test]
594 fn test_where_int_overflow_returns_null_not_panic() -> Result<()> {
595 let schema = Arc::new(Schema::new(vec![Field::new(
598 "v".to_string(),
599 crate::executor::scan::DataType::Int32,
600 false,
601 )]));
602 let columns = vec![ColumnData::Int32(vec![Some(i32::MAX), Some(1)])];
603 let batch = RecordBatch::new(schema, columns, 2)?;
604
605 let predicate = Expr::BinaryOp {
607 left: Box::new(Expr::BinaryOp {
608 left: Box::new(name_col("v")),
609 op: BinaryOperator::Plus,
610 right: Box::new(Expr::Literal(Literal::Integer(1))),
611 }),
612 op: BinaryOperator::Gt,
613 right: Box::new(Expr::Literal(Literal::Integer(0))),
614 };
615 let ovf = Filter::new(Expr::Wildcard).evaluate_binary_op(
618 &Value::Int32(i32::MAX),
619 BinaryOperator::Plus,
620 &Value::Int32(1),
621 )?;
622 assert_eq!(ovf, Value::Null);
623
624 let ovf64 = Filter::new(Expr::Wildcard).evaluate_binary_op(
625 &Value::Int64(i64::MAX),
626 BinaryOperator::Multiply,
627 &Value::Int64(2),
628 )?;
629 assert_eq!(ovf64, Value::Null);
630
631 let _ = Filter::new(predicate).execute(&batch)?;
633 Ok(())
634 }
635}