@@ -351,6 +351,7 @@ mod tests {
351351 use arrow:: datatypes:: Schema ;
352352 use arrow:: datatypes:: { DataType , Field } ;
353353 use datafusion_common:: { config:: ConfigOptions , TableReference , ToDFSchema } ;
354+ use datafusion_common:: { DataFusionError , Result } ;
354355 use datafusion_expr:: {
355356 builder:: LogicalTableSource , cast, col, lit, AggregateUDF , Expr , ScalarUDF ,
356357 TableSource , WindowUDF ,
@@ -1074,6 +1075,26 @@ mod tests {
10741075 create_physical_expr ( expr, & df_schema, schema, & execution_props) . unwrap ( )
10751076 }
10761077
1078+ // Note the values in the `String` column are:
1079+ // ❯ select * from './parquet-testing/data/data_index_bloom_encoding_stats.parquet';
1080+ // +-----------+
1081+ // | String |
1082+ // +-----------+
1083+ // | Hello |
1084+ // | This is |
1085+ // | a |
1086+ // | test |
1087+ // | How |
1088+ // | are you |
1089+ // | doing |
1090+ // | today |
1091+ // | the quick |
1092+ // | brown fox |
1093+ // | jumps |
1094+ // | over |
1095+ // | the lazy |
1096+ // | dog |
1097+ // +-----------+
10771098 #[ tokio:: test]
10781099 async fn test_row_group_bloom_filter_pruning_predicate_simple_expr ( ) {
10791100 // load parquet file
@@ -1082,7 +1103,7 @@ mod tests {
10821103 let path = format ! ( "{testdata}/{file_name}" ) ;
10831104 let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
10841105
1085- // generate pruning predicate
1106+ // generate pruning predicate `(String = "Hello_Not_exists")`
10861107 let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
10871108 let expr = col ( r#""String""# ) . eq ( lit ( "Hello_Not_Exists" ) ) ;
10881109 let expr = logical2physical ( & expr, & schema) ;
@@ -1109,7 +1130,7 @@ mod tests {
11091130 let path = format ! ( "{testdata}/{file_name}" ) ;
11101131 let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
11111132
1112- // generate pruning predicate
1133+ // generate pruning predicate `(String = "Hello_Not_exists" OR String = "Hello_Not_exists2")`
11131134 let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
11141135 let expr = lit ( "1" ) . eq ( lit ( "1" ) ) . and (
11151136 col ( r#""String""# )
@@ -1171,7 +1192,7 @@ mod tests {
11711192 let path = format ! ( "{testdata}/{file_name}" ) ;
11721193 let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
11731194
1174- // generate pruning predicate
1195+ // generate pruning predicate `(String = "Hello")`
11751196 let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
11761197 let expr = col ( r#""String""# ) . eq ( lit ( "Hello" ) ) ;
11771198 let expr = logical2physical ( & expr, & schema) ;
@@ -1190,6 +1211,94 @@ mod tests {
11901211 assert_eq ! ( pruned_row_groups, row_groups) ;
11911212 }
11921213
1214+ #[ tokio:: test]
1215+ async fn test_row_group_bloom_filter_pruning_predicate_with_exists_2_values ( ) {
1216+ // load parquet file
1217+ let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1218+ let file_name = "data_index_bloom_encoding_stats.parquet" ;
1219+ let path = format ! ( "{testdata}/{file_name}" ) ;
1220+ let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1221+
1222+ // generate pruning predicate `(String = "Hello") OR (String = "the quick")`
1223+ let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1224+ let expr = col ( r#""String""# )
1225+ . eq ( lit ( "Hello" ) )
1226+ . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) ) ;
1227+ let expr = logical2physical ( & expr, & schema) ;
1228+ let pruning_predicate =
1229+ PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1230+
1231+ let row_groups = vec ! [ 0 ] ;
1232+ let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1233+ file_name,
1234+ data,
1235+ & pruning_predicate,
1236+ & row_groups,
1237+ )
1238+ . await
1239+ . unwrap ( ) ;
1240+ assert_eq ! ( pruned_row_groups, row_groups) ;
1241+ }
1242+
1243+ #[ tokio:: test]
1244+ async fn test_row_group_bloom_filter_pruning_predicate_with_exists_3_values ( ) {
1245+ // load parquet file
1246+ let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1247+ let file_name = "data_index_bloom_encoding_stats.parquet" ;
1248+ let path = format ! ( "{testdata}/{file_name}" ) ;
1249+ let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1250+
1251+ // generate pruning predicate `(String = "Hello") OR (String = "the quick") OR (String = "are you")`
1252+ let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1253+ let expr = col ( r#""String""# )
1254+ . eq ( lit ( "Hello" ) )
1255+ . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) )
1256+ . or ( col ( r#""String""# ) . eq ( lit ( "are you" ) ) ) ;
1257+ let expr = logical2physical ( & expr, & schema) ;
1258+ let pruning_predicate =
1259+ PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1260+
1261+ let row_groups = vec ! [ 0 ] ;
1262+ let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1263+ file_name,
1264+ data,
1265+ & pruning_predicate,
1266+ & row_groups,
1267+ )
1268+ . await
1269+ . unwrap ( ) ;
1270+ assert_eq ! ( pruned_row_groups, row_groups) ;
1271+ }
1272+
1273+ #[ tokio:: test]
1274+ async fn test_row_group_bloom_filter_pruning_predicate_with_or_not_eq ( ) {
1275+ // load parquet file
1276+ let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1277+ let file_name = "data_index_bloom_encoding_stats.parquet" ;
1278+ let path = format ! ( "{testdata}/{file_name}" ) ;
1279+ let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1280+
1281+ // generate pruning predicate `(String = "foo") OR (String != "bar")`
1282+ let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1283+ let expr = col ( r#""String""# )
1284+ . not_eq ( lit ( "foo" ) )
1285+ . or ( col ( r#""String""# ) . not_eq ( lit ( "bar" ) ) ) ;
1286+ let expr = logical2physical ( & expr, & schema) ;
1287+ let pruning_predicate =
1288+ PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1289+
1290+ let row_groups = vec ! [ 0 ] ;
1291+ let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1292+ file_name,
1293+ data,
1294+ & pruning_predicate,
1295+ & row_groups,
1296+ )
1297+ . await
1298+ . unwrap ( ) ;
1299+ assert_eq ! ( pruned_row_groups, row_groups) ;
1300+ }
1301+
11931302 #[ tokio:: test]
11941303 async fn test_row_group_bloom_filter_pruning_predicate_without_bloom_filter ( ) {
11951304 // load parquet file
@@ -1198,7 +1307,7 @@ mod tests {
11981307 let path = format ! ( "{testdata}/{file_name}" ) ;
11991308 let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
12001309
1201- // generate pruning predicate
1310+ // generate pruning predicate on a column without a bloom filter
12021311 let schema = Schema :: new ( vec ! [ Field :: new( "string_col" , DataType :: Utf8 , false ) ] ) ;
12031312 let expr = col ( r#""string_col""# ) . eq ( lit ( "0" ) ) ;
12041313 let expr = logical2physical ( & expr, & schema) ;
0 commit comments