blob: a54f7622ba20ed6d6197f5fe9532cfe5f8d88e3c [file] [log] [blame]
// 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 <gtest/gtest.h>
#include "arrow/memory_pool.h"
#include "arrow/status.h"
#include "gandiva/projector.h"
#include "gandiva/tests/test_util.h"
#include "gandiva/tree_expr_builder.h"
namespace gandiva {
using arrow::boolean;
using arrow::int32;
class TestBooleanExpr : public ::testing::Test {
public:
void SetUp() { pool_ = arrow::default_memory_pool(); }
protected:
arrow::MemoryPool* pool_;
};
TEST_F(TestBooleanExpr, SimpleAnd) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto schema = arrow::schema({fielda, fieldb});
// output fields
auto field_result = field("res", boolean());
// build expression.
// (a > 0) && (b > 0)
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto literal_0 = TreeExprBuilder::MakeLiteral((int32_t)0);
auto a_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_0}, boolean());
auto b_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_0}, boolean());
auto node_and = TreeExprBuilder::MakeAnd({a_gt_0, b_gt_0});
auto expr = TreeExprBuilder::MakeExpression(node_and, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
// FALSE_VALID && ? => FALSE_VALID
int num_records = 4;
auto arraya = MakeArrowArrayInt32({-2, -2, -2, -2}, {true, true, true, true});
auto arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
auto exp = MakeArrowArrayBool({false, false, false, false}, {true, true, true, true});
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// FALSE_INVALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({-2, -2, -2, -2}, {false, false, false, false});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, false, false}, {true, false, false, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// TRUE_VALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({2, 2, 2, 2}, {true, true, true, true});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, true, false}, {true, false, true, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// TRUE_INVALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({2, 2, 2, 2}, {false, false, false, false});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, false, false}, {true, false, false, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
TEST_F(TestBooleanExpr, IsTrueFalse) {
// schema for input fields
auto field_a = field("a", boolean());
auto schema = arrow::schema({field_a});
// output fields
auto field_result_1 = field("is_true", boolean());
auto field_result_2 = field("is_not_false", boolean());
auto field_result_3 = field("is_false", boolean());
auto field_result_4 = field("is_not_true", boolean());
// build expressions.
auto is_true = TreeExprBuilder::MakeExpression("istrue", {field_a}, field_result_1);
auto is_not_false =
TreeExprBuilder::MakeExpression("isnotfalse", {field_a}, field_result_2);
auto is_false = TreeExprBuilder::MakeExpression("isfalse", {field_a}, field_result_3);
auto is_not_true =
TreeExprBuilder::MakeExpression("isnottrue", {field_a}, field_result_4);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {is_true, is_not_false, is_false, is_not_true},
TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
int num_records = 6;
auto in_a = MakeArrowArrayBool({true, false, false, true, true, false},
{true, true, true, true, false, false});
auto expa = MakeArrowArrayBool({true, false, false, true, false, false},
{true, true, true, true, true, true});
auto expb = MakeArrowArrayBool({true, false, false, true, true, true},
{true, true, true, true, true, true});
auto expc = MakeArrowArrayBool({false, true, true, false, false, false},
{true, true, true, true, true, true});
auto expd = MakeArrowArrayBool({false, true, true, false, true, true},
{true, true, true, true, true, true});
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {in_a});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(expa, outputs.at(0));
EXPECT_ARROW_ARRAY_EQUALS(expb, outputs.at(1));
EXPECT_ARROW_ARRAY_EQUALS(expc, outputs.at(2));
EXPECT_ARROW_ARRAY_EQUALS(expd, outputs.at(3));
}
TEST_F(TestBooleanExpr, SimpleOr) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto schema = arrow::schema({fielda, fieldb});
// output fields
auto field_result = field("res", boolean());
// build expression.
// (a > 0) || (b > 0)
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto literal_0 = TreeExprBuilder::MakeLiteral((int32_t)0);
auto a_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_0}, boolean());
auto b_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_0}, boolean());
auto node_or = TreeExprBuilder::MakeOr({a_gt_0, b_gt_0});
auto expr = TreeExprBuilder::MakeExpression(node_or, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
// TRUE_VALID && ? => TRUE_VALID
int num_records = 4;
auto arraya = MakeArrowArrayInt32({2, 2, 2, 2}, {true, true, true, true});
auto arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
auto exp = MakeArrowArrayBool({true, true, true, true}, {true, true, true, true});
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// TRUE_INVALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({2, 2, 2, 2}, {false, false, false, false});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, true, false}, {false, false, true, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// FALSE_VALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({-2, -2, -2, -2}, {true, true, true, true});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, true, false}, {true, false, true, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
// FALSE_INVALID && ?
num_records = 4;
arraya = MakeArrowArrayInt32({-2, -2, -2, -2}, {false, false, false, false});
arrayb = MakeArrowArrayInt32({-2, -2, 2, 2}, {true, false, true, false});
exp = MakeArrowArrayBool({false, false, true, false}, {false, false, true, false});
in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
outputs.clear();
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
TEST_F(TestBooleanExpr, AndThree) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto fieldc = field("c", int32());
auto schema = arrow::schema({fielda, fieldb, fieldc});
// output fields
auto field_result = field("res", boolean());
// build expression.
// (a > 0) && (b > 0) && (c > 0)
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto node_c = TreeExprBuilder::MakeField(fieldc);
auto literal_0 = TreeExprBuilder::MakeLiteral((int32_t)0);
auto a_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_0}, boolean());
auto b_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_0}, boolean());
auto c_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_c, literal_0}, boolean());
auto node_and = TreeExprBuilder::MakeAnd({a_gt_0, b_gt_0, c_gt_0});
auto expr = TreeExprBuilder::MakeExpression(node_and, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
int num_records = 8;
std::vector<bool> validity({true, true, true, true, true, true, true, true});
auto arraya = MakeArrowArrayInt32({2, 2, 2, 0, 2, 0, 0, 0}, validity);
auto arrayb = MakeArrowArrayInt32({2, 2, 0, 2, 0, 2, 0, 0}, validity);
auto arrayc = MakeArrowArrayInt32({2, 0, 2, 2, 0, 0, 2, 0}, validity);
auto exp = MakeArrowArrayBool({true, false, false, false, false, false, false, false},
validity);
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb, arrayc});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
TEST_F(TestBooleanExpr, OrThree) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto fieldc = field("c", int32());
auto schema = arrow::schema({fielda, fieldb, fieldc});
// output fields
auto field_result = field("res", boolean());
// build expression.
// (a > 0) || (b > 0) || (c > 0)
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto node_c = TreeExprBuilder::MakeField(fieldc);
auto literal_0 = TreeExprBuilder::MakeLiteral((int32_t)0);
auto a_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_0}, boolean());
auto b_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_0}, boolean());
auto c_gt_0 =
TreeExprBuilder::MakeFunction("greater_than", {node_c, literal_0}, boolean());
auto node_or = TreeExprBuilder::MakeOr({a_gt_0, b_gt_0, c_gt_0});
auto expr = TreeExprBuilder::MakeExpression(node_or, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
int num_records = 8;
std::vector<bool> validity({true, true, true, true, true, true, true, true});
auto arraya = MakeArrowArrayInt32({2, 2, 2, 0, 2, 0, 0, 0}, validity);
auto arrayb = MakeArrowArrayInt32({2, 2, 0, 2, 0, 2, 0, 0}, validity);
auto arrayc = MakeArrowArrayInt32({2, 0, 2, 2, 0, 0, 2, 0}, validity);
auto exp =
MakeArrowArrayBool({true, true, true, true, true, true, true, false}, validity);
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb, arrayc});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
TEST_F(TestBooleanExpr, BooleanAndInsideIf) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto schema = arrow::schema({fielda, fieldb});
// output fields
auto field_result = field("res", boolean());
// build expression.
// if (a > 2 && b > 2)
// a > 3 && b > 3
// else
// a > 1 && b > 1
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto literal_1 = TreeExprBuilder::MakeLiteral((int32_t)1);
auto literal_2 = TreeExprBuilder::MakeLiteral((int32_t)2);
auto literal_3 = TreeExprBuilder::MakeLiteral((int32_t)3);
auto a_gt_1 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_1}, boolean());
auto a_gt_2 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_2}, boolean());
auto a_gt_3 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_3}, boolean());
auto b_gt_1 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_1}, boolean());
auto b_gt_2 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_2}, boolean());
auto b_gt_3 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_3}, boolean());
auto and_1 = TreeExprBuilder::MakeAnd({a_gt_1, b_gt_1});
auto and_2 = TreeExprBuilder::MakeAnd({a_gt_2, b_gt_2});
auto and_3 = TreeExprBuilder::MakeAnd({a_gt_3, b_gt_3});
auto node_if = TreeExprBuilder::MakeIf(and_2, and_3, and_1, arrow::boolean());
auto expr = TreeExprBuilder::MakeExpression(node_if, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
int num_records = 4;
std::vector<bool> validity({true, true, true, true});
auto arraya = MakeArrowArrayInt32({4, 4, 2, 1}, validity);
auto arrayb = MakeArrowArrayInt32({5, 3, 3, 1}, validity);
auto exp = MakeArrowArrayBool({true, false, true, false}, validity);
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
TEST_F(TestBooleanExpr, IfInsideBooleanAnd) {
// schema for input fields
auto fielda = field("a", int32());
auto fieldb = field("b", int32());
auto schema = arrow::schema({fielda, fieldb});
// output fields
auto field_result = field("res", boolean());
// build expression.
// (if (a > b) a > 3 else b > 3) && (if (a > b) a > 2 else b > 2)
auto node_a = TreeExprBuilder::MakeField(fielda);
auto node_b = TreeExprBuilder::MakeField(fieldb);
auto literal_2 = TreeExprBuilder::MakeLiteral((int32_t)2);
auto literal_3 = TreeExprBuilder::MakeLiteral((int32_t)3);
auto a_gt_b =
TreeExprBuilder::MakeFunction("greater_than", {node_a, node_b}, boolean());
auto a_gt_2 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_2}, boolean());
auto a_gt_3 =
TreeExprBuilder::MakeFunction("greater_than", {node_a, literal_3}, boolean());
auto b_gt_2 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_2}, boolean());
auto b_gt_3 =
TreeExprBuilder::MakeFunction("greater_than", {node_b, literal_3}, boolean());
auto if_3 = TreeExprBuilder::MakeIf(a_gt_b, a_gt_3, b_gt_3, arrow::boolean());
auto if_2 = TreeExprBuilder::MakeIf(a_gt_b, a_gt_2, b_gt_2, arrow::boolean());
auto node_and = TreeExprBuilder::MakeAnd({if_3, if_2});
auto expr = TreeExprBuilder::MakeExpression(node_and, field_result);
// Build a projector for the expressions.
std::shared_ptr<Projector> projector;
auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
EXPECT_TRUE(status.ok());
int num_records = 4;
std::vector<bool> validity({true, true, true, true});
auto arraya = MakeArrowArrayInt32({4, 3, 3, 2}, validity);
auto arrayb = MakeArrowArrayInt32({3, 4, 2, 3}, validity);
auto exp = MakeArrowArrayBool({true, true, false, false}, validity);
auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arraya, arrayb});
arrow::ArrayVector outputs;
status = projector->Evaluate(*in_batch, pool_, &outputs);
EXPECT_TRUE(status.ok());
EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
}
} // namespace gandiva