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 #ifndef M_PI
19 #define M_PI 3.14159265358979323846
20 #endif
21 
22 #include "gandiva/projector.h"
23 
24 #include <gtest/gtest.h>
25 
26 #include <cmath>
27 
28 #include "arrow/memory_pool.h"
29 #include "gandiva/literal_holder.h"
30 #include "gandiva/node.h"
31 #include "gandiva/tests/test_util.h"
32 #include "gandiva/tree_expr_builder.h"
33 
34 namespace gandiva {
35 
36 using arrow::boolean;
37 using arrow::float32;
38 using arrow::int32;
39 
40 class TestProjector : public ::testing::Test {
41  public:
SetUp()42   void SetUp() { pool_ = arrow::default_memory_pool(); }
43 
44  protected:
45   arrow::MemoryPool* pool_;
46 };
47 
TEST_F(TestProjector,TestProjectCache)48 TEST_F(TestProjector, TestProjectCache) {
49   // schema for input fields
50   auto field0 = field("f0", int32());
51   auto field1 = field("f2", int32());
52   auto schema = arrow::schema({field0, field1});
53 
54   // output fields
55   auto field_sum = field("add", int32());
56   auto field_sub = field("subtract", int32());
57 
58   // Build expression
59   auto sum_expr = TreeExprBuilder::MakeExpression("add", {field0, field1}, field_sum);
60   auto sub_expr =
61       TreeExprBuilder::MakeExpression("subtract", {field0, field1}, field_sub);
62 
63   auto configuration = TestConfiguration();
64 
65   std::shared_ptr<Projector> projector;
66   auto status = Projector::Make(schema, {sum_expr, sub_expr}, configuration, &projector);
67   ASSERT_OK(status);
68 
69   // everything is same, should return the same projector.
70   auto schema_same = arrow::schema({field0, field1});
71   std::shared_ptr<Projector> cached_projector;
72   status = Projector::Make(schema_same, {sum_expr, sub_expr}, configuration,
73                            &cached_projector);
74   ASSERT_OK(status);
75   EXPECT_EQ(cached_projector, projector);
76 
77   // schema is different should return a new projector.
78   auto field2 = field("f2", int32());
79   auto different_schema = arrow::schema({field0, field1, field2});
80   std::shared_ptr<Projector> should_be_new_projector;
81   status = Projector::Make(different_schema, {sum_expr, sub_expr}, configuration,
82                            &should_be_new_projector);
83   ASSERT_OK(status);
84   EXPECT_NE(cached_projector, should_be_new_projector);
85 
86   // expression list is different should return a new projector.
87   std::shared_ptr<Projector> should_be_new_projector1;
88   status = Projector::Make(schema, {sum_expr}, configuration, &should_be_new_projector1);
89   ASSERT_OK(status);
90   EXPECT_NE(cached_projector, should_be_new_projector1);
91 
92   // another instance of the same configuration, should return the same projector.
93   status = Projector::Make(schema, {sum_expr, sub_expr}, TestConfiguration(),
94                            &cached_projector);
95   ASSERT_OK(status);
96   EXPECT_EQ(cached_projector, projector);
97 }
98 
TEST_F(TestProjector,TestProjectCacheFieldNames)99 TEST_F(TestProjector, TestProjectCacheFieldNames) {
100   // schema for input fields
101   auto field0 = field("f0", int32());
102   auto field1 = field("f1", int32());
103   auto field2 = field("f2", int32());
104   auto schema = arrow::schema({field0, field1, field2});
105 
106   // output fields
107   auto sum_01 = field("sum_01", int32());
108   auto sum_12 = field("sum_12", int32());
109 
110   auto sum_expr_01 = TreeExprBuilder::MakeExpression("add", {field0, field1}, sum_01);
111   std::shared_ptr<Projector> projector_01;
112   auto status =
113       Projector::Make(schema, {sum_expr_01}, TestConfiguration(), &projector_01);
114   EXPECT_TRUE(status.ok());
115 
116   auto sum_expr_12 = TreeExprBuilder::MakeExpression("add", {field1, field2}, sum_12);
117   std::shared_ptr<Projector> projector_12;
118   status = Projector::Make(schema, {sum_expr_12}, TestConfiguration(), &projector_12);
119   EXPECT_TRUE(status.ok());
120 
121   // add(f0, f1) != add(f1, f2)
122   EXPECT_TRUE(projector_01.get() != projector_12.get());
123 }
124 
TEST_F(TestProjector,TestProjectCacheDouble)125 TEST_F(TestProjector, TestProjectCacheDouble) {
126   auto schema = arrow::schema({});
127   auto res = field("result", arrow::float64());
128 
129   double d0 = 1.23456788912345677E18;
130   double d1 = 1.23456789012345677E18;
131 
132   auto literal0 = TreeExprBuilder::MakeLiteral(d0);
133   auto expr0 = TreeExprBuilder::MakeExpression(literal0, res);
134   auto configuration = TestConfiguration();
135 
136   std::shared_ptr<Projector> projector0;
137   auto status = Projector::Make(schema, {expr0}, configuration, &projector0);
138   EXPECT_TRUE(status.ok()) << status.message();
139 
140   auto literal1 = TreeExprBuilder::MakeLiteral(d1);
141   auto expr1 = TreeExprBuilder::MakeExpression(literal1, res);
142   std::shared_ptr<Projector> projector1;
143   status = Projector::Make(schema, {expr1}, configuration, &projector1);
144   EXPECT_TRUE(status.ok()) << status.message();
145 
146   EXPECT_TRUE(projector0.get() != projector1.get());
147 }
148 
TEST_F(TestProjector,TestProjectCacheFloat)149 TEST_F(TestProjector, TestProjectCacheFloat) {
150   auto schema = arrow::schema({});
151   auto res = field("result", arrow::float32());
152 
153   float f0 = static_cast<float>(12345678891.000000);
154   float f1 = f0 - 1000;
155 
156   auto literal0 = TreeExprBuilder::MakeLiteral(f0);
157   auto expr0 = TreeExprBuilder::MakeExpression(literal0, res);
158   std::shared_ptr<Projector> projector0;
159   auto status = Projector::Make(schema, {expr0}, TestConfiguration(), &projector0);
160   EXPECT_TRUE(status.ok()) << status.message();
161 
162   auto literal1 = TreeExprBuilder::MakeLiteral(f1);
163   auto expr1 = TreeExprBuilder::MakeExpression(literal1, res);
164   std::shared_ptr<Projector> projector1;
165   status = Projector::Make(schema, {expr1}, TestConfiguration(), &projector1);
166   EXPECT_TRUE(status.ok()) << status.message();
167 
168   EXPECT_TRUE(projector0.get() != projector1.get());
169 }
170 
TEST_F(TestProjector,TestProjectCacheLiteral)171 TEST_F(TestProjector, TestProjectCacheLiteral) {
172   auto schema = arrow::schema({});
173   auto res = field("result", arrow::decimal(38, 5));
174 
175   DecimalScalar128 d0("12345678", 38, 5);
176   DecimalScalar128 d1("98756432", 38, 5);
177 
178   auto literal0 = TreeExprBuilder::MakeDecimalLiteral(d0);
179   auto expr0 = TreeExprBuilder::MakeExpression(literal0, res);
180   std::shared_ptr<Projector> projector0;
181   ASSERT_OK(Projector::Make(schema, {expr0}, TestConfiguration(), &projector0));
182 
183   auto literal1 = TreeExprBuilder::MakeDecimalLiteral(d1);
184   auto expr1 = TreeExprBuilder::MakeExpression(literal1, res);
185   std::shared_ptr<Projector> projector1;
186   ASSERT_OK(Projector::Make(schema, {expr1}, TestConfiguration(), &projector1));
187 
188   EXPECT_NE(projector0.get(), projector1.get());
189 }
190 
TEST_F(TestProjector,TestProjectCacheDecimalCast)191 TEST_F(TestProjector, TestProjectCacheDecimalCast) {
192   auto field_float64 = field("float64", arrow::float64());
193   auto schema = arrow::schema({field_float64});
194 
195   auto res_31_13 = field("result", arrow::decimal(31, 13));
196   auto expr0 = TreeExprBuilder::MakeExpression("castDECIMAL", {field_float64}, res_31_13);
197   std::shared_ptr<Projector> projector0;
198   ASSERT_OK(Projector::Make(schema, {expr0}, TestConfiguration(), &projector0));
199 
200   // if the output scale is different, the cache can't be used.
201   auto res_31_14 = field("result", arrow::decimal(31, 14));
202   auto expr1 = TreeExprBuilder::MakeExpression("castDECIMAL", {field_float64}, res_31_14);
203   std::shared_ptr<Projector> projector1;
204   ASSERT_OK(Projector::Make(schema, {expr1}, TestConfiguration(), &projector1));
205   EXPECT_NE(projector0.get(), projector1.get());
206 
207   // if the output scale/precision are same, should get a cache hit.
208   auto res_31_13_alt = field("result", arrow::decimal(31, 13));
209   auto expr2 =
210       TreeExprBuilder::MakeExpression("castDECIMAL", {field_float64}, res_31_13_alt);
211   std::shared_ptr<Projector> projector2;
212   ASSERT_OK(Projector::Make(schema, {expr2}, TestConfiguration(), &projector2));
213   EXPECT_EQ(projector0.get(), projector2.get());
214 }
215 
TEST_F(TestProjector,TestIntSumSub)216 TEST_F(TestProjector, TestIntSumSub) {
217   // schema for input fields
218   auto field0 = field("f0", int32());
219   auto field1 = field("f2", int32());
220   auto schema = arrow::schema({field0, field1});
221 
222   // output fields
223   auto field_sum = field("add", int32());
224   auto field_sub = field("subtract", int32());
225 
226   // Build expression
227   auto sum_expr = TreeExprBuilder::MakeExpression("add", {field0, field1}, field_sum);
228   auto sub_expr =
229       TreeExprBuilder::MakeExpression("subtract", {field0, field1}, field_sub);
230 
231   std::shared_ptr<Projector> projector;
232   auto status =
233       Projector::Make(schema, {sum_expr, sub_expr}, TestConfiguration(), &projector);
234   EXPECT_TRUE(status.ok());
235 
236   // Create a row-batch with some sample data
237   int num_records = 4;
238   auto array0 = MakeArrowArrayInt32({1, 2, 3, 4}, {true, true, true, false});
239   auto array1 = MakeArrowArrayInt32({11, 13, 15, 17}, {true, true, false, true});
240   // expected output
241   auto exp_sum = MakeArrowArrayInt32({12, 15, 0, 0}, {true, true, false, false});
242   auto exp_sub = MakeArrowArrayInt32({-10, -11, 0, 0}, {true, true, false, false});
243 
244   // prepare input record batch
245   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
246 
247   // Evaluate expression
248   arrow::ArrayVector outputs;
249   status = projector->Evaluate(*in_batch, pool_, &outputs);
250   EXPECT_TRUE(status.ok());
251 
252   // Validate results
253   EXPECT_ARROW_ARRAY_EQUALS(exp_sum, outputs.at(0));
254   EXPECT_ARROW_ARRAY_EQUALS(exp_sub, outputs.at(1));
255 }
256 
257 template <typename TYPE, typename C_TYPE>
TestArithmeticOpsForType(arrow::MemoryPool * pool)258 static void TestArithmeticOpsForType(arrow::MemoryPool* pool) {
259   auto atype = arrow::TypeTraits<TYPE>::type_singleton();
260 
261   // schema for input fields
262   auto field0 = field("f0", atype);
263   auto field1 = field("f1", atype);
264   auto schema = arrow::schema({field0, field1});
265 
266   // output fields
267   auto field_sum = field("add", atype);
268   auto field_sub = field("subtract", atype);
269   auto field_mul = field("multiply", atype);
270   auto field_div = field("divide", atype);
271   auto field_eq = field("equal", arrow::boolean());
272   auto field_lt = field("less_than", arrow::boolean());
273 
274   // Build expression
275   auto sum_expr = TreeExprBuilder::MakeExpression("add", {field0, field1}, field_sum);
276   auto sub_expr =
277       TreeExprBuilder::MakeExpression("subtract", {field0, field1}, field_sub);
278   auto mul_expr =
279       TreeExprBuilder::MakeExpression("multiply", {field0, field1}, field_mul);
280   auto div_expr = TreeExprBuilder::MakeExpression("divide", {field0, field1}, field_div);
281   auto eq_expr = TreeExprBuilder::MakeExpression("equal", {field0, field1}, field_eq);
282   auto lt_expr = TreeExprBuilder::MakeExpression("less_than", {field0, field1}, field_lt);
283 
284   std::shared_ptr<Projector> projector;
285   auto status =
286       Projector::Make(schema, {sum_expr, sub_expr, mul_expr, div_expr, eq_expr, lt_expr},
287                       TestConfiguration(), &projector);
288   EXPECT_TRUE(status.ok());
289 
290   // Create a row-batch with some sample data
291   int num_records = 12;
292   std::vector<C_TYPE> input0 = {1, 2, 53, 84, 5, 15, 0, 1, 52, 83, 4, 120};
293   std::vector<C_TYPE> input1 = {10, 15, 23, 84, 4, 51, 68, 9, 16, 18, 19, 37};
294   std::vector<bool> validity = {true, true, true, true, true, true,
295                                 true, true, true, true, true, true};
296 
297   auto array0 = MakeArrowArray<TYPE, C_TYPE>(input0, validity);
298   auto array1 = MakeArrowArray<TYPE, C_TYPE>(input1, validity);
299 
300   // expected output
301   std::vector<C_TYPE> sum;
302   std::vector<C_TYPE> sub;
303   std::vector<C_TYPE> mul;
304   std::vector<C_TYPE> div;
305   std::vector<bool> eq;
306   std::vector<bool> lt;
307   for (int i = 0; i < num_records; i++) {
308     sum.push_back(static_cast<C_TYPE>(input0[i] + input1[i]));
309     sub.push_back(static_cast<C_TYPE>(input0[i] - input1[i]));
310     mul.push_back(static_cast<C_TYPE>(input0[i] * input1[i]));
311     div.push_back(static_cast<C_TYPE>(input0[i] / input1[i]));
312     eq.push_back(input0[i] == input1[i]);
313     lt.push_back(input0[i] < input1[i]);
314   }
315   auto exp_sum = MakeArrowArray<TYPE, C_TYPE>(sum, validity);
316   auto exp_sub = MakeArrowArray<TYPE, C_TYPE>(sub, validity);
317   auto exp_mul = MakeArrowArray<TYPE, C_TYPE>(mul, validity);
318   auto exp_div = MakeArrowArray<TYPE, C_TYPE>(div, validity);
319   auto exp_eq = MakeArrowArray<arrow::BooleanType, bool>(eq, validity);
320   auto exp_lt = MakeArrowArray<arrow::BooleanType, bool>(lt, validity);
321 
322   // prepare input record batch
323   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
324 
325   // Evaluate expression
326   arrow::ArrayVector outputs;
327   status = projector->Evaluate(*in_batch, pool, &outputs);
328   EXPECT_TRUE(status.ok());
329 
330   // Validate results
331   EXPECT_ARROW_ARRAY_EQUALS(exp_sum, outputs.at(0));
332   EXPECT_ARROW_ARRAY_EQUALS(exp_sub, outputs.at(1));
333   EXPECT_ARROW_ARRAY_EQUALS(exp_mul, outputs.at(2));
334   EXPECT_ARROW_ARRAY_EQUALS(exp_div, outputs.at(3));
335   EXPECT_ARROW_ARRAY_EQUALS(exp_eq, outputs.at(4));
336   EXPECT_ARROW_ARRAY_EQUALS(exp_lt, outputs.at(5));
337 }
338 
TEST_F(TestProjector,TestAllIntTypes)339 TEST_F(TestProjector, TestAllIntTypes) {
340   TestArithmeticOpsForType<arrow::UInt8Type, uint8_t>(pool_);
341   TestArithmeticOpsForType<arrow::UInt16Type, uint16_t>(pool_);
342   TestArithmeticOpsForType<arrow::UInt32Type, uint32_t>(pool_);
343   TestArithmeticOpsForType<arrow::UInt64Type, uint64_t>(pool_);
344   TestArithmeticOpsForType<arrow::Int8Type, int8_t>(pool_);
345   TestArithmeticOpsForType<arrow::Int16Type, int16_t>(pool_);
346   TestArithmeticOpsForType<arrow::Int32Type, int32_t>(pool_);
347   TestArithmeticOpsForType<arrow::Int64Type, int64_t>(pool_);
348 }
349 
TEST_F(TestProjector,TestExtendedMath)350 TEST_F(TestProjector, TestExtendedMath) {
351   // schema for input fields
352   auto field0 = arrow::field("f0", arrow::float64());
353   auto field1 = arrow::field("f1", arrow::float64());
354   auto schema = arrow::schema({field0, field1});
355 
356   // output fields
357   auto field_cbrt = arrow::field("cbrt", arrow::float64());
358   auto field_exp = arrow::field("exp", arrow::float64());
359   auto field_log = arrow::field("log", arrow::float64());
360   auto field_log10 = arrow::field("log10", arrow::float64());
361   auto field_logb = arrow::field("logb", arrow::float64());
362   auto field_power = arrow::field("power", arrow::float64());
363   auto field_sin = arrow::field("sin", arrow::float64());
364   auto field_cos = arrow::field("cos", arrow::float64());
365   auto field_asin = arrow::field("asin", arrow::float64());
366   auto field_acos = arrow::field("acos", arrow::float64());
367   auto field_tan = arrow::field("tan", arrow::float64());
368   auto field_atan = arrow::field("atan", arrow::float64());
369   auto field_sinh = arrow::field("sinh", arrow::float64());
370   auto field_cosh = arrow::field("cosh", arrow::float64());
371   auto field_tanh = arrow::field("tanh", arrow::float64());
372   auto field_atan2 = arrow::field("atan2", arrow::float64());
373   auto field_cot = arrow::field("cot", arrow::float64());
374   auto field_radians = arrow::field("radians", arrow::float64());
375   auto field_degrees = arrow::field("degrees", arrow::float64());
376 
377   // Build expression
378   auto cbrt_expr = TreeExprBuilder::MakeExpression("cbrt", {field0}, field_cbrt);
379   auto exp_expr = TreeExprBuilder::MakeExpression("exp", {field0}, field_exp);
380   auto log_expr = TreeExprBuilder::MakeExpression("log", {field0}, field_log);
381   auto log10_expr = TreeExprBuilder::MakeExpression("log10", {field0}, field_log10);
382   auto logb_expr = TreeExprBuilder::MakeExpression("log", {field0, field1}, field_logb);
383   auto power_expr =
384       TreeExprBuilder::MakeExpression("power", {field0, field1}, field_power);
385   auto sin_expr = TreeExprBuilder::MakeExpression("sin", {field0}, field_sin);
386   auto cos_expr = TreeExprBuilder::MakeExpression("cos", {field0}, field_cos);
387   auto asin_expr = TreeExprBuilder::MakeExpression("asin", {field0}, field_asin);
388   auto acos_expr = TreeExprBuilder::MakeExpression("acos", {field0}, field_acos);
389   auto tan_expr = TreeExprBuilder::MakeExpression("tan", {field0}, field_tan);
390   auto atan_expr = TreeExprBuilder::MakeExpression("atan", {field0}, field_atan);
391   auto sinh_expr = TreeExprBuilder::MakeExpression("sinh", {field0}, field_sinh);
392   auto cosh_expr = TreeExprBuilder::MakeExpression("cosh", {field0}, field_cosh);
393   auto tanh_expr = TreeExprBuilder::MakeExpression("tanh", {field0}, field_tanh);
394   auto atan2_expr =
395       TreeExprBuilder::MakeExpression("atan2", {field0, field1}, field_atan2);
396   auto cot_expr = TreeExprBuilder::MakeExpression("cot", {field0}, field_cot);
397   auto radians_expr = TreeExprBuilder::MakeExpression("radians", {field0}, field_radians);
398   auto degrees_expr = TreeExprBuilder::MakeExpression("degrees", {field0}, field_degrees);
399 
400   std::shared_ptr<Projector> projector;
401   auto status = Projector::Make(
402       schema,
403       {cbrt_expr, exp_expr, log_expr, log10_expr, logb_expr, power_expr, sin_expr,
404        cos_expr, asin_expr, acos_expr, tan_expr, atan_expr, sinh_expr, cosh_expr,
405        tanh_expr, atan2_expr, cot_expr, radians_expr, degrees_expr},
406       TestConfiguration(), &projector);
407   EXPECT_TRUE(status.ok());
408 
409   // Create a row-batch with some sample data
410   int num_records = 4;
411   std::vector<double> input0 = {16, 10, -14, 8.3};
412   std::vector<double> input1 = {2, 3, 5, 7};
413   std::vector<bool> validity = {true, true, true, true};
414 
415   auto array0 = MakeArrowArray<arrow::DoubleType, double>(input0, validity);
416   auto array1 = MakeArrowArray<arrow::DoubleType, double>(input1, validity);
417 
418   // expected output
419   std::vector<double> cbrt_vals;
420   std::vector<double> exp_vals;
421   std::vector<double> log_vals;
422   std::vector<double> log10_vals;
423   std::vector<double> logb_vals;
424   std::vector<double> power_vals;
425   std::vector<double> sin_vals;
426   std::vector<double> cos_vals;
427   std::vector<double> asin_vals;
428   std::vector<double> acos_vals;
429   std::vector<double> tan_vals;
430   std::vector<double> atan_vals;
431   std::vector<double> sinh_vals;
432   std::vector<double> cosh_vals;
433   std::vector<double> tanh_vals;
434   std::vector<double> atan2_vals;
435   std::vector<double> cot_vals;
436   std::vector<double> radians_vals;
437   std::vector<double> degrees_vals;
438   for (int i = 0; i < num_records; i++) {
439     cbrt_vals.push_back(static_cast<double>(cbrtl(input0[i])));
440     exp_vals.push_back(static_cast<double>(expl(input0[i])));
441     log_vals.push_back(static_cast<double>(logl(input0[i])));
442     log10_vals.push_back(static_cast<double>(log10l(input0[i])));
443     logb_vals.push_back(static_cast<double>(logl(input1[i]) / logl(input0[i])));
444     power_vals.push_back(static_cast<double>(powl(input0[i], input1[i])));
445     sin_vals.push_back(static_cast<double>(sin(input0[i])));
446     cos_vals.push_back(static_cast<double>(cos(input0[i])));
447     asin_vals.push_back(static_cast<double>(asin(input0[i])));
448     acos_vals.push_back(static_cast<double>(acos(input0[i])));
449     tan_vals.push_back(static_cast<double>(tan(input0[i])));
450     atan_vals.push_back(static_cast<double>(atan(input0[i])));
451     sinh_vals.push_back(static_cast<double>(sinh(input0[i])));
452     cosh_vals.push_back(static_cast<double>(cosh(input0[i])));
453     tanh_vals.push_back(static_cast<double>(tanh(input0[i])));
454     atan2_vals.push_back(static_cast<double>(atan2(input0[i], input1[i])));
455     cot_vals.push_back(static_cast<double>(tan(M_PI / 2 - input0[i])));
456     radians_vals.push_back(static_cast<double>(input0[i] * M_PI / 180.0));
457     degrees_vals.push_back(static_cast<double>(input0[i] * 180.0 / M_PI));
458   }
459   auto expected_cbrt = MakeArrowArray<arrow::DoubleType, double>(cbrt_vals, validity);
460   auto expected_exp = MakeArrowArray<arrow::DoubleType, double>(exp_vals, validity);
461   auto expected_log = MakeArrowArray<arrow::DoubleType, double>(log_vals, validity);
462   auto expected_log10 = MakeArrowArray<arrow::DoubleType, double>(log10_vals, validity);
463   auto expected_logb = MakeArrowArray<arrow::DoubleType, double>(logb_vals, validity);
464   auto expected_power = MakeArrowArray<arrow::DoubleType, double>(power_vals, validity);
465   auto expected_sin = MakeArrowArray<arrow::DoubleType, double>(sin_vals, validity);
466   auto expected_cos = MakeArrowArray<arrow::DoubleType, double>(cos_vals, validity);
467   auto expected_asin = MakeArrowArray<arrow::DoubleType, double>(asin_vals, validity);
468   auto expected_acos = MakeArrowArray<arrow::DoubleType, double>(acos_vals, validity);
469   auto expected_tan = MakeArrowArray<arrow::DoubleType, double>(tan_vals, validity);
470   auto expected_atan = MakeArrowArray<arrow::DoubleType, double>(atan_vals, validity);
471   auto expected_sinh = MakeArrowArray<arrow::DoubleType, double>(sinh_vals, validity);
472   auto expected_cosh = MakeArrowArray<arrow::DoubleType, double>(cosh_vals, validity);
473   auto expected_tanh = MakeArrowArray<arrow::DoubleType, double>(tanh_vals, validity);
474   auto expected_atan2 = MakeArrowArray<arrow::DoubleType, double>(atan2_vals, validity);
475   auto expected_cot = MakeArrowArray<arrow::DoubleType, double>(cot_vals, validity);
476   auto expected_radians =
477       MakeArrowArray<arrow::DoubleType, double>(radians_vals, validity);
478   auto expected_degrees =
479       MakeArrowArray<arrow::DoubleType, double>(degrees_vals, validity);
480   // prepare input record batch
481   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
482 
483   // Evaluate expression
484   arrow::ArrayVector outputs;
485   status = projector->Evaluate(*in_batch, pool_, &outputs);
486   EXPECT_TRUE(status.ok());
487 
488   // Validate results
489   double epsilon = 1E-13;
490   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_cbrt, outputs.at(0), epsilon);
491   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_exp, outputs.at(1), epsilon);
492   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_log, outputs.at(2), epsilon);
493   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_log10, outputs.at(3), epsilon);
494   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_logb, outputs.at(4), epsilon);
495   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_power, outputs.at(5), epsilon);
496   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_sin, outputs.at(6), epsilon);
497   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_cos, outputs.at(7), epsilon);
498   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_asin, outputs.at(8), epsilon);
499   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_acos, outputs.at(9), epsilon);
500   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_tan, outputs.at(10), epsilon);
501   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_atan, outputs.at(11), epsilon);
502   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_sinh, outputs.at(12), 1E-08);
503   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_cosh, outputs.at(13), 1E-08);
504   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_tanh, outputs.at(14), epsilon);
505   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_atan2, outputs.at(15), epsilon);
506   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_cot, outputs.at(16), epsilon);
507   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_radians, outputs.at(17), epsilon);
508   EXPECT_ARROW_ARRAY_APPROX_EQUALS(expected_degrees, outputs.at(18), epsilon);
509 }
510 
TEST_F(TestProjector,TestFloatLessThan)511 TEST_F(TestProjector, TestFloatLessThan) {
512   // schema for input fields
513   auto field0 = field("f0", float32());
514   auto field1 = field("f2", float32());
515   auto schema = arrow::schema({field0, field1});
516 
517   // output fields
518   auto field_result = field("res", boolean());
519 
520   // Build expression
521   auto lt_expr =
522       TreeExprBuilder::MakeExpression("less_than", {field0, field1}, field_result);
523 
524   // Build a projector for the expressions.
525   std::shared_ptr<Projector> projector;
526   auto status = Projector::Make(schema, {lt_expr}, TestConfiguration(), &projector);
527   EXPECT_TRUE(status.ok());
528 
529   // Create a row-batch with some sample data
530   int num_records = 3;
531   auto array0 = MakeArrowArrayFloat32({1.0f, 8.9f, 3.0f}, {true, true, false});
532   auto array1 = MakeArrowArrayFloat32({4.0f, 3.4f, 6.8f}, {true, true, true});
533   // expected output
534   auto exp = MakeArrowArrayBool({true, false, false}, {true, true, false});
535 
536   // prepare input record batch
537   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
538 
539   // Evaluate expression
540   arrow::ArrayVector outputs;
541   status = projector->Evaluate(*in_batch, pool_, &outputs);
542   EXPECT_TRUE(status.ok());
543 
544   // Validate results
545   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
546 }
547 
TEST_F(TestProjector,TestIsNotNull)548 TEST_F(TestProjector, TestIsNotNull) {
549   // schema for input fields
550   auto field0 = field("f0", float32());
551   auto schema = arrow::schema({field0});
552 
553   // output fields
554   auto field_result = field("res", boolean());
555 
556   // Build expression
557   auto myexpr = TreeExprBuilder::MakeExpression("isnotnull", {field0}, field_result);
558 
559   // Build a projector for the expressions.
560   std::shared_ptr<Projector> projector;
561   auto status = Projector::Make(schema, {myexpr}, TestConfiguration(), &projector);
562   EXPECT_TRUE(status.ok());
563 
564   // Create a row-batch with some sample data
565   int num_records = 3;
566   auto array0 = MakeArrowArrayFloat32({1.0f, 8.9f, 3.0f}, {true, true, false});
567   // expected output
568   auto exp = MakeArrowArrayBool({true, true, false}, {true, true, true});
569 
570   // prepare input record batch
571   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
572 
573   // Evaluate expression
574   arrow::ArrayVector outputs;
575   status = projector->Evaluate(*in_batch, pool_, &outputs);
576   EXPECT_TRUE(status.ok());
577 
578   // Validate results
579   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
580 }
581 
TEST_F(TestProjector,TestZeroCopy)582 TEST_F(TestProjector, TestZeroCopy) {
583   // schema for input fields
584   auto field0 = field("f0", int32());
585   auto schema = arrow::schema({field0});
586 
587   // output fields
588   auto res = field("res", float32());
589 
590   // Build expression
591   auto cast_expr = TreeExprBuilder::MakeExpression("castFLOAT4", {field0}, res);
592 
593   std::shared_ptr<Projector> projector;
594   auto status = Projector::Make(schema, {cast_expr}, TestConfiguration(), &projector);
595   EXPECT_TRUE(status.ok());
596 
597   // Create a row-batch with some sample data
598   int num_records = 4;
599   auto array0 = MakeArrowArrayInt32({1, 2, 3, 4}, {true, true, true, false});
600   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
601 
602   // expected output
603   auto exp = MakeArrowArrayFloat32({1, 2, 3, 0}, {true, true, true, false});
604 
605   // allocate output buffers
606   int64_t bitmap_sz = arrow::BitUtil::BytesForBits(num_records);
607   int64_t bitmap_capacity = arrow::BitUtil::RoundUpToMultipleOf64(bitmap_sz);
608   std::vector<uint8_t> bitmap(bitmap_capacity);
609   std::shared_ptr<arrow::MutableBuffer> bitmap_buf =
610       std::make_shared<arrow::MutableBuffer>(&bitmap[0], bitmap_capacity);
611 
612   int64_t data_sz = sizeof(float) * num_records;
613   std::vector<uint8_t> data(bitmap_capacity);
614   std::shared_ptr<arrow::MutableBuffer> data_buf =
615       std::make_shared<arrow::MutableBuffer>(&data[0], data_sz);
616 
617   auto array_data =
618       arrow::ArrayData::Make(float32(), num_records, {bitmap_buf, data_buf});
619 
620   // Evaluate expression
621   status = projector->Evaluate(*in_batch, {array_data});
622   EXPECT_TRUE(status.ok());
623 
624   // Validate results
625   auto output = arrow::MakeArray(array_data);
626   EXPECT_ARROW_ARRAY_EQUALS(exp, output);
627 }
628 
TEST_F(TestProjector,TestZeroCopyNegative)629 TEST_F(TestProjector, TestZeroCopyNegative) {
630   // schema for input fields
631   auto field0 = field("f0", int32());
632   auto schema = arrow::schema({field0});
633 
634   // output fields
635   auto res = field("res", float32());
636 
637   // Build expression
638   auto cast_expr = TreeExprBuilder::MakeExpression("castFLOAT4", {field0}, res);
639 
640   std::shared_ptr<Projector> projector;
641   auto status = Projector::Make(schema, {cast_expr}, TestConfiguration(), &projector);
642   EXPECT_TRUE(status.ok());
643 
644   // Create a row-batch with some sample data
645   int num_records = 4;
646   auto array0 = MakeArrowArrayInt32({1, 2, 3, 4}, {true, true, true, false});
647   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
648 
649   // expected output
650   auto exp = MakeArrowArrayFloat32({1, 2, 3, 0}, {true, true, true, false});
651 
652   // allocate output buffers
653   int64_t bitmap_sz = arrow::BitUtil::BytesForBits(num_records);
654   std::unique_ptr<uint8_t[]> bitmap(new uint8_t[bitmap_sz]);
655   std::shared_ptr<arrow::MutableBuffer> bitmap_buf =
656       std::make_shared<arrow::MutableBuffer>(bitmap.get(), bitmap_sz);
657 
658   int64_t data_sz = sizeof(float) * num_records;
659   std::unique_ptr<uint8_t[]> data(new uint8_t[data_sz]);
660   std::shared_ptr<arrow::MutableBuffer> data_buf =
661       std::make_shared<arrow::MutableBuffer>(data.get(), data_sz);
662 
663   auto array_data =
664       arrow::ArrayData::Make(float32(), num_records, {bitmap_buf, data_buf});
665 
666   // the batch can't be empty.
667   auto bad_batch = arrow::RecordBatch::Make(schema, 0 /*num_records*/, {array0});
668   status = projector->Evaluate(*bad_batch, {array_data});
669   EXPECT_EQ(status.code(), StatusCode::Invalid);
670 
671   // the output array can't be null.
672   std::shared_ptr<arrow::ArrayData> null_array_data;
673   status = projector->Evaluate(*in_batch, {null_array_data});
674   EXPECT_EQ(status.code(), StatusCode::Invalid);
675 
676   // the output array must have at least two buffers.
677   auto bad_array_data = arrow::ArrayData::Make(float32(), num_records, {bitmap_buf});
678   status = projector->Evaluate(*in_batch, {bad_array_data});
679   EXPECT_EQ(status.code(), StatusCode::Invalid);
680 
681   // the output buffers must have sufficiently sized data_buf.
682   std::shared_ptr<arrow::MutableBuffer> bad_data_buf =
683       std::make_shared<arrow::MutableBuffer>(data.get(), data_sz - 1);
684   auto bad_array_data2 =
685       arrow::ArrayData::Make(float32(), num_records, {bitmap_buf, bad_data_buf});
686   status = projector->Evaluate(*in_batch, {bad_array_data2});
687   EXPECT_EQ(status.code(), StatusCode::Invalid);
688 
689   // the output buffers must have sufficiently sized bitmap_buf.
690   std::shared_ptr<arrow::MutableBuffer> bad_bitmap_buf =
691       std::make_shared<arrow::MutableBuffer>(bitmap.get(), bitmap_sz - 1);
692   auto bad_array_data3 =
693       arrow::ArrayData::Make(float32(), num_records, {bad_bitmap_buf, data_buf});
694   status = projector->Evaluate(*in_batch, {bad_array_data3});
695   EXPECT_EQ(status.code(), StatusCode::Invalid);
696 }
697 
TEST_F(TestProjector,TestDivideZero)698 TEST_F(TestProjector, TestDivideZero) {
699   // schema for input fields
700   auto field0 = field("f0", int32());
701   auto field1 = field("f2", int32());
702   auto schema = arrow::schema({field0, field1});
703 
704   // output fields
705   auto field_div = field("divide", int32());
706 
707   // Build expression
708   auto div_expr = TreeExprBuilder::MakeExpression("divide", {field0, field1}, field_div);
709 
710   std::shared_ptr<Projector> projector;
711   auto status = Projector::Make(schema, {div_expr}, TestConfiguration(), &projector);
712   EXPECT_TRUE(status.ok()) << status.message();
713 
714   // Create a row-batch with some sample data
715   int num_records = 5;
716   auto array0 = MakeArrowArrayInt32({2, 3, 4, 5, 6}, {true, true, true, true, true});
717   auto array1 = MakeArrowArrayInt32({1, 2, 2, 0, 0}, {true, true, false, true, true});
718 
719   // prepare input record batch
720   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
721 
722   // Evaluate expression
723   arrow::ArrayVector outputs;
724   status = projector->Evaluate(*in_batch, pool_, &outputs);
725   EXPECT_EQ(status.code(), StatusCode::ExecutionError);
726   std::string expected_error = "divide by zero error";
727   EXPECT_TRUE(status.message().find(expected_error) != std::string::npos);
728 
729   // Testing for second batch that has no error should succeed.
730   num_records = 5;
731   array0 = MakeArrowArrayInt32({2, 3, 4, 5, 6}, {true, true, true, true, true});
732   array1 = MakeArrowArrayInt32({1, 2, 2, 1, 1}, {true, true, false, true, true});
733 
734   // prepare input record batch
735   in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
736   // expected output
737   auto exp = MakeArrowArrayInt32({2, 1, 2, 5, 6}, {true, true, false, true, true});
738 
739   // Evaluate expression
740   status = projector->Evaluate(*in_batch, pool_, &outputs);
741   EXPECT_TRUE(status.ok());
742 
743   // Validate results
744   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
745 }
746 
TEST_F(TestProjector,TestModZero)747 TEST_F(TestProjector, TestModZero) {
748   // schema for input fields
749   auto field0 = field("f0", arrow::int64());
750   auto field1 = field("f2", int32());
751   auto schema = arrow::schema({field0, field1});
752 
753   // output fields
754   auto field_div = field("mod", int32());
755 
756   // Build expression
757   auto mod_expr = TreeExprBuilder::MakeExpression("mod", {field0, field1}, field_div);
758 
759   std::shared_ptr<Projector> projector;
760   auto status = Projector::Make(schema, {mod_expr}, TestConfiguration(), &projector);
761   EXPECT_TRUE(status.ok()) << status.message();
762 
763   // Create a row-batch with some sample data
764   int num_records = 4;
765   auto array0 = MakeArrowArrayInt64({2, 3, 4, 5}, {true, true, true, true});
766   auto array1 = MakeArrowArrayInt32({1, 2, 2, 0}, {true, true, false, true});
767   // expected output
768   auto exp_mod = MakeArrowArrayInt32({0, 1, 0, 5}, {true, true, false, true});
769 
770   // prepare input record batch
771   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
772 
773   // Evaluate expression
774   arrow::ArrayVector outputs;
775   status = projector->Evaluate(*in_batch, pool_, &outputs);
776   EXPECT_TRUE(status.ok()) << status.message();
777 
778   // Validate results
779   EXPECT_ARROW_ARRAY_EQUALS(exp_mod, outputs.at(0));
780 }
781 
TEST_F(TestProjector,TestConcat)782 TEST_F(TestProjector, TestConcat) {
783   // schema for input fields
784   auto field0 = field("f0", arrow::utf8());
785   auto field1 = field("f1", arrow::utf8());
786   auto schema = arrow::schema({field0, field1});
787 
788   // output fields
789   auto field_concat = field("concat", arrow::utf8());
790 
791   // Build expression
792   auto concat_expr =
793       TreeExprBuilder::MakeExpression("concat", {field0, field1}, field_concat);
794 
795   std::shared_ptr<Projector> projector;
796   auto status = Projector::Make(schema, {concat_expr}, TestConfiguration(), &projector);
797   EXPECT_TRUE(status.ok()) << status.message();
798 
799   // Create a row-batch with some sample data
800   int num_records = 6;
801   auto array0 = MakeArrowArrayUtf8({"ab", "", "ab", "invalid", "valid", "invalid"},
802                                    {true, true, true, false, true, false});
803   auto array1 = MakeArrowArrayUtf8({"cd", "cd", "", "valid", "invalid", "invalid"},
804                                    {true, true, true, true, false, false});
805   // expected output
806   auto exp_concat = MakeArrowArrayUtf8({"abcd", "cd", "ab", "valid", "valid", ""},
807                                        {true, true, true, true, true, true});
808 
809   // prepare input record batch
810   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
811 
812   // Evaluate expression
813   arrow::ArrayVector outputs;
814   status = projector->Evaluate(*in_batch, pool_, &outputs);
815   EXPECT_TRUE(status.ok()) << status.message();
816 
817   // Validate results
818   EXPECT_ARROW_ARRAY_EQUALS(exp_concat, outputs.at(0));
819 }
820 
TEST_F(TestProjector,TestBase64)821 TEST_F(TestProjector, TestBase64) {
822   // schema for input fields
823   auto field0 = field("f0", arrow::binary());
824   auto schema = arrow::schema({field0});
825 
826   // output fields
827   auto field_base = field("base64", arrow::utf8());
828 
829   // Build expression
830   auto base_expr = TreeExprBuilder::MakeExpression("base64", {field0}, field_base);
831 
832   std::shared_ptr<Projector> projector;
833   auto status = Projector::Make(schema, {base_expr}, TestConfiguration(), &projector);
834   EXPECT_TRUE(status.ok()) << status.message();
835 
836   // Create a row-batch with some sample data
837   int num_records = 4;
838   auto array0 =
839       MakeArrowArrayBinary({"hello", "", "test", "hive"}, {true, true, true, true});
840   // expected output
841   auto exp_base = MakeArrowArrayUtf8({"aGVsbG8=", "", "dGVzdA==", "aGl2ZQ=="},
842                                      {true, true, true, true});
843 
844   // prepare input record batch
845   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
846 
847   // Evaluate expression
848   arrow::ArrayVector outputs;
849   status = projector->Evaluate(*in_batch, pool_, &outputs);
850   EXPECT_TRUE(status.ok()) << status.message();
851 
852   // Validate results
853   EXPECT_ARROW_ARRAY_EQUALS(exp_base, outputs.at(0));
854 }
855 
TEST_F(TestProjector,TestUnbase64)856 TEST_F(TestProjector, TestUnbase64) {
857   // schema for input fields
858   auto field0 = field("f0", arrow::utf8());
859   auto schema = arrow::schema({field0});
860 
861   // output fields
862   auto field_base = field("base64", arrow::binary());
863 
864   // Build expression
865   auto base_expr = TreeExprBuilder::MakeExpression("unbase64", {field0}, field_base);
866 
867   std::shared_ptr<Projector> projector;
868   auto status = Projector::Make(schema, {base_expr}, TestConfiguration(), &projector);
869   EXPECT_TRUE(status.ok()) << status.message();
870 
871   // Create a row-batch with some sample data
872   int num_records = 4;
873   auto array0 = MakeArrowArrayUtf8({"aGVsbG8=", "", "dGVzdA==", "aGl2ZQ=="},
874                                    {true, true, true, true});
875   // expected output
876   auto exp_unbase =
877       MakeArrowArrayBinary({"hello", "", "test", "hive"}, {true, true, true, true});
878 
879   // prepare input record batch
880   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
881 
882   // Evaluate expression
883   arrow::ArrayVector outputs;
884   status = projector->Evaluate(*in_batch, pool_, &outputs);
885   EXPECT_TRUE(status.ok()) << status.message();
886 
887   // Validate results
888   EXPECT_ARROW_ARRAY_EQUALS(exp_unbase, outputs.at(0));
889 }
890 
TEST_F(TestProjector,TestLeftString)891 TEST_F(TestProjector, TestLeftString) {
892   // schema for input fields
893   auto field0 = field("f0", arrow::utf8());
894   auto field1 = field("f1", arrow::int32());
895   auto schema = arrow::schema({field0, field1});
896 
897   // output fields
898   auto field_concat = field("left", arrow::utf8());
899 
900   // Build expression
901   auto concat_expr =
902       TreeExprBuilder::MakeExpression("left", {field0, field1}, field_concat);
903 
904   std::shared_ptr<Projector> projector;
905   auto status = Projector::Make(schema, {concat_expr}, TestConfiguration(), &projector);
906   EXPECT_TRUE(status.ok()) << status.message();
907 
908   // Create a row-batch with some sample data
909   int num_records = 6;
910   auto array0 = MakeArrowArrayUtf8({"ab", "", "ab", "invalid", "valid", "invalid"},
911                                    {true, true, true, true, true, true});
912   auto array1 =
913       MakeArrowArrayInt32({1, 500, 2, -5, 5, 0}, {true, true, true, true, true, true});
914   // expected output
915   auto exp_left = MakeArrowArrayUtf8({"a", "", "ab", "in", "valid", ""},
916                                      {true, true, true, true, true, true});
917 
918   // prepare input record batch
919   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
920 
921   // Evaluate expression
922   arrow::ArrayVector outputs;
923   status = projector->Evaluate(*in_batch, pool_, &outputs);
924   EXPECT_TRUE(status.ok()) << status.message();
925 
926   // Validate results
927   EXPECT_ARROW_ARRAY_EQUALS(exp_left, outputs.at(0));
928 }
929 
TEST_F(TestProjector,TestRightString)930 TEST_F(TestProjector, TestRightString) {
931   // schema for input fields
932   auto field0 = field("f0", arrow::utf8());
933   auto field1 = field("f1", arrow::int32());
934   auto schema = arrow::schema({field0, field1});
935 
936   // output fields
937   auto field_concat = field("right", arrow::utf8());
938 
939   // Build expression
940   auto concat_expr =
941       TreeExprBuilder::MakeExpression("right", {field0, field1}, field_concat);
942 
943   std::shared_ptr<Projector> projector;
944   auto status = Projector::Make(schema, {concat_expr}, TestConfiguration(), &projector);
945   EXPECT_TRUE(status.ok()) << status.message();
946 
947   // Create a row-batch with some sample data
948   int num_records = 6;
949   auto array0 = MakeArrowArrayUtf8({"ab", "", "ab", "invalid", "valid", "invalid"},
950                                    {true, true, true, true, true, true});
951   auto array1 =
952       MakeArrowArrayInt32({1, 500, 2, -5, 5, 0}, {true, true, true, true, true, true});
953   // expected output
954   auto exp_left = MakeArrowArrayUtf8({"b", "", "ab", "id", "valid", ""},
955                                      {true, true, true, true, true, true});
956 
957   // prepare input record batch
958   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
959 
960   // Evaluate expression
961   arrow::ArrayVector outputs;
962   status = projector->Evaluate(*in_batch, pool_, &outputs);
963   EXPECT_TRUE(status.ok()) << status.message();
964 
965   // Validate results
966   EXPECT_ARROW_ARRAY_EQUALS(exp_left, outputs.at(0));
967 }
968 
TEST_F(TestProjector,TestOffset)969 TEST_F(TestProjector, TestOffset) {
970   // schema for input fields
971   auto field0 = field("f0", arrow::int32());
972   auto field1 = field("f1", arrow::int32());
973   auto schema = arrow::schema({field0, field1});
974 
975   // output fields
976   auto field_sum = field("sum", arrow::int32());
977 
978   // Build expression
979   auto sum_expr = TreeExprBuilder::MakeExpression("add", {field0, field1}, field_sum);
980 
981   std::shared_ptr<Projector> projector;
982   auto status = Projector::Make(schema, {sum_expr}, TestConfiguration(), &projector);
983   EXPECT_TRUE(status.ok()) << status.message();
984 
985   // Create a row-batch with some sample data
986   int num_records = 4;
987   auto array0 = MakeArrowArrayInt32({1, 2, 3, 4, 5}, {true, true, true, true, false});
988   array0 = array0->Slice(1);
989   auto array1 = MakeArrowArrayInt32({5, 6, 7, 8}, {true, false, true, true});
990   // expected output
991   auto exp_sum = MakeArrowArrayInt32({9, 11, 13}, {false, true, false});
992 
993   // prepare input record batch
994   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
995   in_batch = in_batch->Slice(1);
996 
997   // Evaluate expression
998   arrow::ArrayVector outputs;
999   status = projector->Evaluate(*in_batch, pool_, &outputs);
1000   EXPECT_TRUE(status.ok()) << status.message();
1001 
1002   // Validate results
1003   EXPECT_ARROW_ARRAY_EQUALS(exp_sum, outputs.at(0));
1004 }
1005 
TEST_F(TestProjector,TestByteSubString)1006 TEST_F(TestProjector, TestByteSubString) {
1007   // schema for input fields
1008   auto field0 = field("f0", arrow::binary());
1009   auto field1 = field("f1", arrow::int32());
1010   auto field2 = field("f2", arrow::int32());
1011   auto schema = arrow::schema({field0, field1, field2});
1012 
1013   // output fields
1014   auto field_byte_substr = field("bytesubstring", arrow::binary());
1015 
1016   // Build expression
1017   auto byte_substr_expr = TreeExprBuilder::MakeExpression(
1018       "bytesubstring", {field0, field1, field2}, field_byte_substr);
1019 
1020   std::shared_ptr<Projector> projector;
1021   auto status =
1022       Projector::Make(schema, {byte_substr_expr}, TestConfiguration(), &projector);
1023   EXPECT_TRUE(status.ok()) << status.message();
1024 
1025   // Create a row-batch with some sample data
1026   int num_records = 6;
1027   auto array0 = MakeArrowArrayBinary({"ab", "", "ab", "invalid", "valid", "invalid"},
1028                                      {true, true, true, true, true, true});
1029   auto array1 =
1030       MakeArrowArrayInt32({0, 1, 1, 1, 3, 3}, {true, true, true, true, true, true});
1031   auto array2 =
1032       MakeArrowArrayInt32({0, 1, 1, 2, 3, 3}, {true, true, true, true, true, true});
1033   // expected output
1034   auto exp_byte_substr = MakeArrowArrayBinary({"", "", "a", "in", "lid", "val"},
1035                                               {true, true, true, true, true, true});
1036 
1037   // prepare input record batch
1038   auto in = arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2});
1039 
1040   // Evaluate expression
1041   arrow::ArrayVector outputs;
1042   status = projector->Evaluate(*in, pool_, &outputs);
1043   EXPECT_TRUE(status.ok()) << status.message();
1044 
1045   // Validate results
1046   EXPECT_ARROW_ARRAY_EQUALS(exp_byte_substr, outputs.at(0));
1047 }
1048 
1049 // Test to ensure behaviour of cast functions when the validity is false for an input. The
1050 // function should not run for that input.
TEST_F(TestProjector,TestCastFunction)1051 TEST_F(TestProjector, TestCastFunction) {
1052   auto field0 = field("f0", arrow::utf8());
1053   auto schema = arrow::schema({field0});
1054 
1055   // output fields
1056   auto res_float4 = field("res_float4", arrow::float32());
1057   auto res_float8 = field("res_float8", arrow::float64());
1058   auto res_int4 = field("castINT", arrow::int32());
1059   auto res_int8 = field("castBIGINT", arrow::int64());
1060 
1061   // Build expression
1062   auto cast_expr_float4 =
1063       TreeExprBuilder::MakeExpression("castFLOAT4", {field0}, res_float4);
1064   auto cast_expr_float8 =
1065       TreeExprBuilder::MakeExpression("castFLOAT8", {field0}, res_float8);
1066   auto cast_expr_int4 = TreeExprBuilder::MakeExpression("castINT", {field0}, res_int4);
1067   auto cast_expr_int8 = TreeExprBuilder::MakeExpression("castBIGINT", {field0}, res_int8);
1068 
1069   std::shared_ptr<Projector> projector;
1070 
1071   //  {cast_expr_float4, cast_expr_float8, cast_expr_int4, cast_expr_int8}
1072   auto status = Projector::Make(
1073       schema, {cast_expr_float4, cast_expr_float8, cast_expr_int4, cast_expr_int8},
1074       TestConfiguration(), &projector);
1075   EXPECT_TRUE(status.ok());
1076 
1077   // Create a row-batch with some sample data
1078   int num_records = 4;
1079 
1080   // Last validity is false and the cast functions throw error when input is empty. Should
1081   // not be evaluated due to addition of NativeFunction::kCanReturnErrors
1082   auto array0 = MakeArrowArrayUtf8({"1", "2", "3", ""}, {true, true, true, false});
1083   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
1084 
1085   auto out_float4 = MakeArrowArrayFloat32({1, 2, 3, 0}, {true, true, true, false});
1086   auto out_float8 = MakeArrowArrayFloat64({1, 2, 3, 0}, {true, true, true, false});
1087   auto out_int4 = MakeArrowArrayInt32({1, 2, 3, 0}, {true, true, true, false});
1088   auto out_int8 = MakeArrowArrayInt64({1, 2, 3, 0}, {true, true, true, false});
1089 
1090   arrow::ArrayVector outputs;
1091 
1092   // Evaluate expression
1093   status = projector->Evaluate(*in_batch, pool_, &outputs);
1094   EXPECT_TRUE(status.ok());
1095 
1096   EXPECT_ARROW_ARRAY_EQUALS(out_float4, outputs.at(0));
1097   EXPECT_ARROW_ARRAY_EQUALS(out_float8, outputs.at(1));
1098   EXPECT_ARROW_ARRAY_EQUALS(out_int4, outputs.at(2));
1099   EXPECT_ARROW_ARRAY_EQUALS(out_int8, outputs.at(3));
1100 }
1101 
TEST_F(TestProjector,TestCastBitFunction)1102 TEST_F(TestProjector, TestCastBitFunction) {
1103   auto field0 = field("f0", arrow::utf8());
1104   auto schema = arrow::schema({field0});
1105 
1106   // output fields
1107   auto res_bit = field("res_bit", arrow::boolean());
1108 
1109   // Build expression
1110   auto cast_bit = TreeExprBuilder::MakeExpression("castBIT", {field0}, res_bit);
1111 
1112   std::shared_ptr<Projector> projector;
1113 
1114   auto status = Projector::Make(schema, {cast_bit}, TestConfiguration(), &projector);
1115   EXPECT_TRUE(status.ok());
1116 
1117   // Create a row-batch with some sample data
1118   int num_records = 4;
1119   auto arr = MakeArrowArrayUtf8({"1", "true", "false", "0"}, {true, true, true, true});
1120   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {arr});
1121 
1122   auto out = MakeArrowArrayBool({true, true, false, false}, {true, true, true, true});
1123 
1124   arrow::ArrayVector outputs;
1125 
1126   // Evaluate expression
1127   status = projector->Evaluate(*in_batch, pool_, &outputs);
1128   EXPECT_TRUE(status.ok());
1129 
1130   EXPECT_ARROW_ARRAY_EQUALS(out, outputs.at(0));
1131 }
1132 
1133 // Test to ensure behaviour of cast functions when the validity is false for an input. The
1134 // function should not run for that input.
TEST_F(TestProjector,TestCastVarbinaryFunction)1135 TEST_F(TestProjector, TestCastVarbinaryFunction) {
1136   auto field0 = field("f0", arrow::binary());
1137   auto schema = arrow::schema({field0});
1138 
1139   // output fields
1140   auto res_int4 = field("res_int4", arrow::int32());
1141   auto res_int8 = field("res_int8", arrow::int64());
1142   auto res_float4 = field("res_float4", arrow::float32());
1143   auto res_float8 = field("res_float8", arrow::float64());
1144 
1145   // Build expression
1146   auto cast_expr_int4 = TreeExprBuilder::MakeExpression("castINT", {field0}, res_int4);
1147   auto cast_expr_int8 = TreeExprBuilder::MakeExpression("castBIGINT", {field0}, res_int8);
1148   auto cast_expr_float4 =
1149       TreeExprBuilder::MakeExpression("castFLOAT4", {field0}, res_float4);
1150   auto cast_expr_float8 =
1151       TreeExprBuilder::MakeExpression("castFLOAT8", {field0}, res_float8);
1152 
1153   std::shared_ptr<Projector> projector;
1154 
1155   //  {cast_expr_float4, cast_expr_float8, cast_expr_int4, cast_expr_int8}
1156   auto status = Projector::Make(
1157       schema, {cast_expr_int4, cast_expr_int8, cast_expr_float4, cast_expr_float8},
1158       TestConfiguration(), &projector);
1159   EXPECT_TRUE(status.ok());
1160 
1161   // Create a row-batch with some sample data
1162   int num_records = 4;
1163 
1164   // Last validity is false and the cast functions throw error when input is empty. Should
1165   // not be evaluated due to addition of NativeFunction::kCanReturnErrors
1166   auto array0 =
1167       MakeArrowArrayBinary({"37", "-99999", "99999", "4"}, {true, true, true, false});
1168   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
1169 
1170   auto out_int4 = MakeArrowArrayInt32({37, -99999, 99999, 0}, {true, true, true, false});
1171   auto out_int8 = MakeArrowArrayInt64({37, -99999, 99999, 0}, {true, true, true, false});
1172   auto out_float4 =
1173       MakeArrowArrayFloat32({37, -99999, 99999, 0}, {true, true, true, false});
1174   auto out_float8 =
1175       MakeArrowArrayFloat64({37, -99999, 99999, 0}, {true, true, true, false});
1176 
1177   arrow::ArrayVector outputs;
1178 
1179   // Evaluate expression
1180   status = projector->Evaluate(*in_batch, pool_, &outputs);
1181   EXPECT_TRUE(status.ok());
1182 
1183   EXPECT_ARROW_ARRAY_EQUALS(out_int4, outputs.at(0));
1184   EXPECT_ARROW_ARRAY_EQUALS(out_int8, outputs.at(1));
1185   EXPECT_ARROW_ARRAY_EQUALS(out_float4, outputs.at(2));
1186   EXPECT_ARROW_ARRAY_EQUALS(out_float8, outputs.at(3));
1187 }
1188 
TEST_F(TestProjector,TestToDate)1189 TEST_F(TestProjector, TestToDate) {
1190   // schema for input fields
1191   auto field0 = field("f0", arrow::utf8());
1192   auto field_node = std::make_shared<FieldNode>(field0);
1193   auto schema = arrow::schema({field0});
1194 
1195   // output fields
1196   auto field_result = field("res", arrow::date64());
1197 
1198   auto pattern_node = std::make_shared<LiteralNode>(
1199       arrow::utf8(), LiteralHolder(std::string("YYYY-MM-DD")), false);
1200 
1201   // Build expression
1202   auto fn_node = TreeExprBuilder::MakeFunction("to_date", {field_node, pattern_node},
1203                                                arrow::date64());
1204   auto expr = TreeExprBuilder::MakeExpression(fn_node, field_result);
1205 
1206   // Build a projector for the expressions.
1207   std::shared_ptr<Projector> projector;
1208   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
1209   EXPECT_TRUE(status.ok());
1210 
1211   // Create a row-batch with some sample data
1212   int num_records = 3;
1213   auto array0 =
1214       MakeArrowArrayUtf8({"1986-12-01", "2012-12-01", "invalid"}, {true, true, false});
1215   // expected output
1216   auto exp = MakeArrowArrayDate64({533779200000, 1354320000000, 0}, {true, true, false});
1217 
1218   // prepare input record batch
1219   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
1220 
1221   // Evaluate expression
1222   arrow::ArrayVector outputs;
1223   status = projector->Evaluate(*in_batch, pool_, &outputs);
1224   EXPECT_TRUE(status.ok());
1225 
1226   // Validate results
1227   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
1228 }
1229 
1230 // ARROW-11617
TEST_F(TestProjector,TestIfElseOpt)1231 TEST_F(TestProjector, TestIfElseOpt) {
1232   // schema for input
1233   auto field0 = field("f0", int32());
1234   auto field1 = field("f1", int32());
1235   auto field2 = field("f2", int32());
1236   auto schema = arrow::schema({field0, field1, field2});
1237 
1238   auto f0 = std::make_shared<FieldNode>(field0);
1239   auto f1 = std::make_shared<FieldNode>(field1);
1240   auto f2 = std::make_shared<FieldNode>(field2);
1241 
1242   // output fields
1243   auto field_result = field("out", int32());
1244 
1245   // Expr - (f0, f1 - null; f2 non null)
1246   //
1247   // if (is not null(f0))
1248   // then f0
1249   // else add((
1250   //    if (is not null (f1))
1251   //    then f1
1252   //    else f2
1253   //  ), f1)
1254 
1255   auto cond_node_inner = TreeExprBuilder::MakeFunction("isnotnull", {f1}, boolean());
1256   auto if_node_inner = TreeExprBuilder::MakeIf(cond_node_inner, f1, f2, int32());
1257 
1258   auto cond_node_outer = TreeExprBuilder::MakeFunction("isnotnull", {f0}, boolean());
1259   auto else_node_outer =
1260       TreeExprBuilder::MakeFunction("add", {if_node_inner, f1}, int32());
1261 
1262   auto if_node_outer =
1263       TreeExprBuilder::MakeIf(cond_node_outer, f1, else_node_outer, int32());
1264   auto expr = TreeExprBuilder::MakeExpression(if_node_outer, field_result);
1265 
1266   // Build a projector for the expressions.
1267   std::shared_ptr<Projector> projector;
1268   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
1269   EXPECT_TRUE(status.ok());
1270 
1271   // Create a row-batch with some sample data
1272   int num_records = 1;
1273   auto array0 = MakeArrowArrayInt32({0}, {false});
1274   auto array1 = MakeArrowArrayInt32({0}, {false});
1275   auto array2 = MakeArrowArrayInt32({99}, {true});
1276   // expected output
1277   auto exp = MakeArrowArrayInt32({0}, {false});
1278 
1279   // prepare input record batch
1280   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2});
1281 
1282   // Evaluate expression
1283   arrow::ArrayVector outputs;
1284   status = projector->Evaluate(*in_batch, pool_, &outputs);
1285   EXPECT_TRUE(status.ok());
1286 
1287   // Validate results
1288   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
1289 }
1290 
TEST_F(TestProjector,TestRepeat)1291 TEST_F(TestProjector, TestRepeat) {
1292   // schema for input fields
1293   auto field0 = field("f0", arrow::utf8());
1294   auto field1 = field("f1", arrow::int32());
1295   auto schema = arrow::schema({field0, field1});
1296 
1297   // output fields
1298   auto field_repeat = field("repeat", arrow::utf8());
1299 
1300   // Build expression
1301   auto repeat_expr =
1302       TreeExprBuilder::MakeExpression("repeat", {field0, field1}, field_repeat);
1303 
1304   std::shared_ptr<Projector> projector;
1305   auto status = Projector::Make(schema, {repeat_expr}, TestConfiguration(), &projector);
1306   EXPECT_TRUE(status.ok()) << status.message();
1307 
1308   // Create a row-batch with some sample data
1309   int num_records = 5;
1310   auto array0 =
1311       MakeArrowArrayUtf8({"ab", "a", "car", "valid", ""}, {true, true, true, true, true});
1312   auto array1 = MakeArrowArrayInt32({2, 1, 3, 2, 10}, {true, true, true, true, true});
1313   // expected output
1314   auto exp_repeat = MakeArrowArrayUtf8({"abab", "a", "carcarcar", "validvalid", ""},
1315                                        {true, true, true, true, true});
1316 
1317   // prepare input record batch
1318   auto in = arrow::RecordBatch::Make(schema, num_records, {array0, array1});
1319 
1320   // Evaluate expression
1321   arrow::ArrayVector outputs;
1322   status = projector->Evaluate(*in, pool_, &outputs);
1323   EXPECT_TRUE(status.ok()) << status.message();
1324 
1325   // Validate results
1326   EXPECT_ARROW_ARRAY_EQUALS(exp_repeat, outputs.at(0));
1327 }
1328 
TEST_F(TestProjector,TestLpad)1329 TEST_F(TestProjector, TestLpad) {
1330   // schema for input fields
1331   auto field0 = field("f0", arrow::utf8());
1332   auto field1 = field("f1", arrow::int32());
1333   auto field2 = field("f2", arrow::utf8());
1334   auto schema = arrow::schema({field0, field1, field2});
1335 
1336   // output fields
1337   auto field_lpad = field("lpad", arrow::utf8());
1338 
1339   // Build expression
1340   auto lpad_expr =
1341       TreeExprBuilder::MakeExpression("lpad", {field0, field1, field2}, field_lpad);
1342 
1343   std::shared_ptr<Projector> projector;
1344   auto status = Projector::Make(schema, {lpad_expr}, TestConfiguration(), &projector);
1345   EXPECT_TRUE(status.ok()) << status.message();
1346 
1347   // Create a row-batch with some sample data
1348   int num_records = 7;
1349   auto array0 = MakeArrowArrayUtf8({"ab", "a", "ab", "invalid", "valid", "invalid", ""},
1350                                    {true, true, true, true, true, true, true});
1351   auto array1 = MakeArrowArrayInt32({1, 5, 3, 12, 0, 2, 10},
1352                                     {true, true, true, true, true, true, true});
1353   auto array2 = MakeArrowArrayUtf8({"z", "z", "c", "valid", "invalid", "invalid", ""},
1354                                    {true, true, true, true, true, true, true});
1355   // expected output
1356   auto exp_lpad = MakeArrowArrayUtf8({"a", "zzzza", "cab", "validinvalid", "", "in", ""},
1357                                      {true, true, true, true, true, true, true});
1358 
1359   // prepare input record batch
1360   auto in = arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2});
1361 
1362   // Evaluate expression
1363   arrow::ArrayVector outputs;
1364   status = projector->Evaluate(*in, pool_, &outputs);
1365   EXPECT_TRUE(status.ok()) << status.message();
1366 
1367   // Validate results
1368   EXPECT_ARROW_ARRAY_EQUALS(exp_lpad, outputs.at(0));
1369 }
1370 
TEST_F(TestProjector,TestRpad)1371 TEST_F(TestProjector, TestRpad) {
1372   // schema for input fields
1373   auto field0 = field("f0", arrow::utf8());
1374   auto field1 = field("f1", arrow::int32());
1375   auto field2 = field("f2", arrow::utf8());
1376   auto schema = arrow::schema({field0, field1, field2});
1377 
1378   // output fields
1379   auto field_rpad = field("rpad", arrow::utf8());
1380 
1381   // Build expression
1382   auto rpad_expr =
1383       TreeExprBuilder::MakeExpression("rpad", {field0, field1, field2}, field_rpad);
1384 
1385   std::shared_ptr<Projector> projector;
1386   auto status = Projector::Make(schema, {rpad_expr}, TestConfiguration(), &projector);
1387   EXPECT_TRUE(status.ok()) << status.message();
1388 
1389   // Create a row-batch with some sample data
1390   int num_records = 7;
1391   auto array0 = MakeArrowArrayUtf8({"ab", "a", "ab", "invalid", "valid", "invalid", ""},
1392                                    {true, true, true, true, true, true, true});
1393   auto array1 = MakeArrowArrayInt32({1, 5, 3, 12, 0, 2, 10},
1394                                     {true, true, true, true, true, true, true});
1395   auto array2 = MakeArrowArrayUtf8({"z", "z", "c", "valid", "invalid", "invalid", ""},
1396                                    {true, true, true, true, true, true, true});
1397   // expected output
1398   auto exp_rpad = MakeArrowArrayUtf8({"a", "azzzz", "abc", "invalidvalid", "", "in", ""},
1399                                      {true, true, true, true, true, true, true});
1400 
1401   // prepare input record batch
1402   auto in = arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2});
1403 
1404   // Evaluate expression
1405   arrow::ArrayVector outputs;
1406   status = projector->Evaluate(*in, pool_, &outputs);
1407   EXPECT_TRUE(status.ok()) << status.message();
1408 
1409   // Validate results
1410   EXPECT_ARROW_ARRAY_EQUALS(exp_rpad, outputs.at(0));
1411 }
1412 
TEST_F(TestProjector,TestBinRepresentation)1413 TEST_F(TestProjector, TestBinRepresentation) {
1414   // schema for input fields
1415   auto field0 = field("f0", arrow::int64());
1416   auto schema = arrow::schema({field0});
1417 
1418   // output fields
1419   auto field_result = field("bin", arrow::utf8());
1420 
1421   // Build expression
1422   auto myexpr = TreeExprBuilder::MakeExpression("bin", {field0}, field_result);
1423 
1424   // Build a projector for the expressions.
1425   std::shared_ptr<Projector> projector;
1426   auto status = Projector::Make(schema, {myexpr}, TestConfiguration(), &projector);
1427   EXPECT_TRUE(status.ok());
1428 
1429   // Create a row-batch with some sample data
1430   int num_records = 3;
1431   auto array0 = MakeArrowArrayInt64({7, -28550, 58117}, {true, true, true});
1432   // expected output
1433   auto exp = MakeArrowArrayUtf8(
1434       {"111", "1111111111111111111111111111111111111111111111111001000001111010",
1435        "1110001100000101"},
1436       {true, true, true});
1437 
1438   // prepare input record batch
1439   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
1440 
1441   // Evaluate expression
1442   arrow::ArrayVector outputs;
1443   status = projector->Evaluate(*in_batch, pool_, &outputs);
1444   EXPECT_TRUE(status.ok());
1445 
1446   // Validate results
1447   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
1448 }
1449 
TEST_F(TestProjector,TestBigIntCastFunction)1450 TEST_F(TestProjector, TestBigIntCastFunction) {
1451   // input fields
1452   auto field0 = field("f0", arrow::float32());
1453   auto field1 = field("f1", arrow::float64());
1454   auto field2 = field("f2", arrow::day_time_interval());
1455   auto field3 = field("f3", arrow::month_interval());
1456   auto schema = arrow::schema({field0, field1, field2, field3});
1457 
1458   // output fields
1459   auto res_int64 = field("res", arrow::int64());
1460 
1461   // Build expression
1462   auto cast_expr_float4 =
1463       TreeExprBuilder::MakeExpression("castBIGINT", {field0}, res_int64);
1464   auto cast_expr_float8 =
1465       TreeExprBuilder::MakeExpression("castBIGINT", {field1}, res_int64);
1466   auto cast_expr_day_interval =
1467       TreeExprBuilder::MakeExpression("castBIGINT", {field2}, res_int64);
1468   auto cast_expr_year_interval =
1469       TreeExprBuilder::MakeExpression("castBIGINT", {field3}, res_int64);
1470 
1471   std::shared_ptr<Projector> projector;
1472 
1473   //  {cast_expr_float4, cast_expr_float8, cast_expr_day_interval,
1474   //  cast_expr_year_interval}
1475   auto status = Projector::Make(schema,
1476                                 {cast_expr_float4, cast_expr_float8,
1477                                  cast_expr_day_interval, cast_expr_year_interval},
1478                                 TestConfiguration(), &projector);
1479   EXPECT_TRUE(status.ok());
1480 
1481   // Create a row-batch with some sample data
1482   int num_records = 4;
1483 
1484   // Last validity is false and the cast functions throw error when input is empty. Should
1485   // not be evaluated due to addition of NativeFunction::kCanReturnErrors
1486   auto array0 =
1487       MakeArrowArrayFloat32({6.6f, -6.6f, 9.999999f, 0}, {true, true, true, false});
1488   auto array1 =
1489       MakeArrowArrayFloat64({6.6, -6.6, 9.99999999999, 0}, {true, true, true, false});
1490   auto array2 = MakeArrowArrayInt64({100, 25, -0, 0}, {true, true, true, false});
1491   auto array3 = MakeArrowArrayInt32({25, -25, -0, 0}, {true, true, true, false});
1492   auto in_batch =
1493       arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2, array3});
1494 
1495   auto out_float4 = MakeArrowArrayInt64({7, -7, 10, 0}, {true, true, true, false});
1496   auto out_float8 = MakeArrowArrayInt64({7, -7, 10, 0}, {true, true, true, false});
1497   auto out_days_interval =
1498       MakeArrowArrayInt64({8640000000, 2160000000, 0, 0}, {true, true, true, false});
1499   auto out_year_interval = MakeArrowArrayInt64({2, -2, 0, 0}, {true, true, true, false});
1500 
1501   arrow::ArrayVector outputs;
1502 
1503   // Evaluate expression
1504   status = projector->Evaluate(*in_batch, pool_, &outputs);
1505   EXPECT_TRUE(status.ok());
1506 
1507   EXPECT_ARROW_ARRAY_EQUALS(out_float4, outputs.at(0));
1508   EXPECT_ARROW_ARRAY_EQUALS(out_float8, outputs.at(1));
1509   EXPECT_ARROW_ARRAY_EQUALS(out_days_interval, outputs.at(2));
1510   EXPECT_ARROW_ARRAY_EQUALS(out_year_interval, outputs.at(3));
1511 }
1512 
TEST_F(TestProjector,TestIntCastFunction)1513 TEST_F(TestProjector, TestIntCastFunction) {
1514   // input fields
1515   auto field0 = field("f0", arrow::float32());
1516   auto field1 = field("f1", arrow::float64());
1517   auto field2 = field("f2", arrow::month_interval());
1518   auto schema = arrow::schema({field0, field1, field2});
1519 
1520   // output fields
1521   auto res_int32 = field("res", arrow::int32());
1522 
1523   // Build expression
1524   auto cast_expr_float4 = TreeExprBuilder::MakeExpression("castINT", {field0}, res_int32);
1525   auto cast_expr_float8 = TreeExprBuilder::MakeExpression("castINT", {field1}, res_int32);
1526   auto cast_expr_year_interval =
1527       TreeExprBuilder::MakeExpression("castINT", {field2}, res_int32);
1528 
1529   std::shared_ptr<Projector> projector;
1530 
1531   //  {cast_expr_float4, cast_expr_float8, cast_expr_day_interval,
1532   //  cast_expr_year_interval}
1533   auto status = Projector::Make(
1534       schema, {cast_expr_float4, cast_expr_float8, cast_expr_year_interval},
1535       TestConfiguration(), &projector);
1536   EXPECT_TRUE(status.ok());
1537 
1538   // Create a row-batch with some sample data
1539   int num_records = 4;
1540 
1541   // Last validity is false and the cast functions throw error when input is empty. Should
1542   // not be evaluated due to addition of NativeFunction::kCanReturnErrors
1543   auto array0 =
1544       MakeArrowArrayFloat32({6.6f, -6.6f, 9.999999f, 0}, {true, true, true, false});
1545   auto array1 =
1546       MakeArrowArrayFloat64({6.6, -6.6, 9.99999999999, 0}, {true, true, true, false});
1547   auto array2 = MakeArrowArrayInt32({25, -25, -0, 0}, {true, true, true, false});
1548   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0, array1, array2});
1549 
1550   auto out_float4 = MakeArrowArrayInt32({7, -7, 10, 0}, {true, true, true, false});
1551   auto out_float8 = MakeArrowArrayInt32({7, -7, 10, 0}, {true, true, true, false});
1552   auto out_year_interval = MakeArrowArrayInt32({2, -2, 0, 0}, {true, true, true, false});
1553 
1554   arrow::ArrayVector outputs;
1555 
1556   // Evaluate expression
1557   status = projector->Evaluate(*in_batch, pool_, &outputs);
1558   EXPECT_TRUE(status.ok());
1559 
1560   EXPECT_ARROW_ARRAY_EQUALS(out_float4, outputs.at(0));
1561   EXPECT_ARROW_ARRAY_EQUALS(out_float8, outputs.at(1));
1562   EXPECT_ARROW_ARRAY_EQUALS(out_year_interval, outputs.at(2));
1563 }
1564 
TEST_F(TestProjector,TestCastNullableIntYearInterval)1565 TEST_F(TestProjector, TestCastNullableIntYearInterval) {
1566   // input fields
1567   auto field1 = field("f1", arrow::month_interval());
1568   auto schema = arrow::schema({field1});
1569 
1570   // output fields
1571   auto res_int32 = field("res", arrow::int32());
1572   auto res_int64 = field("res", arrow::int64());
1573 
1574   // Build expression
1575   auto cast_expr_int32 =
1576       TreeExprBuilder::MakeExpression("castNULLABLEINT", {field1}, res_int32);
1577   auto cast_expr_int64 =
1578       TreeExprBuilder::MakeExpression("castNULLABLEBIGINT", {field1}, res_int64);
1579 
1580   std::shared_ptr<Projector> projector;
1581 
1582   //  {cast_expr_int32, cast_expr_int64, cast_expr_day_interval,
1583   //  cast_expr_year_interval}
1584   auto status = Projector::Make(schema, {cast_expr_int32, cast_expr_int64},
1585                                 TestConfiguration(), &projector);
1586   EXPECT_TRUE(status.ok());
1587 
1588   // Create a row-batch with some sample data
1589   int num_records = 4;
1590 
1591   // Last validity is false and the cast functions throw error when input is empty. Should
1592   // not be evaluated due to addition of NativeFunction::kCanReturnErrors
1593   auto array0 = MakeArrowArrayInt32({12, -24, -0, 0}, {true, true, true, false});
1594   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array0});
1595 
1596   auto out_int32 = MakeArrowArrayInt32({1, -2, -0, 0}, {true, true, true, false});
1597   auto out_int64 = MakeArrowArrayInt64({1, -2, -0, 0}, {true, true, true, false});
1598 
1599   arrow::ArrayVector outputs;
1600 
1601   // Evaluate expression
1602   status = projector->Evaluate(*in_batch, pool_, &outputs);
1603   EXPECT_TRUE(status.ok());
1604 
1605   EXPECT_ARROW_ARRAY_EQUALS(out_int32, outputs.at(0));
1606   EXPECT_ARROW_ARRAY_EQUALS(out_int64, outputs.at(1));
1607 }
1608 
1609 }  // namespace gandiva
1610