1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements.  See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.  The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License.  You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied.  See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 #include "gandiva/tree_expr_builder.h"
19 
20 #include <gtest/gtest.h>
21 #include "gandiva/annotator.h"
22 #include "gandiva/dex.h"
23 #include "gandiva/expr_decomposer.h"
24 #include "gandiva/function_registry.h"
25 #include "gandiva/function_signature.h"
26 #include "gandiva/gandiva_aliases.h"
27 #include "gandiva/node.h"
28 
29 namespace gandiva {
30 
31 using arrow::boolean;
32 using arrow::int32;
33 
34 class TestExprTree : public ::testing::Test {
35  public:
SetUp()36   void SetUp() {
37     i0_ = field("i0", int32());
38     i1_ = field("i1", int32());
39 
40     b0_ = field("b0", boolean());
41   }
42 
43  protected:
44   FieldPtr i0_;  // int32
45   FieldPtr i1_;  // int32
46 
47   FieldPtr b0_;  // bool
48   FunctionRegistry registry_;
49 };
50 
TEST_F(TestExprTree,TestField)51 TEST_F(TestExprTree, TestField) {
52   Annotator annotator;
53 
54   auto n0 = TreeExprBuilder::MakeField(i0_);
55   EXPECT_EQ(n0->return_type(), int32());
56 
57   auto n1 = TreeExprBuilder::MakeField(b0_);
58   EXPECT_EQ(n1->return_type(), boolean());
59 
60   ExprDecomposer decomposer(registry_, annotator);
61   ValueValidityPairPtr pair;
62   auto status = decomposer.Decompose(*n1, &pair);
63   DCHECK_EQ(status.ok(), true) << status.message();
64 
65   auto value = pair->value_expr();
66   auto value_dex = std::dynamic_pointer_cast<VectorReadFixedLenValueDex>(value);
67   EXPECT_EQ(value_dex->FieldType(), boolean());
68 
69   EXPECT_EQ(pair->validity_exprs().size(), 1);
70   auto validity = pair->validity_exprs().at(0);
71   auto validity_dex = std::dynamic_pointer_cast<VectorReadValidityDex>(validity);
72   EXPECT_NE(validity_dex->ValidityIdx(), value_dex->DataIdx());
73 }
74 
TEST_F(TestExprTree,TestBinary)75 TEST_F(TestExprTree, TestBinary) {
76   Annotator annotator;
77 
78   auto left = TreeExprBuilder::MakeField(i0_);
79   auto right = TreeExprBuilder::MakeField(i1_);
80 
81   auto n = TreeExprBuilder::MakeFunction("add", {left, right}, int32());
82   auto add = std::dynamic_pointer_cast<FunctionNode>(n);
83 
84   auto func_desc = add->descriptor();
85   FunctionSignature sign(func_desc->name(), func_desc->params(),
86                          func_desc->return_type());
87 
88   EXPECT_EQ(add->return_type(), int32());
89   EXPECT_TRUE(sign == FunctionSignature("add", {int32(), int32()}, int32()));
90 
91   ExprDecomposer decomposer(registry_, annotator);
92   ValueValidityPairPtr pair;
93   auto status = decomposer.Decompose(*n, &pair);
94   DCHECK_EQ(status.ok(), true) << status.message();
95 
96   auto value = pair->value_expr();
97   auto null_if_null = std::dynamic_pointer_cast<NonNullableFuncDex>(value);
98 
99   FunctionSignature signature("add", {int32(), int32()}, int32());
100   const NativeFunction* fn = registry_.LookupSignature(signature);
101   EXPECT_EQ(null_if_null->native_function(), fn);
102 }
103 
TEST_F(TestExprTree,TestUnary)104 TEST_F(TestExprTree, TestUnary) {
105   Annotator annotator;
106 
107   auto arg = TreeExprBuilder::MakeField(i0_);
108   auto n = TreeExprBuilder::MakeFunction("isnumeric", {arg}, boolean());
109 
110   auto unaryFn = std::dynamic_pointer_cast<FunctionNode>(n);
111   auto func_desc = unaryFn->descriptor();
112   FunctionSignature sign(func_desc->name(), func_desc->params(),
113                          func_desc->return_type());
114   EXPECT_EQ(unaryFn->return_type(), boolean());
115   EXPECT_TRUE(sign == FunctionSignature("isnumeric", {int32()}, boolean()));
116 
117   ExprDecomposer decomposer(registry_, annotator);
118   ValueValidityPairPtr pair;
119   auto status = decomposer.Decompose(*n, &pair);
120   DCHECK_EQ(status.ok(), true) << status.message();
121 
122   auto value = pair->value_expr();
123   auto never_null = std::dynamic_pointer_cast<NullableNeverFuncDex>(value);
124 
125   FunctionSignature signature("isnumeric", {int32()}, boolean());
126   const NativeFunction* fn = registry_.LookupSignature(signature);
127   EXPECT_EQ(never_null->native_function(), fn);
128 }
129 
TEST_F(TestExprTree,TestExpression)130 TEST_F(TestExprTree, TestExpression) {
131   Annotator annotator;
132   auto left = TreeExprBuilder::MakeField(i0_);
133   auto right = TreeExprBuilder::MakeField(i1_);
134 
135   auto n = TreeExprBuilder::MakeFunction("add", {left, right}, int32());
136   auto e = TreeExprBuilder::MakeExpression(n, field("r", int32()));
137   auto root_node = e->root();
138   EXPECT_EQ(root_node->return_type(), int32());
139 
140   auto add_node = std::dynamic_pointer_cast<FunctionNode>(root_node);
141   auto func_desc = add_node->descriptor();
142   FunctionSignature sign(func_desc->name(), func_desc->params(),
143                          func_desc->return_type());
144   EXPECT_TRUE(sign == FunctionSignature("add", {int32(), int32()}, int32()));
145 
146   ExprDecomposer decomposer(registry_, annotator);
147   ValueValidityPairPtr pair;
148   auto status = decomposer.Decompose(*root_node, &pair);
149   DCHECK_EQ(status.ok(), true) << status.message();
150 
151   auto value = pair->value_expr();
152   auto null_if_null = std::dynamic_pointer_cast<NonNullableFuncDex>(value);
153 
154   FunctionSignature signature("add", {int32(), int32()}, int32());
155   const NativeFunction* fn = registry_.LookupSignature(signature);
156   EXPECT_EQ(null_if_null->native_function(), fn);
157 }
158 
159 }  // namespace gandiva
160