@@ -751,6 +751,13 @@ fn is_always_true(expr: &Arc<dyn PhysicalExpr>) -> bool {
751
751
. unwrap_or_default ( )
752
752
}
753
753
754
+ fn is_always_false ( expr : & Arc < dyn PhysicalExpr > ) -> bool {
755
+ expr. as_any ( )
756
+ . downcast_ref :: < phys_expr:: Literal > ( )
757
+ . map ( |l| matches ! ( l. value( ) , ScalarValue :: Boolean ( Some ( false ) ) ) )
758
+ . unwrap_or_default ( )
759
+ }
760
+
754
761
/// Describes which columns statistics are necessary to evaluate a
755
762
/// [`PruningPredicate`].
756
763
///
@@ -1439,6 +1446,11 @@ fn build_predicate_expression(
1439
1446
required_columns : & mut RequiredColumns ,
1440
1447
unhandled_hook : & Arc < dyn UnhandledPredicateHook > ,
1441
1448
) -> Arc < dyn PhysicalExpr > {
1449
+ if is_always_false ( expr) {
1450
+ // Shouldn't return `unhandled_hook.handle(expr)`
1451
+ // Because it will transfer false to true.
1452
+ return Arc :: clone ( expr) ;
1453
+ }
1442
1454
// predicate expression can only be a binary expression
1443
1455
let expr_any = expr. as_any ( ) ;
1444
1456
if let Some ( is_null) = expr_any. downcast_ref :: < phys_expr:: IsNullExpr > ( ) {
@@ -1538,13 +1550,21 @@ fn build_predicate_expression(
1538
1550
build_predicate_expression ( & right, schema, required_columns, unhandled_hook) ;
1539
1551
// simplify boolean expression if applicable
1540
1552
let expr = match ( & left_expr, op, & right_expr) {
1553
+ ( left, Operator :: And , right)
1554
+ if is_always_false ( left) || is_always_false ( right) =>
1555
+ {
1556
+ Arc :: new ( phys_expr:: Literal :: new ( ScalarValue :: Boolean ( Some ( false ) ) ) )
1557
+ }
1541
1558
( left, Operator :: And , _) if is_always_true ( left) => right_expr,
1542
1559
( _, Operator :: And , right) if is_always_true ( right) => left_expr,
1543
1560
( left, Operator :: Or , right)
1544
1561
if is_always_true ( left) || is_always_true ( right) =>
1545
1562
{
1546
1563
Arc :: new ( phys_expr:: Literal :: new ( ScalarValue :: Boolean ( Some ( true ) ) ) )
1547
1564
}
1565
+ ( left, Operator :: Or , _) if is_always_false ( left) => right_expr,
1566
+ ( _, Operator :: Or , right) if is_always_false ( right) => left_expr,
1567
+
1548
1568
_ => Arc :: new ( phys_expr:: BinaryExpr :: new ( left_expr, op, right_expr) ) ,
1549
1569
} ;
1550
1570
return expr;
@@ -1904,7 +1924,7 @@ mod tests {
1904
1924
1905
1925
use super :: * ;
1906
1926
use datafusion_common:: test_util:: batches_to_string;
1907
- use datafusion_expr:: { col, lit} ;
1927
+ use datafusion_expr:: { and , col, lit, or } ;
1908
1928
use insta:: assert_snapshot;
1909
1929
1910
1930
use arrow:: array:: Decimal128Array ;
@@ -3585,12 +3605,10 @@ mod tests {
3585
3605
3586
3606
prune_with_expr (
3587
3607
// false
3588
- // constant literals that do NOT refer to any columns are currently not evaluated at all, hence the result is
3589
- // "all true"
3590
3608
lit ( false ) ,
3591
3609
& schema,
3592
3610
& statistics,
3593
- & [ true , true , true , true , true ] ,
3611
+ & [ false , false , false , false , false ] ,
3594
3612
) ;
3595
3613
}
3596
3614
@@ -5171,4 +5189,42 @@ mod tests {
5171
5189
let unhandled_hook = Arc :: new ( ConstantUnhandledPredicateHook :: default ( ) ) as _ ;
5172
5190
build_predicate_expression ( & expr, schema, required_columns, & unhandled_hook)
5173
5191
}
5192
+
5193
+ #[ test]
5194
+ fn test_build_predicate_expression_with_false ( ) {
5195
+ let expr = lit ( ScalarValue :: Boolean ( Some ( false ) ) ) ;
5196
+ let schema = Schema :: empty ( ) ;
5197
+ let res =
5198
+ test_build_predicate_expression ( & expr, & schema, & mut RequiredColumns :: new ( ) ) ;
5199
+ let expected = logical2physical ( & expr, & schema) ;
5200
+ assert_eq ! ( & res, & expected) ;
5201
+ }
5202
+
5203
+ #[ test]
5204
+ fn test_build_predicate_expression_with_and_false ( ) {
5205
+ let schema = Schema :: new ( vec ! [ Field :: new( "c1" , DataType :: Utf8View , false ) ] ) ;
5206
+ let expr = and (
5207
+ col ( "c1" ) . eq ( lit ( "a" ) ) ,
5208
+ lit ( ScalarValue :: Boolean ( Some ( false ) ) ) ,
5209
+ ) ;
5210
+ let res =
5211
+ test_build_predicate_expression ( & expr, & schema, & mut RequiredColumns :: new ( ) ) ;
5212
+ let expected = logical2physical ( & lit ( ScalarValue :: Boolean ( Some ( false ) ) ) , & schema) ;
5213
+ assert_eq ! ( & res, & expected) ;
5214
+ }
5215
+
5216
+ #[ test]
5217
+ fn test_build_predicate_expression_with_or_false ( ) {
5218
+ let schema = Schema :: new ( vec ! [ Field :: new( "c1" , DataType :: Utf8View , false ) ] ) ;
5219
+ let left_expr = col ( "c1" ) . eq ( lit ( "a" ) ) ;
5220
+ let right_expr = lit ( ScalarValue :: Boolean ( Some ( false ) ) ) ;
5221
+ let res = test_build_predicate_expression (
5222
+ & or ( left_expr. clone ( ) , right_expr. clone ( ) ) ,
5223
+ & schema,
5224
+ & mut RequiredColumns :: new ( ) ,
5225
+ ) ;
5226
+ let expected =
5227
+ "c1_null_count@2 != row_count@3 AND c1_min@0 <= a AND a <= c1_max@1" ;
5228
+ assert_eq ! ( res. to_string( ) , expected) ;
5229
+ }
5174
5230
}
0 commit comments