1use arrow::array::StringArray;
16use arrow::compute::kernels::comparison;
17use datafusion::common::ScalarValue;
18use datafusion::logical_expr::expr::Like;
19use datafusion::logical_expr::{Expr, Operator};
20use datatypes::value::Value;
21use store_api::storage::ScanRequest;
22
23type ColumnName = String;
24#[derive(Clone, PartialEq, Eq, Debug)]
28pub(crate) enum Predicate {
29 Eq(ColumnName, Value),
30 Like(ColumnName, String, bool),
31 NotEq(ColumnName, Value),
32 InList(ColumnName, Vec<Value>),
33 And(Box<Predicate>, Box<Predicate>),
34 Or(Box<Predicate>, Box<Predicate>),
35 Not(Box<Predicate>),
36}
37
38impl Predicate {
39 fn eval(&self, row: &[(&str, &Value)]) -> Option<bool> {
44 match self {
45 Predicate::Eq(c, v) => {
46 for (column, value) in row {
47 if c != column {
48 continue;
49 }
50 return Some(v == *value);
51 }
52 }
53 Predicate::Like(c, pattern, case_insensitive) => {
54 for (column, value) in row {
55 if c != column {
56 continue;
57 }
58
59 let Value::String(bs) = value else {
60 continue;
61 };
62
63 return like_utf8(bs.as_utf8(), pattern, case_insensitive);
64 }
65 }
66 Predicate::NotEq(c, v) => {
67 for (column, value) in row {
68 if c != column {
69 continue;
70 }
71 return Some(v != *value);
72 }
73 }
74 Predicate::InList(c, values) => {
75 for (column, value) in row {
76 if c != column {
77 continue;
78 }
79 return Some(values.iter().any(|v| v == *value));
80 }
81 }
82 Predicate::And(left, right) => {
83 let left = left.eval(row);
84
85 if matches!(left, Some(false)) {
87 return Some(false);
88 }
89
90 return match (left, right.eval(row)) {
91 (Some(left), Some(right)) => Some(left && right),
92 (None, Some(false)) => Some(false),
93 _ => None,
94 };
95 }
96 Predicate::Or(left, right) => {
97 let left = left.eval(row);
98
99 if matches!(left, Some(true)) {
101 return Some(true);
102 }
103
104 return match (left, right.eval(row)) {
105 (Some(left), Some(right)) => Some(left || right),
106 (None, Some(true)) => Some(true),
107 _ => None,
108 };
109 }
110 Predicate::Not(p) => {
111 return Some(!p.eval(row)?);
112 }
113 }
114
115 None
117 }
118
119 fn from_expr(expr: Expr) -> Option<Predicate> {
121 match expr {
122 Expr::Not(expr) => Some(Predicate::Not(Box::new(Self::from_expr(*expr)?))),
124 Expr::Like(Like {
126 negated,
127 expr,
128 pattern,
129 case_insensitive,
130 ..
131 }) if is_column(&expr) && is_string_literal(&pattern) => {
132 let Expr::Column(c) = *expr else {
134 unreachable!();
135 };
136 let Expr::Literal(ScalarValue::Utf8(Some(pattern)), _) = *pattern else {
137 unreachable!();
138 };
139
140 let p = Predicate::Like(c.name, pattern, case_insensitive);
141
142 if negated {
143 Some(Predicate::Not(Box::new(p)))
144 } else {
145 Some(p)
146 }
147 }
148 Expr::BinaryExpr(bin) => match (*bin.left, bin.op, *bin.right) {
150 (Expr::Literal(scalar, _), Operator::Eq, Expr::Column(c))
152 | (Expr::Column(c), Operator::Eq, Expr::Literal(scalar, _)) => {
153 let Ok(v) = Value::try_from(scalar) else {
154 return None;
155 };
156
157 Some(Predicate::Eq(c.name, v))
158 }
159 (Expr::Literal(scalar, _), Operator::NotEq, Expr::Column(c))
161 | (Expr::Column(c), Operator::NotEq, Expr::Literal(scalar, _)) => {
162 let Ok(v) = Value::try_from(scalar) else {
163 return None;
164 };
165
166 Some(Predicate::NotEq(c.name, v))
167 }
168 (left, Operator::And, right) => {
170 let left = Self::from_expr(left)?;
171 let right = Self::from_expr(right)?;
172
173 Some(Predicate::And(Box::new(left), Box::new(right)))
174 }
175 (left, Operator::Or, right) => {
177 let left = Self::from_expr(left)?;
178 let right = Self::from_expr(right)?;
179
180 Some(Predicate::Or(Box::new(left), Box::new(right)))
181 }
182 _ => None,
183 },
184 Expr::InList(list) => {
186 match (*list.expr, list.list, list.negated) {
187 (Expr::Column(c), list, negated) if is_all_scalars(&list) => {
189 let mut values = Vec::with_capacity(list.len());
190 for scalar in list {
191 let Expr::Literal(scalar, _) = scalar else {
193 unreachable!();
194 };
195
196 let Ok(value) = Value::try_from(scalar) else {
197 return None;
198 };
199
200 values.push(value);
201 }
202
203 let predicate = Predicate::InList(c.name, values);
204
205 if negated {
206 Some(Predicate::Not(Box::new(predicate)))
207 } else {
208 Some(predicate)
209 }
210 }
211 _ => None,
212 }
213 }
214 _ => None,
215 }
216 }
217
218 fn collect_eq_values<'a>(&'a self, column: &str, values: &mut Vec<&'a Value>) {
224 match self {
225 Predicate::Eq(c, v) if c == column => values.push(v),
226 Predicate::And(left, right) => {
227 left.collect_eq_values(column, values);
228 right.collect_eq_values(column, values);
229 }
230 _ => {}
231 }
232 }
233}
234
235fn like_utf8(s: &str, pattern: &str, case_insensitive: &bool) -> Option<bool> {
240 let array = StringArray::from(vec![s]);
241 let patterns = StringArray::new_scalar(pattern);
242
243 let Ok(booleans) = (if *case_insensitive {
244 comparison::ilike(&array, &patterns)
245 } else {
246 comparison::like(&array, &patterns)
247 }) else {
248 return None;
249 };
250
251 Some(booleans.value(0))
253}
254
255fn is_string_literal(expr: &Expr) -> bool {
256 matches!(expr, Expr::Literal(ScalarValue::Utf8(Some(_)), _))
257}
258
259fn is_column(expr: &Expr) -> bool {
260 matches!(expr, Expr::Column(_))
261}
262
263pub struct Predicates {
265 predicates: Vec<Predicate>,
266}
267
268impl Predicates {
269 pub fn from_scan_request(request: &Option<ScanRequest>) -> Predicates {
271 if let Some(request) = request {
272 let mut predicates = Vec::with_capacity(request.filters.len());
273
274 for filter in &request.filters {
275 if let Some(predicate) = Predicate::from_expr(filter.clone()) {
276 predicates.push(predicate);
277 }
278 }
279
280 Self { predicates }
281 } else {
282 Self {
283 predicates: Vec::new(),
284 }
285 }
286 }
287
288 pub fn find_eq_value(&self, column: &str) -> Option<&Value> {
294 let mut values = Vec::new();
295 for predicate in &self.predicates {
296 predicate.collect_eq_values(column, &mut values);
297 }
298
299 let (first, rest) = values.split_first()?;
300 if rest.iter().all(|v| v == first) {
301 Some(*first)
302 } else {
303 None
304 }
305 }
306
307 pub fn eval(&self, row: &[(&str, &Value)]) -> bool {
310 if self.predicates.is_empty() {
312 return true;
313 }
314
315 self.predicates
316 .iter()
317 .filter_map(|p| p.eval(row))
318 .all(|b| b)
319 }
320}
321
322fn is_all_scalars(list: &[Expr]) -> bool {
324 list.iter().all(|v| matches!(v, Expr::Literal(_, _)))
325}
326
327#[cfg(test)]
328mod tests {
329 use datafusion::common::Column;
330 use datafusion::logical_expr::expr::InList;
331 use datafusion::logical_expr::{BinaryExpr, Literal};
332
333 use super::*;
334
335 #[test]
336 fn test_predicate_eval() {
337 let a_col = "a".to_string();
338 let b_col = "b".to_string();
339 let a_value = Value::from("a_value");
340 let b_value = Value::from("b_value");
341 let wrong_value = Value::from("wrong_value");
342
343 let a_row = [(a_col.as_str(), &a_value)];
344 let b_row = [("b", &wrong_value)];
345 let wrong_row = [(a_col.as_str(), &wrong_value)];
346
347 let p = Predicate::Eq(a_col.clone(), a_value.clone());
349 assert!(p.eval(&a_row).unwrap());
350 assert!(p.eval(&b_row).is_none());
351 assert!(!p.eval(&wrong_row).unwrap());
352
353 let p = Predicate::NotEq(a_col.clone(), a_value.clone());
355 assert!(!p.eval(&a_row).unwrap());
356 assert!(p.eval(&b_row).is_none());
357 assert!(p.eval(&wrong_row).unwrap());
358
359 let p = Predicate::InList(a_col.clone(), vec![a_value.clone(), b_value.clone()]);
361 assert!(p.eval(&a_row).unwrap());
362 assert!(p.eval(&b_row).is_none());
363 assert!(!p.eval(&wrong_row).unwrap());
364 assert!(p.eval(&[(&a_col, &b_value)]).unwrap());
365
366 let p1 = Predicate::Eq(a_col.clone(), a_value.clone());
367 let p2 = Predicate::Eq(b_col.clone(), b_value.clone());
368 let row = [(a_col.as_str(), &a_value), (b_col.as_str(), &b_value)];
369 let wrong_row = [(a_col.as_str(), &a_value), (b_col.as_str(), &wrong_value)];
370
371 let p = Predicate::And(Box::new(p1.clone()), Box::new(p2.clone()));
373 assert!(p.eval(&row).unwrap());
374 assert!(!p.eval(&wrong_row).unwrap());
375 assert!(p.eval(&[]).is_none());
376 assert!(p.eval(&[("c", &a_value)]).is_none());
377 assert!(
378 !p.eval(&[(a_col.as_str(), &b_value), (b_col.as_str(), &a_value)])
379 .unwrap()
380 );
381 assert!(
382 !p.eval(&[(a_col.as_str(), &b_value), (b_col.as_str(), &b_value)])
383 .unwrap()
384 );
385 assert!(
386 p.eval(&[(a_col.as_ref(), &a_value), ("c", &a_value)])
387 .is_none()
388 );
389 assert!(
390 !p.eval(&[(a_col.as_ref(), &b_value), ("c", &a_value)])
391 .unwrap()
392 );
393
394 let p = Predicate::Or(Box::new(p1), Box::new(p2));
396 assert!(p.eval(&row).unwrap());
397 assert!(p.eval(&wrong_row).unwrap());
398 assert!(p.eval(&[]).is_none());
399 assert!(p.eval(&[("c", &a_value)]).is_none());
400 assert!(
401 !p.eval(&[(a_col.as_str(), &b_value), (b_col.as_str(), &a_value)])
402 .unwrap()
403 );
404 assert!(
405 p.eval(&[(a_col.as_str(), &b_value), (b_col.as_str(), &b_value)])
406 .unwrap()
407 );
408 assert!(
409 p.eval(&[(a_col.as_ref(), &a_value), ("c", &a_value)])
410 .unwrap()
411 );
412 assert!(
413 p.eval(&[(a_col.as_ref(), &b_value), ("c", &a_value)])
414 .is_none()
415 );
416 }
417
418 #[test]
419 fn test_predicate_like() {
420 let expr = Expr::Like(Like {
422 negated: false,
423 expr: Box::new(column("a")),
424 pattern: Box::new("%abc".lit()),
425 case_insensitive: true,
426 escape_char: None,
427 });
428
429 let p = Predicate::from_expr(expr).unwrap();
430 assert!(
431 matches!(&p, Predicate::Like(c, pattern, case_insensitive) if
432 c == "a"
433 && pattern == "%abc"
434 && *case_insensitive)
435 );
436
437 let match_row = [
438 ("a", &Value::from("hello AbC")),
439 ("b", &Value::from("b value")),
440 ];
441 let unmatch_row = [("a", &Value::from("bca")), ("b", &Value::from("b value"))];
442
443 assert!(p.eval(&match_row).unwrap());
444 assert!(!p.eval(&unmatch_row).unwrap());
445 assert!(p.eval(&[]).is_none());
446
447 let expr = Expr::Like(Like {
449 negated: false,
450 expr: Box::new(column("a")),
451 pattern: Box::new("%abc".lit()),
452 case_insensitive: false,
453 escape_char: None,
454 });
455
456 let p = Predicate::from_expr(expr).unwrap();
457 assert!(
458 matches!(&p, Predicate::Like(c, pattern, case_insensitive) if
459 c == "a"
460 && pattern == "%abc"
461 && !*case_insensitive)
462 );
463 assert!(!p.eval(&match_row).unwrap());
464 assert!(!p.eval(&unmatch_row).unwrap());
465 assert!(p.eval(&[]).is_none());
466
467 let expr = Expr::Like(Like {
469 negated: true,
470 expr: Box::new(column("a")),
471 pattern: Box::new("%abc".lit()),
472 case_insensitive: true,
473 escape_char: None,
474 });
475
476 let p = Predicate::from_expr(expr).unwrap();
477 assert!(!p.eval(&match_row).unwrap());
478 assert!(p.eval(&unmatch_row).unwrap());
479 assert!(p.eval(&[]).is_none());
480 }
481
482 fn column(name: &str) -> Expr {
483 Expr::Column(Column::from_name(name))
484 }
485
486 fn match_string_value(v: &Value, expected: &str) -> bool {
487 matches!(v, Value::String(bs) if bs.as_utf8() == expected)
488 }
489
490 fn match_string_values(vs: &[Value], expected: &[&str]) -> bool {
491 assert_eq!(vs.len(), expected.len());
492
493 let mut result = true;
494 for (i, v) in vs.iter().enumerate() {
495 result = result && match_string_value(v, expected[i]);
496 }
497
498 result
499 }
500
501 fn mock_exprs() -> (Expr, Expr) {
502 let expr1 = Expr::BinaryExpr(BinaryExpr {
503 left: Box::new(column("a")),
504 op: Operator::Eq,
505 right: Box::new("a_value".lit()),
506 });
507
508 let expr2 = Expr::BinaryExpr(BinaryExpr {
509 left: Box::new(column("b")),
510 op: Operator::NotEq,
511 right: Box::new("b_value".lit()),
512 });
513
514 (expr1, expr2)
515 }
516
517 #[test]
518 fn test_predicate_from_expr() {
519 let (expr1, expr2) = mock_exprs();
520
521 let p1 = Predicate::from_expr(expr1.clone()).unwrap();
522 assert!(matches!(&p1, Predicate::Eq(column, v) if column == "a"
523 && match_string_value(v, "a_value")));
524
525 let p2 = Predicate::from_expr(expr2.clone()).unwrap();
526 assert!(matches!(&p2, Predicate::NotEq(column, v) if column == "b"
527 && match_string_value(v, "b_value")));
528
529 let and_expr = Expr::BinaryExpr(BinaryExpr {
530 left: Box::new(expr1.clone()),
531 op: Operator::And,
532 right: Box::new(expr2.clone()),
533 });
534 let or_expr = Expr::BinaryExpr(BinaryExpr {
535 left: Box::new(expr1.clone()),
536 op: Operator::Or,
537 right: Box::new(expr2.clone()),
538 });
539 let not_expr = Expr::Not(Box::new(expr1.clone()));
540
541 let and_p = Predicate::from_expr(and_expr).unwrap();
542 assert!(matches!(and_p, Predicate::And(left, right) if *left == p1 && *right == p2));
543 let or_p = Predicate::from_expr(or_expr).unwrap();
544 assert!(matches!(or_p, Predicate::Or(left, right) if *left == p1 && *right == p2));
545 let not_p = Predicate::from_expr(not_expr).unwrap();
546 assert!(matches!(not_p, Predicate::Not(p) if *p == p1));
547
548 let inlist_expr = Expr::InList(InList {
549 expr: Box::new(column("a")),
550 list: vec!["a1".lit(), "a2".lit()],
551 negated: false,
552 });
553
554 let inlist_p = Predicate::from_expr(inlist_expr).unwrap();
555 assert!(matches!(&inlist_p, Predicate::InList(c, values) if c == "a"
556 && match_string_values(values, &["a1", "a2"])));
557
558 let inlist_expr = Expr::InList(InList {
559 expr: Box::new(column("a")),
560 list: vec!["a1".lit(), "a2".lit()],
561 negated: true,
562 });
563 let inlist_p = Predicate::from_expr(inlist_expr).unwrap();
564 assert!(matches!(inlist_p, Predicate::Not(p) if
565 matches!(&*p,
566 Predicate::InList(c, values) if c == "a"
567 && match_string_values(values, &["a1", "a2"]))));
568 }
569
570 #[test]
571 fn test_predicates_from_scan_request() {
572 let predicates = Predicates::from_scan_request(&None);
573 assert!(predicates.predicates.is_empty());
574
575 let (expr1, expr2) = mock_exprs();
576
577 let request = ScanRequest {
578 filters: vec![expr1, expr2],
579 ..Default::default()
580 };
581 let predicates = Predicates::from_scan_request(&Some(request));
582
583 assert_eq!(2, predicates.predicates.len());
584 assert!(
585 matches!(&predicates.predicates[0], Predicate::Eq(column, v) if column == "a"
586 && match_string_value(v, "a_value"))
587 );
588 assert!(
589 matches!(&predicates.predicates[1], Predicate::NotEq(column, v) if column == "b"
590 && match_string_value(v, "b_value"))
591 );
592 }
593
594 #[test]
595 fn test_find_eq_value() {
596 fn eq(name: &str, value: &str) -> Predicate {
597 Predicate::Eq(name.to_string(), Value::from(value))
598 }
599
600 fn and(left: Predicate, right: Predicate) -> Predicate {
601 Predicate::And(Box::new(left), Box::new(right))
602 }
603
604 fn or(left: Predicate, right: Predicate) -> Predicate {
605 Predicate::Or(Box::new(left), Box::new(right))
606 }
607
608 fn predicates(predicates: Vec<Predicate>) -> Predicates {
609 Predicates { predicates }
610 }
611
612 assert!(predicates(vec![]).find_eq_value("a").is_none());
614
615 let p = predicates(vec![Predicate::NotEq("a".to_string(), Value::from("x"))]);
617 assert!(p.find_eq_value("a").is_none());
618 assert!(p.find_eq_value("b").is_none());
619
620 let p = predicates(vec![eq("a", "x")]);
622 let v = p.find_eq_value("a").unwrap();
623 assert!(match_string_value(v, "x"));
624 assert!(p.find_eq_value("b").is_none());
625
626 let p = predicates(vec![and(eq("a", "x"), eq("a", "x"))]);
628 let v = p.find_eq_value("a").unwrap();
629 assert!(match_string_value(v, "x"));
630
631 let p = predicates(vec![and(eq("a", "x"), eq("a", "y"))]);
633 assert!(p.find_eq_value("a").is_none());
634
635 let p = predicates(vec![eq("a", "x"), eq("a", "y")]);
637 assert!(p.find_eq_value("a").is_none());
638
639 let p = predicates(vec![and(and(eq("b", "y"), eq("a", "x")), eq("a", "x"))]);
641 let v = p.find_eq_value("a").unwrap();
642 assert!(match_string_value(v, "x"));
643
644 let p = predicates(vec![or(eq("a", "x"), eq("a", "x"))]);
646 assert!(p.find_eq_value("a").is_none());
647 let p = predicates(vec![Predicate::Not(Box::new(eq("a", "x")))]);
648 assert!(p.find_eq_value("a").is_none());
649
650 let p = predicates(vec![
652 eq("a", "x"),
653 Predicate::Like("b".to_string(), "%y".to_string(), false),
654 ]);
655 let v = p.find_eq_value("a").unwrap();
656 assert!(match_string_value(v, "x"));
657 }
658
659 #[test]
660 fn test_predicates_eval_row() {
661 let wrong_row = [
662 ("a", &Value::from("a_value")),
663 ("b", &Value::from("b_value")),
664 ("c", &Value::from("c_value")),
665 ];
666 let row = [
667 ("a", &Value::from("a_value")),
668 ("b", &Value::from("not_b_value")),
669 ("c", &Value::from("c_value")),
670 ];
671 let c_row = [("c", &Value::from("c_value"))];
672
673 let predicates = Predicates::from_scan_request(&None);
675 assert!(predicates.eval(&row));
676 assert!(predicates.eval(&wrong_row));
677 assert!(predicates.eval(&c_row));
678
679 let (expr1, expr2) = mock_exprs();
680 let request = ScanRequest {
681 filters: vec![expr1, expr2],
682 ..Default::default()
683 };
684 let predicates = Predicates::from_scan_request(&Some(request));
685 assert!(predicates.eval(&row));
686 assert!(!predicates.eval(&wrong_row));
687 assert!(predicates.eval(&c_row));
688 }
689}