| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "paimon/format/parquet/predicate_converter.h" |
| |
| #include <cstdint> |
| #include <utility> |
| |
| #include "arrow/compute/expression.h" |
| #include "gtest/gtest.h" |
| #include "paimon/data/decimal.h" |
| #include "paimon/data/timestamp.h" |
| #include "paimon/defs.h" |
| #include "paimon/predicate/literal.h" |
| #include "paimon/predicate/predicate_builder.h" |
| #include "paimon/testing/utils/testharness.h" |
| |
| namespace paimon::parquet::test { |
| |
| TEST(PredicateConverterTest, TestSimple) { |
| // "struct<f0:bigint,f1:double,f2:string,f3:int,f4:tinyint,f5:decimal(6,2),f6:date,f7:timestamp>"; |
| { |
| auto predicate = |
| PredicateBuilder::IsNull(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("is_null(f0, {nan_is_null=false})", expression.ToString()); |
| } |
| { |
| auto predicate = |
| PredicateBuilder::IsNotNull(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("invert(is_null(f0, {nan_is_null=false}))", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 == 5)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::INT, Literal(10)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f3 == 10)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::Equal(/*field_index=*/6, /*field_name=*/"f6", |
| FieldType::DATE, Literal(FieldType::DATE, 10)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f6 == 1970-01-11)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::NotEqual(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 != 5)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::GreaterThan(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 > 5)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::GreaterOrEqual(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 >= 5)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::GreaterOrEqual( |
| /*field_index=*/4, /*field_name=*/"f4", FieldType::TINYINT, |
| Literal(static_cast<int8_t>(16))); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f4 >= 16)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::LessThan(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 < 5)", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::LessOrEqual(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(5l)); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 <= 5)", expression.ToString()); |
| } |
| { |
| auto predicate = |
| PredicateBuilder::In(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT, |
| {Literal(1l), Literal(3l), Literal(5l)}); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(((f0 == 1) or (f0 == 3)) or (f0 == 5))", expression.ToString()); |
| } |
| { |
| auto predicate = |
| PredicateBuilder::NotIn(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT, |
| {Literal(1l), Literal(3l), Literal(5l)}); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(((f0 != 1) and (f0 != 3)) and (f0 != 5))", expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| const auto predicate, |
| PredicateBuilder::StartsWith(/*field_index=*/0, /*field_name=*/"f0", FieldType::STRING, |
| Literal(FieldType::STRING, "aab", 3))); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("starts_with(f0, {pattern=\"aab\", ignore_case=false})", expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| const auto predicate, |
| PredicateBuilder::EndsWith(/*field_index=*/0, /*field_name=*/"f0", FieldType::STRING, |
| Literal(FieldType::STRING, "bcc", 3))); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("ends_with(f0, {pattern=\"bcc\", ignore_case=false})", expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| const auto predicate, |
| PredicateBuilder::Contains(/*field_index=*/0, /*field_name=*/"f0", FieldType::STRING, |
| Literal(FieldType::STRING, "abc", 3))); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("match_substring(f0, {pattern=\"abc\", ignore_case=false})", |
| expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| const auto predicate, |
| PredicateBuilder::Like(/*field_index=*/0, /*field_name=*/"f0", FieldType::STRING, |
| Literal(FieldType::STRING, "abc", 3))); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("match_like(f0, {pattern=\"abc\", ignore_case=false})", expression.ToString()); |
| } |
| { |
| // support decimal precision and scale mismatches between literal and data |
| auto predicate = PredicateBuilder::In(/*field_index=*/7, /*field_name=*/"f7", |
| FieldType::DECIMAL, {Literal(Decimal(5, 1, 12345))}); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f7 == 1234.5)", expression.ToString()); |
| } |
| { |
| // do not support pushdown predicate with timestamp literal, will always return true |
| auto predicate = |
| PredicateBuilder::In(/*field_index=*/6, /*field_name=*/"f6", FieldType::TIMESTAMP, |
| {Literal(Timestamp(1000, 12345))}); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("true", expression.ToString()); |
| } |
| { |
| auto predicate = PredicateBuilder::LessOrEqual( |
| /*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT, Literal(FieldType::BIGINT)); |
| ASSERT_NOK_WITH_MSG( |
| PredicateConverter::Convert(predicate, /*predicate_node_count_limit=*/100), |
| "literal cannot be null in predicate"); |
| } |
| } |
| |
| TEST(PredicateConverterTest, TestJavaCompatibleSignedZeroExpressions) { |
| struct TestType { |
| FieldType field_type; |
| Literal negative_zero; |
| Literal positive_zero; |
| Literal one; |
| }; |
| const std::vector<TestType> test_types = { |
| {FieldType::FLOAT, Literal(-0.0f), Literal(0.0f), Literal(1.0f)}, |
| {FieldType::DOUBLE, Literal(-0.0), Literal(0.0), Literal(1.0)}}; |
| |
| for (const auto& test_type : test_types) { |
| auto equal_negative_zero = PredicateBuilder::Equal( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto equal_negative_zero_expr, |
| PredicateConverter::Convert(equal_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 == -0)", equal_negative_zero_expr.ToString()); |
| |
| auto equal_positive_zero = PredicateBuilder::Equal( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto equal_positive_zero_expr, |
| PredicateConverter::Convert(equal_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 == 0)", equal_positive_zero_expr.ToString()); |
| |
| auto greater_negative_zero = PredicateBuilder::GreaterThan( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto greater_negative_zero_expr, |
| PredicateConverter::Convert(greater_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 >= -0)", greater_negative_zero_expr.ToString()); |
| |
| auto less_positive_zero = PredicateBuilder::LessThan( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto less_positive_zero_expr, |
| PredicateConverter::Convert(less_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 <= 0)", less_positive_zero_expr.ToString()); |
| |
| auto not_equal_negative_zero = PredicateBuilder::NotEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto not_equal_negative_zero_expr, |
| PredicateConverter::Convert(not_equal_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("is_valid(f0)", not_equal_negative_zero_expr.ToString()); |
| |
| auto not_equal_positive_zero = PredicateBuilder::NotEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto not_equal_positive_zero_expr, |
| PredicateConverter::Convert(not_equal_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("is_valid(f0)", not_equal_positive_zero_expr.ToString()); |
| |
| auto greater_positive_zero = PredicateBuilder::GreaterThan( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto greater_positive_zero_expr, |
| PredicateConverter::Convert(greater_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 > 0)", greater_positive_zero_expr.ToString()); |
| |
| auto greater_or_equal_positive_zero = PredicateBuilder::GreaterOrEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto greater_or_equal_positive_zero_expr, |
| PredicateConverter::Convert(greater_or_equal_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 >= 0)", greater_or_equal_positive_zero_expr.ToString()); |
| |
| auto greater_or_equal_negative_zero = PredicateBuilder::GreaterOrEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto greater_or_equal_negative_zero_expr, |
| PredicateConverter::Convert(greater_or_equal_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 >= -0)", greater_or_equal_negative_zero_expr.ToString()); |
| |
| auto less_negative_zero = PredicateBuilder::LessThan( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto less_negative_zero_expr, |
| PredicateConverter::Convert(less_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 < -0)", less_negative_zero_expr.ToString()); |
| |
| auto less_or_equal_negative_zero = PredicateBuilder::LessOrEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.negative_zero); |
| ASSERT_OK_AND_ASSIGN(auto less_or_equal_negative_zero_expr, |
| PredicateConverter::Convert(less_or_equal_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 <= -0)", less_or_equal_negative_zero_expr.ToString()); |
| |
| auto less_or_equal_positive_zero = PredicateBuilder::LessOrEqual( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, test_type.positive_zero); |
| ASSERT_OK_AND_ASSIGN(auto less_or_equal_positive_zero_expr, |
| PredicateConverter::Convert(less_or_equal_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(f0 <= 0)", less_or_equal_positive_zero_expr.ToString()); |
| |
| auto in_negative_zero = PredicateBuilder::In( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, |
| {test_type.negative_zero, test_type.one}); |
| ASSERT_OK_AND_ASSIGN(auto in_negative_zero_expr, |
| PredicateConverter::Convert(in_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("((f0 == -0) or (f0 == 1))", in_negative_zero_expr.ToString()); |
| |
| auto in_positive_zero = PredicateBuilder::In( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, |
| {test_type.positive_zero, test_type.one}); |
| ASSERT_OK_AND_ASSIGN(auto in_positive_zero_expr, |
| PredicateConverter::Convert(in_positive_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("((f0 == 0) or (f0 == 1))", in_positive_zero_expr.ToString()); |
| |
| auto not_in_negative_zero = PredicateBuilder::NotIn( |
| /*field_index=*/0, /*field_name=*/"f0", test_type.field_type, |
| {test_type.negative_zero, test_type.one}); |
| ASSERT_OK_AND_ASSIGN(auto not_in_negative_zero_expr, |
| PredicateConverter::Convert(not_in_negative_zero, |
| /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(is_valid(f0) and (f0 != 1))", not_in_negative_zero_expr.ToString()); |
| } |
| } |
| |
| TEST(PredicateConverterTest, TestCompound) { |
| // "struct<f0:bigint,f1:float,f2:string,f3:boolean,f4:date,f5:timestamp,f6:decimal(6,2),f7:binary>"; |
| { |
| ASSERT_OK_AND_ASSIGN( |
| auto predicate, |
| PredicateBuilder::And({ |
| PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT, |
| Literal(3l)), |
| PredicateBuilder::Equal(/*field_index=*/1, /*field_name=*/"f1", FieldType::FLOAT, |
| Literal(static_cast<float>(5.0))), |
| PredicateBuilder::Equal(/*field_index=*/2, /*field_name=*/"f2", FieldType::STRING, |
| Literal(FieldType::STRING, "apple", 5)), |
| PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", FieldType::BOOLEAN, |
| Literal(true)), |
| PredicateBuilder::Equal(/*field_index=*/4, /*field_name=*/"f4", FieldType::DATE, |
| Literal(FieldType::DATE, 3)), |
| PredicateBuilder::Equal(/*field_index=*/5, /*field_name=*/"f5", |
| FieldType::TIMESTAMP, |
| Literal(Timestamp(1725875365442l, 12000))), |
| PredicateBuilder::Equal(/*field_index=*/6, /*field_name=*/"f6", FieldType::DECIMAL, |
| Literal(Decimal(6, 2, 123456))), |
| PredicateBuilder::Equal(/*field_index=*/7, /*field_name=*/"f7", FieldType::BINARY, |
| Literal(FieldType::BINARY, "add", 3)), |
| })); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ( |
| "((((((((f0 == 3) and (f1 == 5)) and (f2 == \"apple\")) and (f3 == true)) and (f4 == " |
| "1970-01-04)) and true) and (f6 == 1234.56)) and true)", |
| expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| auto predicate, |
| PredicateBuilder::Or({ |
| PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"f0", FieldType::BIGINT, |
| Literal(3l)), |
| PredicateBuilder::Equal(/*field_index=*/1, /*field_name=*/"f1", FieldType::FLOAT, |
| Literal(static_cast<float>(5.0))), |
| PredicateBuilder::Equal(/*field_index=*/2, /*field_name=*/"f2", FieldType::STRING, |
| Literal(FieldType::STRING, "apple", 5)), |
| PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", FieldType::BOOLEAN, |
| Literal(true)), |
| })); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("((((f0 == 3) or (f1 == 5)) or (f2 == \"apple\")) or (f3 == true))", |
| expression.ToString()); |
| } |
| { |
| ASSERT_OK_AND_ASSIGN( |
| auto predicate, |
| PredicateBuilder::Or( |
| {PredicateBuilder::And( |
| {PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::BOOLEAN, Literal(true)), |
| PredicateBuilder::LessThan(/*field_index=*/0, /*field_name=*/"f0", |
| FieldType::BIGINT, Literal(3l))}) |
| .value(), |
| PredicateBuilder::And( |
| {PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::BOOLEAN, Literal(false)), |
| PredicateBuilder::LessThan(/*field_index=*/1, /*field_name=*/"f1", |
| FieldType::FLOAT, |
| Literal(static_cast<float>(3.1)))}) |
| .value()})); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(((f3 == true) and (f0 < 3)) or ((f3 == false) and (f1 < 3.1)))", |
| expression.ToString()); |
| } |
| { |
| // predicate nodes containing binary type will not be pushed down |
| ASSERT_OK_AND_ASSIGN( |
| auto predicate, |
| PredicateBuilder::And( |
| {PredicateBuilder::Or( |
| {PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::BOOLEAN, Literal(true)), |
| PredicateBuilder::LessThan( |
| /*field_index=*/7, /*field_name=*/"f7", FieldType::BINARY, |
| Literal(FieldType::BINARY, "add", 3))}) |
| .value(), |
| PredicateBuilder::Or( |
| {PredicateBuilder::Equal(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::BOOLEAN, Literal(false)), |
| PredicateBuilder::LessThan(/*field_index=*/1, /*field_name=*/"f1", |
| FieldType::FLOAT, |
| Literal(static_cast<float>(3.1)))}) |
| .value()})); |
| ASSERT_OK_AND_ASSIGN(auto expression, PredicateConverter::Convert( |
| predicate, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("(((f3 == true) or true) and ((f3 == false) or (f1 < 3.1)))", |
| expression.ToString()); |
| } |
| } |
| |
| TEST(PredicateConverterTest, TestCollectNodeCount) { |
| // And([And([Equal(f0, 10), NotEqual(f1, 20)]), Or([GreaterThan(v0, 30), LessThan(f3, 20)]), |
| // Or([LessOrEqual(f2, 50), In(f0, [20, 60]), In(f0, [120, 160])]), GreaterOrEqual(v1, 120)]) |
| auto equal = PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"f0", FieldType::INT, |
| Literal(10)); |
| auto not_equal = PredicateBuilder::NotEqual(/*field_index=*/1, /*field_name=*/"f1", |
| FieldType::INT, Literal(20)); |
| // and_predicate has 3 nodes |
| ASSERT_OK_AND_ASSIGN(auto and_predicate, PredicateBuilder::And({equal, not_equal})); |
| uint32_t node_count = 0; |
| PredicateConverter::CollectNodeCount(and_predicate, &node_count); |
| ASSERT_EQ(node_count, 3); |
| |
| auto greater_than = PredicateBuilder::GreaterThan(/*field_index=*/2, /*field_name=*/"v0", |
| FieldType::INT, Literal(30)); |
| auto less_than = PredicateBuilder::LessThan(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::INT, Literal(20)); |
| // or_predicate has 3 nodes |
| ASSERT_OK_AND_ASSIGN(auto or_predicate, PredicateBuilder::Or({greater_than, less_than})); |
| node_count = 0; |
| PredicateConverter::CollectNodeCount(or_predicate, &node_count); |
| ASSERT_EQ(node_count, 3); |
| |
| auto less_or_equal = PredicateBuilder::LessOrEqual(/*field_index=*/4, /*field_name=*/"f2", |
| FieldType::INT, Literal(50)); |
| auto in = PredicateBuilder::In(/*field_index=*/5, /*field_name=*/"f0", FieldType::INT, |
| {Literal(20), Literal(60)}); |
| auto not_in = PredicateBuilder::NotIn(/*field_index=*/5, /*field_name=*/"f0", FieldType::INT, |
| {Literal(120), Literal(160)}); |
| // or_predicate2 has 8 nodes |
| ASSERT_OK_AND_ASSIGN(auto or_predicate2, PredicateBuilder::Or({less_or_equal, in, not_in})); |
| node_count = 0; |
| PredicateConverter::CollectNodeCount(or_predicate2, &node_count); |
| ASSERT_EQ(node_count, 8); |
| |
| auto greater_or_equal = PredicateBuilder::GreaterOrEqual(/*field_index=*/4, /*field_name=*/"v1", |
| FieldType::INT, Literal(120)); |
| node_count = 0; |
| PredicateConverter::CollectNodeCount(greater_or_equal, &node_count); |
| ASSERT_EQ(node_count, 1); |
| |
| // predicate has (1+3+3+8+1) nodes |
| ASSERT_OK_AND_ASSIGN(auto predicate, PredicateBuilder::And({and_predicate, or_predicate, |
| or_predicate2, greater_or_equal})); |
| node_count = 0; |
| PredicateConverter::CollectNodeCount(predicate, &node_count); |
| ASSERT_EQ(node_count, 16); |
| } |
| |
| TEST(PredicateConverterTest, TestExceedNodeCountLimit) { |
| // And([And([Equal(f0, 10), NotEqual(f1, 20)]), Or([GreaterThan(v0, 30), LessThan(f3, 20)]), |
| // Or([LessOrEqual(f2, 50), In(f0, [20, 60]), In(f0, [120, 160])]), GreaterOrEqual(v1, 120)]) |
| auto equal = PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"f0", FieldType::INT, |
| Literal(10)); |
| auto not_equal = PredicateBuilder::NotEqual(/*field_index=*/1, /*field_name=*/"f1", |
| FieldType::INT, Literal(20)); |
| // and_predicate has 3 nodes |
| ASSERT_OK_AND_ASSIGN(auto and_predicate, PredicateBuilder::And({equal, not_equal})); |
| |
| auto greater_than = PredicateBuilder::GreaterThan(/*field_index=*/2, /*field_name=*/"v0", |
| FieldType::INT, Literal(30)); |
| auto less_than = PredicateBuilder::LessThan(/*field_index=*/3, /*field_name=*/"f3", |
| FieldType::INT, Literal(20)); |
| // or_predicate has 3 nodes |
| ASSERT_OK_AND_ASSIGN(auto or_predicate, PredicateBuilder::Or({greater_than, less_than})); |
| |
| auto less_or_equal = PredicateBuilder::LessOrEqual(/*field_index=*/4, /*field_name=*/"f2", |
| FieldType::INT, Literal(50)); |
| auto in = PredicateBuilder::In(/*field_index=*/5, /*field_name=*/"f0", FieldType::INT, |
| {Literal(20), Literal(60)}); |
| auto not_in = PredicateBuilder::NotIn(/*field_index=*/5, /*field_name=*/"f0", FieldType::INT, |
| {Literal(120), Literal(160)}); |
| // or_predicate2 has 8 nodes |
| ASSERT_OK_AND_ASSIGN(auto or_predicate2, PredicateBuilder::Or({less_or_equal, in, not_in})); |
| |
| auto greater_or_equal = PredicateBuilder::GreaterOrEqual(/*field_index=*/4, /*field_name=*/"v1", |
| FieldType::INT, Literal(120)); |
| |
| // predicate has (1+3+3+8+1) nodes |
| ASSERT_OK_AND_ASSIGN(auto predicate, PredicateBuilder::And({and_predicate, or_predicate, |
| or_predicate2, greater_or_equal})); |
| |
| ASSERT_OK_AND_ASSIGN(auto expression, |
| PredicateConverter::Convert(predicate, /*predicate_node_count_limit=*/20)); |
| ASSERT_EQ(expression.ToString(), |
| "(((((f0 == 10) and (f1 != 20)) and ((v0 > 30) or (f3 < 20))) and (((f2 <= 50) or " |
| "((f0 == 20) or (f0 == 60))) or ((f0 != 120) and (f0 != 160)))) and (v1 >= 120))"); |
| ASSERT_OK_AND_ASSIGN(auto expression_always_true, |
| PredicateConverter::Convert(predicate, /*predicate_node_count_limit=*/10)); |
| ASSERT_EQ(expression_always_true.ToString(), "true"); |
| } |
| |
| TEST(PredicateConverterTest, TestWithoutPredicate) { |
| ASSERT_OK_AND_ASSIGN(auto expression, |
| PredicateConverter::Convert(nullptr, /*predicate_node_count_limit=*/100)); |
| ASSERT_EQ("true", expression.ToString()); |
| } |
| |
| TEST(PredicateConverterTest, TestInvalidCase) { |
| auto empty_in = |
| PredicateBuilder::In(/*field_index=*/0, /*field_name=*/"f0", FieldType::INT, {}); |
| ASSERT_NOK_WITH_MSG(PredicateConverter::Convert(empty_in, /*predicate_node_count_limit=*/100), |
| "predicate [In] need literal on field f0"); |
| } |
| |
| } // namespace paimon::parquet::test |