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