1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements.  See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.  The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License.  You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied.  See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 #include <sstream>
19 
20 #include <gtest/gtest.h>
21 #include "arrow/memory_pool.h"
22 #include "arrow/status.h"
23 #include "arrow/util/decimal.h"
24 
25 #include "gandiva/decimal_type_util.h"
26 #include "gandiva/projector.h"
27 #include "gandiva/tests/test_util.h"
28 #include "gandiva/tree_expr_builder.h"
29 
30 using arrow::boolean;
31 using arrow::Decimal128;
32 using arrow::utf8;
33 
34 namespace gandiva {
35 
36 class TestDecimal : public ::testing::Test {
37  public:
SetUp()38   void SetUp() { pool_ = arrow::default_memory_pool(); }
39 
40   std::vector<Decimal128> MakeDecimalVector(std::vector<std::string> values,
41                                             int32_t scale);
42 
43  protected:
44   arrow::MemoryPool* pool_;
45 };
46 
MakeDecimalVector(std::vector<std::string> values,int32_t scale)47 std::vector<Decimal128> TestDecimal::MakeDecimalVector(std::vector<std::string> values,
48                                                        int32_t scale) {
49   std::vector<arrow::Decimal128> ret;
50   for (auto str : values) {
51     Decimal128 str_value;
52     int32_t str_precision;
53     int32_t str_scale;
54 
55     DCHECK_OK(Decimal128::FromString(str, &str_value, &str_precision, &str_scale));
56 
57     Decimal128 scaled_value;
58     if (str_scale == scale) {
59       scaled_value = str_value;
60     } else {
61       scaled_value = str_value.Rescale(str_scale, scale).ValueOrDie();
62     }
63     ret.push_back(scaled_value);
64   }
65   return ret;
66 }
67 
TEST_F(TestDecimal,TestSimple)68 TEST_F(TestDecimal, TestSimple) {
69   // schema for input fields
70   constexpr int32_t precision = 36;
71   constexpr int32_t scale = 18;
72   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
73   auto field_a = field("a", decimal_type);
74   auto field_b = field("b", decimal_type);
75   auto field_c = field("c", decimal_type);
76   auto schema = arrow::schema({field_a, field_b, field_c});
77 
78   Decimal128TypePtr add2_type;
79   auto status = DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd,
80                                                {decimal_type, decimal_type}, &add2_type);
81 
82   Decimal128TypePtr output_type;
83   status = DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd,
84                                           {add2_type, decimal_type}, &output_type);
85 
86   // output fields
87   auto res = field("res0", output_type);
88 
89   // build expression : a + b + c
90   auto node_a = TreeExprBuilder::MakeField(field_a);
91   auto node_b = TreeExprBuilder::MakeField(field_b);
92   auto node_c = TreeExprBuilder::MakeField(field_c);
93   auto add2 = TreeExprBuilder::MakeFunction("add", {node_a, node_b}, add2_type);
94   auto add3 = TreeExprBuilder::MakeFunction("add", {add2, node_c}, output_type);
95   auto expr = TreeExprBuilder::MakeExpression(add3, res);
96 
97   // Build a projector for the expression.
98   std::shared_ptr<Projector> projector;
99   status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
100   DCHECK_OK(status);
101 
102   // Create a row-batch with some sample data
103   int num_records = 4;
104   auto array_a =
105       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"1", "2", "3", "4"}, scale),
106                             {false, true, true, true});
107   auto array_b =
108       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"2", "3", "4", "5"}, scale),
109                             {false, true, true, true});
110   auto array_c =
111       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"3", "4", "5", "6"}, scale),
112                             {true, true, true, true});
113 
114   // prepare input record batch
115   auto in_batch =
116       arrow::RecordBatch::Make(schema, num_records, {array_a, array_b, array_c});
117 
118   auto expected =
119       MakeArrowArrayDecimal(output_type, MakeDecimalVector({"6", "9", "12", "15"}, scale),
120                             {false, true, true, true});
121 
122   // Evaluate expression
123   arrow::ArrayVector outputs;
124   status = projector->Evaluate(*in_batch, pool_, &outputs);
125   DCHECK_OK(status);
126 
127   // Validate results
128   EXPECT_ARROW_ARRAY_EQUALS(expected, outputs[0]);
129 }
130 
TEST_F(TestDecimal,TestLiteral)131 TEST_F(TestDecimal, TestLiteral) {
132   // schema for input fields
133   constexpr int32_t precision = 36;
134   constexpr int32_t scale = 18;
135   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
136   auto field_a = field("a", decimal_type);
137   auto schema = arrow::schema({
138       field_a,
139   });
140 
141   Decimal128TypePtr add2_type;
142   auto status = DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd,
143                                                {decimal_type, decimal_type}, &add2_type);
144 
145   // output fields
146   auto res = field("res0", add2_type);
147 
148   // build expression : a + b + c
149   auto node_a = TreeExprBuilder::MakeField(field_a);
150   static std::string decimal_point_six = "6";
151   DecimalScalar128 literal(decimal_point_six, 2, 1);
152   auto node_b = TreeExprBuilder::MakeDecimalLiteral(literal);
153   auto add2 = TreeExprBuilder::MakeFunction("add", {node_a, node_b}, add2_type);
154   auto expr = TreeExprBuilder::MakeExpression(add2, res);
155 
156   // Build a projector for the expression.
157   std::shared_ptr<Projector> projector;
158   status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
159   DCHECK_OK(status);
160 
161   // Create a row-batch with some sample data
162   int num_records = 4;
163   auto array_a =
164       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"1", "2", "3", "4"}, scale),
165                             {false, true, true, true});
166 
167   // prepare input record batch
168   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
169 
170   auto expected = MakeArrowArrayDecimal(
171       add2_type, MakeDecimalVector({"1.6", "2.6", "3.6", "4.6"}, scale),
172       {false, true, true, true});
173 
174   // Evaluate expression
175   arrow::ArrayVector outputs;
176   status = projector->Evaluate(*in_batch, pool_, &outputs);
177   DCHECK_OK(status);
178 
179   // Validate results
180   EXPECT_ARROW_ARRAY_EQUALS(expected, outputs[0]);
181 }
182 
TEST_F(TestDecimal,TestIfElse)183 TEST_F(TestDecimal, TestIfElse) {
184   // schema for input fields
185   constexpr int32_t precision = 36;
186   constexpr int32_t scale = 18;
187   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
188   auto field_a = field("a", decimal_type);
189   auto field_b = field("b", decimal_type);
190   auto field_c = field("c", arrow::boolean());
191   auto schema = arrow::schema({field_a, field_b, field_c});
192 
193   // output fields
194   auto field_result = field("res", decimal_type);
195 
196   // build expression.
197   // if (c)
198   //   a
199   // else
200   //   b
201   auto node_a = TreeExprBuilder::MakeField(field_a);
202   auto node_b = TreeExprBuilder::MakeField(field_b);
203   auto node_c = TreeExprBuilder::MakeField(field_c);
204   auto if_node = TreeExprBuilder::MakeIf(node_c, node_a, node_b, decimal_type);
205 
206   auto expr = TreeExprBuilder::MakeExpression(if_node, field_result);
207 
208   // Build a projector for the expressions.
209   std::shared_ptr<Projector> projector;
210   Status status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
211   DCHECK_OK(status);
212 
213   // Create a row-batch with some sample data
214   int num_records = 4;
215   auto array_a =
216       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"1", "2", "3", "4"}, scale),
217                             {false, true, true, true});
218   auto array_b =
219       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"2", "3", "4", "5"}, scale),
220                             {true, true, true, true});
221 
222   auto array_c = MakeArrowArrayBool({true, false, true, false}, {true, true, true, true});
223 
224   // expected output
225   auto exp =
226       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"0", "3", "3", "5"}, scale),
227                             {false, true, true, true});
228 
229   // prepare input record batch
230   auto in_batch =
231       arrow::RecordBatch::Make(schema, num_records, {array_a, array_b, array_c});
232 
233   // Evaluate expression
234   arrow::ArrayVector outputs;
235   status = projector->Evaluate(*in_batch, pool_, &outputs);
236   DCHECK_OK(status);
237 
238   // Validate results
239   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
240 }
241 
TEST_F(TestDecimal,TestCompare)242 TEST_F(TestDecimal, TestCompare) {
243   // schema for input fields
244   constexpr int32_t precision = 36;
245   constexpr int32_t scale = 18;
246   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
247   auto field_a = field("a", decimal_type);
248   auto field_b = field("b", decimal_type);
249   auto schema = arrow::schema({field_a, field_b});
250 
251   // build expressions
252   auto exprs = std::vector<ExpressionPtr>{
253       TreeExprBuilder::MakeExpression("equal", {field_a, field_b},
254                                       field("res_eq", boolean())),
255       TreeExprBuilder::MakeExpression("not_equal", {field_a, field_b},
256                                       field("res_ne", boolean())),
257       TreeExprBuilder::MakeExpression("less_than", {field_a, field_b},
258                                       field("res_lt", boolean())),
259       TreeExprBuilder::MakeExpression("less_than_or_equal_to", {field_a, field_b},
260                                       field("res_le", boolean())),
261       TreeExprBuilder::MakeExpression("greater_than", {field_a, field_b},
262                                       field("res_gt", boolean())),
263       TreeExprBuilder::MakeExpression("greater_than_or_equal_to", {field_a, field_b},
264                                       field("res_ge", boolean())),
265   };
266 
267   // Build a projector for the expression.
268   std::shared_ptr<Projector> projector;
269   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
270   DCHECK_OK(status);
271 
272   // Create a row-batch with some sample data
273   int num_records = 4;
274   auto array_a =
275       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"1", "2", "3", "-4"}, scale),
276                             {true, true, true, true});
277   auto array_b =
278       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"1", "3", "2", "-3"}, scale),
279                             {true, true, true, true});
280 
281   // prepare input record batch
282   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a, array_b});
283 
284   // Evaluate expression
285   arrow::ArrayVector outputs;
286   status = projector->Evaluate(*in_batch, pool_, &outputs);
287   DCHECK_OK(status);
288 
289   // Validate results
290   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, false, false, false}),
291                             outputs[0]);  // equal
292   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({false, true, true, true}),
293                             outputs[1]);  // not_equal
294   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({false, true, false, true}),
295                             outputs[2]);  // less_than
296   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, true, false, true}),
297                             outputs[3]);  // less_than_or_equal_to
298   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({false, false, true, false}),
299                             outputs[4]);  // greater_than
300   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, false, true, false}),
301                             outputs[5]);  // greater_than_or_equal_to
302 }
303 
304 // ARROW-9092: This test is conditionally disabled when building with LLVM 9
305 // because it hangs.
306 #if GANDIVA_LLVM_VERSION != 9
307 
TEST_F(TestDecimal,TestRoundFunctions)308 TEST_F(TestDecimal, TestRoundFunctions) {
309   // schema for input fields
310   constexpr int32_t precision = 38;
311   constexpr int32_t scale = 2;
312   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
313   auto field_a = field("a", decimal_type);
314   auto schema = arrow::schema({field_a});
315 
316   auto scale_1 = TreeExprBuilder::MakeLiteral(1);
317 
318   // build expressions
319   auto exprs = std::vector<ExpressionPtr>{
320       TreeExprBuilder::MakeExpression("abs", {field_a}, field("res_abs", decimal_type)),
321       TreeExprBuilder::MakeExpression("ceil", {field_a},
322                                       field("res_ceil", arrow::decimal(precision, 0))),
323       TreeExprBuilder::MakeExpression("floor", {field_a},
324                                       field("res_floor", arrow::decimal(precision, 0))),
325       TreeExprBuilder::MakeExpression("round", {field_a},
326                                       field("res_round", arrow::decimal(precision, 0))),
327       TreeExprBuilder::MakeExpression(
328           "truncate", {field_a}, field("res_truncate", arrow::decimal(precision, 0))),
329 
330       TreeExprBuilder::MakeExpression(
331           TreeExprBuilder::MakeFunction("round",
332                                         {TreeExprBuilder::MakeField(field_a), scale_1},
333                                         arrow::decimal(precision, 1)),
334           field("res_round_3", arrow::decimal(precision, 1))),
335 
336       TreeExprBuilder::MakeExpression(
337           TreeExprBuilder::MakeFunction("truncate",
338                                         {TreeExprBuilder::MakeField(field_a), scale_1},
339                                         arrow::decimal(precision, 1)),
340           field("res_truncate_3", arrow::decimal(precision, 1))),
341   };
342 
343   // Build a projector for the expression.
344   std::shared_ptr<Projector> projector;
345   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
346   DCHECK_OK(status);
347 
348   // Create a row-batch with some sample data
349   int num_records = 4;
350   auto validity = {true, true, true, true};
351   auto array_a = MakeArrowArrayDecimal(
352       decimal_type, MakeDecimalVector({"1.23", "1.58", "-1.23", "-1.58"}, scale),
353       validity);
354 
355   // prepare input record batch
356   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
357 
358   // Evaluate expression
359   arrow::ArrayVector outputs;
360   status = projector->Evaluate(*in_batch, pool_, &outputs);
361   DCHECK_OK(status);
362 
363   // Validate results
364 
365   // abs(x)
366   EXPECT_ARROW_ARRAY_EQUALS(
367       MakeArrowArrayDecimal(decimal_type,
368                             MakeDecimalVector({"1.23", "1.58", "1.23", "1.58"}, scale),
369                             validity),
370       outputs[0]);
371 
372   // ceil(x)
373   EXPECT_ARROW_ARRAY_EQUALS(
374       MakeArrowArrayDecimal(arrow::decimal(precision, 0),
375                             MakeDecimalVector({"2", "2", "-1", "-1"}, 0), validity),
376       outputs[1]);
377 
378   // floor(x)
379   EXPECT_ARROW_ARRAY_EQUALS(
380       MakeArrowArrayDecimal(arrow::decimal(precision, 0),
381                             MakeDecimalVector({"1", "1", "-2", "-2"}, 0), validity),
382       outputs[2]);
383 
384   // round(x)
385   EXPECT_ARROW_ARRAY_EQUALS(
386       MakeArrowArrayDecimal(arrow::decimal(precision, 0),
387                             MakeDecimalVector({"1", "2", "-1", "-2"}, 0), validity),
388       outputs[3]);
389 
390   // truncate(x)
391   EXPECT_ARROW_ARRAY_EQUALS(
392       MakeArrowArrayDecimal(arrow::decimal(precision, 0),
393                             MakeDecimalVector({"1", "1", "-1", "-1"}, 0), validity),
394       outputs[4]);
395 
396   // round(x, 1)
397   EXPECT_ARROW_ARRAY_EQUALS(
398       MakeArrowArrayDecimal(arrow::decimal(precision, 1),
399                             MakeDecimalVector({"1.2", "1.6", "-1.2", "-1.6"}, 1),
400                             validity),
401       outputs[5]);
402 
403   // truncate(x, 1)
404   EXPECT_ARROW_ARRAY_EQUALS(
405       MakeArrowArrayDecimal(arrow::decimal(precision, 1),
406                             MakeDecimalVector({"1.2", "1.5", "-1.2", "-1.5"}, 1),
407                             validity),
408       outputs[6]);
409 }
410 
411 #endif  // GANDIVA_LLVM_VERSION != 9
412 
TEST_F(TestDecimal,TestCastFunctions)413 TEST_F(TestDecimal, TestCastFunctions) {
414   // schema for input fields
415   constexpr int32_t precision = 38;
416   constexpr int32_t scale = 2;
417   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
418   auto decimal_type_scale_1 = std::make_shared<arrow::Decimal128Type>(precision, 1);
419   auto field_int32 = field("int32", arrow::int32());
420   auto field_int64 = field("int64", arrow::int64());
421   auto field_float32 = field("float32", arrow::float32());
422   auto field_float64 = field("float64", arrow::float64());
423   auto field_dec = field("dec", decimal_type);
424   auto schema =
425       arrow::schema({field_int32, field_int64, field_float32, field_float64, field_dec});
426 
427   // build expressions
428   auto exprs = std::vector<ExpressionPtr>{
429       TreeExprBuilder::MakeExpression("castDECIMAL", {field_int32},
430                                       field("int32_to_dec", decimal_type)),
431       TreeExprBuilder::MakeExpression("castDECIMAL", {field_int64},
432                                       field("int64_to_dec", decimal_type)),
433       TreeExprBuilder::MakeExpression("castDECIMAL", {field_float32},
434                                       field("float32_to_dec", decimal_type)),
435       TreeExprBuilder::MakeExpression("castDECIMAL", {field_float64},
436                                       field("float64_to_dec", decimal_type)),
437       TreeExprBuilder::MakeExpression("castDECIMAL", {field_dec},
438                                       field("dec_to_dec", decimal_type_scale_1)),
439       TreeExprBuilder::MakeExpression("castBIGINT", {field_dec},
440                                       field("dec_to_int64", arrow::int64())),
441       TreeExprBuilder::MakeExpression("castFLOAT8", {field_dec},
442                                       field("dec_to_float64", arrow::float64())),
443   };
444 
445   // Build a projector for the expression.
446   std::shared_ptr<Projector> projector;
447   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
448   DCHECK_OK(status);
449 
450   // Create a row-batch with some sample data
451   int num_records = 4;
452   auto validity = {true, true, true, true};
453 
454   auto array_int32 = MakeArrowArrayInt32({123, 158, -123, -158});
455   auto array_int64 = MakeArrowArrayInt64({123, 158, -123, -158});
456   auto array_float32 = MakeArrowArrayFloat32({1.23f, 1.58f, -1.23f, -1.58f});
457   auto array_float64 = MakeArrowArrayFloat64({1.23, 1.58, -1.23, -1.58});
458   auto array_dec = MakeArrowArrayDecimal(
459       decimal_type, MakeDecimalVector({"1.23", "1.58", "-1.23", "-1.58"}, scale),
460       validity);
461 
462   // prepare input record batch
463   auto in_batch = arrow::RecordBatch::Make(
464       schema, num_records,
465       {array_int32, array_int64, array_float32, array_float64, array_dec});
466 
467   // Evaluate expression
468   arrow::ArrayVector outputs;
469   status = projector->Evaluate(*in_batch, pool_, &outputs);
470   DCHECK_OK(status);
471 
472   // Validate results
473   auto expected_int_dec = MakeArrowArrayDecimal(
474       decimal_type, MakeDecimalVector({"123", "158", "-123", "-158"}, scale), validity);
475 
476   // castDECIMAL(int32)
477   EXPECT_ARROW_ARRAY_EQUALS(expected_int_dec, outputs[0]);
478 
479   // castDECIMAL(int64)
480   EXPECT_ARROW_ARRAY_EQUALS(expected_int_dec, outputs[1]);
481 
482   // castDECIMAL(float32)
483   EXPECT_ARROW_ARRAY_EQUALS(array_dec, outputs[2]);
484 
485   // castDECIMAL(float64)
486   EXPECT_ARROW_ARRAY_EQUALS(array_dec, outputs[3]);
487 
488   // castDECIMAL(decimal)
489   EXPECT_ARROW_ARRAY_EQUALS(
490       MakeArrowArrayDecimal(arrow::decimal(precision, 1),
491                             MakeDecimalVector({"1.2", "1.6", "-1.2", "-1.6"}, 1),
492                             validity),
493       outputs[4]);
494 
495   // castBIGINT(decimal)
496   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayInt64({1, 2, -1, -2}), outputs[5]);
497 
498   // castDOUBLE(decimal)
499   EXPECT_ARROW_ARRAY_EQUALS(array_float64, outputs[6]);
500 }
501 
502 // isnull, isnumeric
TEST_F(TestDecimal,TestIsNullNumericFunctions)503 TEST_F(TestDecimal, TestIsNullNumericFunctions) {
504   // schema for input fields
505   constexpr int32_t precision = 38;
506   constexpr int32_t scale = 2;
507   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
508   auto field_dec = field("dec", decimal_type);
509   auto schema = arrow::schema({field_dec});
510 
511   // build expressions
512   auto exprs = std::vector<ExpressionPtr>{
513       TreeExprBuilder::MakeExpression("isnull", {field_dec},
514                                       field("isnull", arrow::boolean())),
515 
516       TreeExprBuilder::MakeExpression("isnotnull", {field_dec},
517                                       field("isnotnull", arrow::boolean())),
518       TreeExprBuilder::MakeExpression("isnumeric", {field_dec},
519                                       field("isnumeric", arrow::boolean()))};
520 
521   // Build a projector for the expression.
522   std::shared_ptr<Projector> projector;
523   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
524   DCHECK_OK(status);
525 
526   // Create a row-batch with some sample data
527   int num_records = 5;
528   auto validity = {false, true, true, true, false};
529 
530   auto array_dec = MakeArrowArrayDecimal(
531       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
532       validity);
533 
534   // prepare input record batch
535   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_dec});
536 
537   // Evaluate expression
538   arrow::ArrayVector outputs;
539   status = projector->Evaluate(*in_batch, pool_, &outputs);
540   DCHECK_OK(status);
541 
542   // Validate results
543   auto is_null = outputs.at(0);
544   auto is_not_null = outputs.at(1);
545   auto is_numeric = outputs.at(2);
546 
547   // isnull
548   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, false, false, false, true}),
549                             outputs[0]);
550 
551   // isnotnull
552   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool(validity), outputs[1]);
553 
554   // isnumeric
555   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool(validity), outputs[2]);
556 }
557 
TEST_F(TestDecimal,TestIsDistinct)558 TEST_F(TestDecimal, TestIsDistinct) {
559   // schema for input fields
560   constexpr int32_t precision = 38;
561   constexpr int32_t scale_1 = 2;
562   auto decimal_type_1 = std::make_shared<arrow::Decimal128Type>(precision, scale_1);
563   auto field_dec_1 = field("dec_1", decimal_type_1);
564   constexpr int32_t scale_2 = 1;
565   auto decimal_type_2 = std::make_shared<arrow::Decimal128Type>(precision, scale_2);
566   auto field_dec_2 = field("dec_2", decimal_type_2);
567 
568   auto schema = arrow::schema({field_dec_1, field_dec_2});
569 
570   // build expressions
571   auto exprs = std::vector<ExpressionPtr>{
572       TreeExprBuilder::MakeExpression("is_distinct_from", {field_dec_1, field_dec_2},
573                                       field("isdistinct", arrow::boolean())),
574 
575       TreeExprBuilder::MakeExpression("is_not_distinct_from", {field_dec_1, field_dec_2},
576                                       field("isnotdistinct", arrow::boolean()))};
577 
578   // Build a projector for the expression.
579   std::shared_ptr<Projector> projector;
580   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
581   DCHECK_OK(status);
582 
583   // Create a row-batch with some sample data
584   int num_records = 4;
585 
586   auto validity_1 = {true, false, true, true};
587   auto array_dec_1 = MakeArrowArrayDecimal(
588       decimal_type_1, MakeDecimalVector({"1.51", "1.23", "1.20", "-1.20"}, scale_1),
589       validity_1);
590 
591   auto validity_2 = {true, false, false, true};
592   auto array_dec_2 = MakeArrowArrayDecimal(
593       decimal_type_2, MakeDecimalVector({"1.5", "1.2", "1.2", "-1.2"}, scale_2),
594       validity_2);
595 
596   // prepare input record batch
597   auto in_batch =
598       arrow::RecordBatch::Make(schema, num_records, {array_dec_1, array_dec_2});
599 
600   // Evaluate expression
601   arrow::ArrayVector outputs;
602   status = projector->Evaluate(*in_batch, pool_, &outputs);
603   DCHECK_OK(status);
604 
605   // Validate results
606   auto is_distinct = std::dynamic_pointer_cast<arrow::BooleanArray>(outputs.at(0));
607   auto is_not_distinct = std::dynamic_pointer_cast<arrow::BooleanArray>(outputs.at(1));
608 
609   // isdistinct
610   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, false, true, false}), outputs[0]);
611 
612   // isnotdistinct
613   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({false, true, false, true}), outputs[1]);
614 }
615 
616 // decimal hashes without seed
TEST_F(TestDecimal,TestHashFunctions)617 TEST_F(TestDecimal, TestHashFunctions) {
618   // schema for input fields
619   constexpr int32_t precision = 38;
620   constexpr int32_t scale = 2;
621   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
622   auto field_dec = field("dec", decimal_type);
623   auto literal_seed32 = TreeExprBuilder::MakeLiteral((int32_t)10);
624   auto literal_seed64 = TreeExprBuilder::MakeLiteral((int64_t)10);
625   auto schema = arrow::schema({field_dec});
626 
627   // build expressions
628   auto exprs = std::vector<ExpressionPtr>{
629       TreeExprBuilder::MakeExpression("hash", {field_dec},
630                                       field("hash_of_dec", arrow::int32())),
631 
632       TreeExprBuilder::MakeExpression("hash64", {field_dec},
633                                       field("hash64_of_dec", arrow::int64())),
634 
635       TreeExprBuilder::MakeExpression("hash32AsDouble", {field_dec},
636                                       field("hash32_as_double", arrow::int32())),
637 
638       TreeExprBuilder::MakeExpression("hash64AsDouble", {field_dec},
639                                       field("hash64_as_double", arrow::int64()))};
640 
641   // Build a projector for the expression.
642   std::shared_ptr<Projector> projector;
643   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
644   DCHECK_OK(status);
645 
646   // Create a row-batch with some sample data
647   int num_records = 5;
648   auto validity = {false, true, true, true, true};
649 
650   auto array_dec = MakeArrowArrayDecimal(
651       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
652       validity);
653 
654   // prepare input record batch
655   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_dec});
656 
657   // Evaluate expression
658   arrow::ArrayVector outputs;
659   status = projector->Evaluate(*in_batch, pool_, &outputs);
660   DCHECK_OK(status);
661 
662   // Validate results
663   auto int32_arr = std::dynamic_pointer_cast<arrow::Int32Array>(outputs.at(0));
664   EXPECT_EQ(int32_arr->null_count(), 0);
665   EXPECT_EQ(int32_arr->Value(0), 0);
666   EXPECT_EQ(int32_arr->Value(1), int32_arr->Value(2));
667   EXPECT_NE(int32_arr->Value(2), int32_arr->Value(3));
668   EXPECT_NE(int32_arr->Value(3), int32_arr->Value(4));
669 
670   auto int64_arr = std::dynamic_pointer_cast<arrow::Int64Array>(outputs.at(1));
671   EXPECT_EQ(int64_arr->null_count(), 0);
672   EXPECT_EQ(int64_arr->Value(0), 0);
673   EXPECT_EQ(int64_arr->Value(1), int64_arr->Value(2));
674   EXPECT_NE(int64_arr->Value(2), int64_arr->Value(3));
675   EXPECT_NE(int64_arr->Value(3), int64_arr->Value(4));
676 }
677 
TEST_F(TestDecimal,TestHash32WithSeed)678 TEST_F(TestDecimal, TestHash32WithSeed) {
679   constexpr int32_t precision = 38;
680   constexpr int32_t scale = 2;
681   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
682   auto field_dec_1 = field("dec1", decimal_type);
683   auto field_dec_2 = field("dec2", decimal_type);
684   auto schema = arrow::schema({field_dec_1, field_dec_2});
685 
686   auto res = field("hash32_with_seed", arrow::int32());
687 
688   auto field_1_nodePtr = TreeExprBuilder::MakeField(field_dec_1);
689   auto field_2_nodePtr = TreeExprBuilder::MakeField(field_dec_2);
690 
691   auto hash32 =
692       TreeExprBuilder::MakeFunction("hash32", {field_2_nodePtr}, arrow::int32());
693   auto hash32_with_seed =
694       TreeExprBuilder::MakeFunction("hash32", {field_1_nodePtr, hash32}, arrow::int32());
695   auto expr = TreeExprBuilder::MakeExpression(hash32, field("hash32", arrow::int32()));
696   auto exprWS = TreeExprBuilder::MakeExpression(hash32_with_seed, res);
697 
698   auto exprs = std::vector<ExpressionPtr>{expr, exprWS};
699 
700   // Build a projector for the expression.
701   std::shared_ptr<Projector> projector;
702   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
703   DCHECK_OK(status);
704 
705   // Create a row-batch with some sample data
706   int num_records = 5;
707   auto validity_1 = {false, false, true, true, true};
708 
709   auto array_dec_1 = MakeArrowArrayDecimal(
710       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
711       validity_1);
712 
713   auto validity_2 = {false, true, false, true, true};
714 
715   auto array_dec_2 = MakeArrowArrayDecimal(
716       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
717       validity_2);
718 
719   // prepare input record batch
720   auto in_batch =
721       arrow::RecordBatch::Make(schema, num_records, {array_dec_1, array_dec_2});
722 
723   // Evaluate expression
724   arrow::ArrayVector outputs;
725   status = projector->Evaluate(*in_batch, pool_, &outputs);
726   DCHECK_OK(status);
727 
728   // Validate results
729   auto int32_arr = std::dynamic_pointer_cast<arrow::Int32Array>(outputs.at(0));
730   auto int32_arr_WS = std::dynamic_pointer_cast<arrow::Int32Array>(outputs.at(1));
731   EXPECT_EQ(int32_arr->null_count(), 0);
732   // seed 0, null decimal
733   EXPECT_EQ(int32_arr_WS->Value(0), 0);
734   // null decimal => hash = seed
735   EXPECT_EQ(int32_arr_WS->Value(1), int32_arr->Value(1));
736   // seed = 0 => hash = hash without seed
737   EXPECT_EQ(int32_arr_WS->Value(2), int32_arr->Value(1));
738   // different inputs => different outputs
739   EXPECT_NE(int32_arr_WS->Value(3), int32_arr_WS->Value(4));
740   // hash with, without seed are not equal
741   EXPECT_NE(int32_arr_WS->Value(4), int32_arr->Value(4));
742 }
743 
TEST_F(TestDecimal,TestHash64WithSeed)744 TEST_F(TestDecimal, TestHash64WithSeed) {
745   constexpr int32_t precision = 38;
746   constexpr int32_t scale = 2;
747   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
748   auto field_dec_1 = field("dec1", decimal_type);
749   auto field_dec_2 = field("dec2", decimal_type);
750   auto schema = arrow::schema({field_dec_1, field_dec_2});
751 
752   auto res = field("hash64_with_seed", arrow::int64());
753 
754   auto field_1_nodePtr = TreeExprBuilder::MakeField(field_dec_1);
755   auto field_2_nodePtr = TreeExprBuilder::MakeField(field_dec_2);
756 
757   auto hash64 =
758       TreeExprBuilder::MakeFunction("hash64", {field_2_nodePtr}, arrow::int64());
759   auto hash64_with_seed =
760       TreeExprBuilder::MakeFunction("hash64", {field_1_nodePtr, hash64}, arrow::int64());
761   auto expr = TreeExprBuilder::MakeExpression(hash64, field("hash64", arrow::int64()));
762   auto exprWS = TreeExprBuilder::MakeExpression(hash64_with_seed, res);
763 
764   auto exprs = std::vector<ExpressionPtr>{expr, exprWS};
765 
766   // Build a projector for the expression.
767   std::shared_ptr<Projector> projector;
768   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
769   DCHECK_OK(status);
770 
771   // Create a row-batch with some sample data
772   int num_records = 5;
773   auto validity_1 = {false, false, true, true, true};
774 
775   auto array_dec_1 = MakeArrowArrayDecimal(
776       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
777       validity_1);
778 
779   auto validity_2 = {false, true, false, true, true};
780 
781   auto array_dec_2 = MakeArrowArrayDecimal(
782       decimal_type, MakeDecimalVector({"1.51", "1.23", "1.23", "-1.23", "-1.24"}, scale),
783       validity_2);
784 
785   // prepare input record batch
786   auto in_batch =
787       arrow::RecordBatch::Make(schema, num_records, {array_dec_1, array_dec_2});
788 
789   // Evaluate expression
790   arrow::ArrayVector outputs;
791   status = projector->Evaluate(*in_batch, pool_, &outputs);
792   DCHECK_OK(status);
793 
794   // Validate results
795   auto int64_arr = std::dynamic_pointer_cast<arrow::Int64Array>(outputs.at(0));
796   auto int64_arr_WS = std::dynamic_pointer_cast<arrow::Int64Array>(outputs.at(1));
797   EXPECT_EQ(int64_arr->null_count(), 0);
798   // seed 0, null decimal
799   EXPECT_EQ(int64_arr_WS->Value(0), 0);
800   // null decimal => hash = seed
801   EXPECT_EQ(int64_arr_WS->Value(1), int64_arr->Value(1));
802   // seed = 0 => hash = hash without seed
803   EXPECT_EQ(int64_arr_WS->Value(2), int64_arr->Value(1));
804   // different inputs => different outputs
805   EXPECT_NE(int64_arr_WS->Value(3), int64_arr_WS->Value(4));
806   // hash with, without seed are not equal
807   EXPECT_NE(int64_arr_WS->Value(4), int64_arr->Value(4));
808 }
809 
TEST_F(TestDecimal,TestNullDecimalConstant)810 TEST_F(TestDecimal, TestNullDecimalConstant) {
811   // schema for input fields
812   constexpr int32_t precision = 36;
813   constexpr int32_t scale = 18;
814   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
815   auto field_b = field("b", decimal_type);
816   auto field_c = field("c", arrow::boolean());
817   auto schema = arrow::schema({field_b, field_c});
818 
819   // output fields
820   auto field_result = field("res", decimal_type);
821 
822   // build expression.
823   // if (c)
824   //   null
825   // else
826   //   b
827   auto node_a = TreeExprBuilder::MakeNull(decimal_type);
828   auto node_b = TreeExprBuilder::MakeField(field_b);
829   auto node_c = TreeExprBuilder::MakeField(field_c);
830   auto if_node = TreeExprBuilder::MakeIf(node_c, node_a, node_b, decimal_type);
831 
832   auto expr = TreeExprBuilder::MakeExpression(if_node, field_result);
833 
834   // Build a projector for the expressions.
835   std::shared_ptr<Projector> projector;
836   Status status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
837   DCHECK_OK(status);
838 
839   // Create a row-batch with some sample data
840   int num_records = 4;
841 
842   auto array_b =
843       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"2", "3", "4", "5"}, scale),
844                             {true, true, true, true});
845 
846   auto array_c = MakeArrowArrayBool({true, false, true, false}, {true, true, true, true});
847 
848   // expected output
849   auto exp =
850       MakeArrowArrayDecimal(decimal_type, MakeDecimalVector({"0", "3", "3", "5"}, scale),
851                             {false, true, false, true});
852 
853   // prepare input record batch
854   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_b, array_c});
855 
856   // Evaluate expression
857   arrow::ArrayVector outputs;
858   status = projector->Evaluate(*in_batch, pool_, &outputs);
859   DCHECK_OK(status);
860 
861   // Validate results
862   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
863 }
864 
TEST_F(TestDecimal,TestCastVarCharDecimal)865 TEST_F(TestDecimal, TestCastVarCharDecimal) {
866   // schema for input fields
867   constexpr int32_t precision = 38;
868   constexpr int32_t scale = 2;
869   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
870 
871   auto field_dec = field("dec", decimal_type);
872   auto field_res_str = field("res_str", utf8());
873   auto field_res_str_1 = field("res_str_1", utf8());
874   auto schema = arrow::schema({field_dec, field_res_str, field_res_str_1});
875 
876   // output fields
877   auto res_str = field("res_str", utf8());
878   auto equals_res_bool = field("equals_res", boolean());
879 
880   // build expressions.
881   auto node_dec = TreeExprBuilder::MakeField(field_dec);
882   auto node_res_str = TreeExprBuilder::MakeField(field_res_str);
883   auto node_res_str_1 = TreeExprBuilder::MakeField(field_res_str_1);
884   // limits decimal string to input length
885   auto str_len_limit = TreeExprBuilder::MakeLiteral(static_cast<int64_t>(5));
886   auto str_len_limit_1 = TreeExprBuilder::MakeLiteral(static_cast<int64_t>(1));
887   auto cast_varchar =
888       TreeExprBuilder::MakeFunction("castVARCHAR", {node_dec, str_len_limit}, utf8());
889   auto cast_varchar_1 =
890       TreeExprBuilder::MakeFunction("castVARCHAR", {node_dec, str_len_limit_1}, utf8());
891   auto equals =
892       TreeExprBuilder::MakeFunction("equal", {cast_varchar, node_res_str}, boolean());
893   auto equals_1 =
894       TreeExprBuilder::MakeFunction("equal", {cast_varchar_1, node_res_str_1}, boolean());
895   auto expr = TreeExprBuilder::MakeExpression(equals, equals_res_bool);
896   auto expr_1 = TreeExprBuilder::MakeExpression(equals_1, equals_res_bool);
897 
898   // Build a projector for the expressions.
899   std::shared_ptr<Projector> projector;
900 
901   auto status = Projector::Make(schema, {expr, expr_1}, TestConfiguration(), &projector);
902   EXPECT_TRUE(status.ok()) << status.message();
903 
904   // Create a row-batch with some sample data
905   int num_records = 5;
906   auto array_dec = MakeArrowArrayDecimal(
907       decimal_type,
908       MakeDecimalVector({"10.51", "1.23", "100.23", "-1000.23", "-0000.10"}, scale),
909       {true, false, true, true, true});
910   auto array_str_res = MakeArrowArrayUtf8({"10.51", "-null-", "100.2", "-1000", "-0.10"},
911                                           {true, false, true, true, true});
912   auto array_str_res_1 =
913       MakeArrowArrayUtf8({"1", "-null-", "1", "-", "-"}, {true, false, true, true, true});
914   // prepare input record batch
915   auto in_batch = arrow::RecordBatch::Make(schema, num_records,
916                                            {array_dec, array_str_res, array_str_res_1});
917 
918   // Evaluate expression
919   arrow::ArrayVector outputs;
920   status = projector->Evaluate(*in_batch, pool_, &outputs);
921   EXPECT_TRUE(status.ok()) << status.message();
922 
923   auto exp = MakeArrowArrayBool({true, false, true, true, true},
924                                 {true, false, true, true, true});
925   auto exp_1 = MakeArrowArrayBool({true, false, true, true, true},
926                                   {true, false, true, true, true});
927   // Validate results
928   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs[0]);
929   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs[1]);
930 }
931 
TEST_F(TestDecimal,TestCastDecimalVarChar)932 TEST_F(TestDecimal, TestCastDecimalVarChar) {
933   // schema for input fields
934   constexpr int32_t precision = 4;
935   constexpr int32_t scale = 2;
936   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
937 
938   auto field_str = field("in_str", utf8());
939   auto schema = arrow::schema({field_str});
940 
941   // output fields
942   auto res_dec = field("res_dec", decimal_type);
943 
944   // build expressions.
945   auto node_str = TreeExprBuilder::MakeField(field_str);
946   auto cast_decimal =
947       TreeExprBuilder::MakeFunction("castDECIMAL", {node_str}, decimal_type);
948   auto expr = TreeExprBuilder::MakeExpression(cast_decimal, res_dec);
949 
950   // Build a projector for the expressions.
951   std::shared_ptr<Projector> projector;
952 
953   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
954   EXPECT_TRUE(status.ok()) << status.message();
955 
956   // Create a row-batch with some sample data
957   int num_records = 5;
958 
959   auto array_str = MakeArrowArrayUtf8({"10.5134", "-0.0", "-0.1", "10.516", "-1000"},
960                                       {true, false, true, true, true});
961 
962   // prepare input record batch
963   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_str});
964 
965   // Evaluate expression
966   arrow::ArrayVector outputs;
967   status = projector->Evaluate(*in_batch, pool_, &outputs);
968   EXPECT_TRUE(status.ok()) << status.message();
969 
970   auto array_dec = MakeArrowArrayDecimal(
971       decimal_type, MakeDecimalVector({"10.51", "1.23", "-0.10", "10.52", "0.00"}, scale),
972       {true, false, true, true, true});
973   // Validate results
974   EXPECT_ARROW_ARRAY_EQUALS(array_dec, outputs[0]);
975 }
976 
TEST_F(TestDecimal,TestCastDecimalVarCharInvalidInput)977 TEST_F(TestDecimal, TestCastDecimalVarCharInvalidInput) {
978   // schema for input fields
979   constexpr int32_t precision = 38;
980   constexpr int32_t scale = 0;
981   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
982 
983   auto field_str = field("in_str", utf8());
984   auto schema = arrow::schema({field_str});
985 
986   // output fields
987   auto res_dec = field("res_dec", decimal_type);
988 
989   // build expressions.
990   auto node_str = TreeExprBuilder::MakeField(field_str);
991   auto cast_decimal =
992       TreeExprBuilder::MakeFunction("castDECIMAL", {node_str}, decimal_type);
993   auto expr = TreeExprBuilder::MakeExpression(cast_decimal, res_dec);
994 
995   // Build a projector for the expressions.
996   std::shared_ptr<Projector> projector;
997 
998   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
999   EXPECT_TRUE(status.ok()) << status.message();
1000 
1001   // Create a row-batch with some sample data
1002   int num_records = 5;
1003 
1004   // invalid input
1005   auto invalid_in = MakeArrowArrayUtf8({"a10.5134", "-0.0", "-0.1", "10.516", "-1000"},
1006                                        {true, false, true, true, true});
1007 
1008   // prepare input record batch
1009   auto in_batch_1 = arrow::RecordBatch::Make(schema, num_records, {invalid_in});
1010 
1011   // Evaluate expression
1012   arrow::ArrayVector outputs_1;
1013   status = projector->Evaluate(*in_batch_1, pool_, &outputs_1);
1014   EXPECT_FALSE(status.ok()) << status.message();
1015   EXPECT_NE(status.message().find("not a valid decimal128 number"), std::string::npos);
1016 }
1017 
TEST_F(TestDecimal,TestVarCharDecimalNestedCast)1018 TEST_F(TestDecimal, TestVarCharDecimalNestedCast) {
1019   // schema for input fields
1020   constexpr int32_t precision = 38;
1021   constexpr int32_t scale = 2;
1022   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
1023 
1024   auto field_dec = field("dec", decimal_type);
1025   auto schema = arrow::schema({field_dec});
1026 
1027   // output fields
1028   auto field_dec_res = field("dec_res", decimal_type);
1029 
1030   // build expressions.
1031   auto node_dec = TreeExprBuilder::MakeField(field_dec);
1032 
1033   // limits decimal string to input length
1034   auto str_len_limit = TreeExprBuilder::MakeLiteral(static_cast<int64_t>(5));
1035   auto cast_varchar =
1036       TreeExprBuilder::MakeFunction("castVARCHAR", {node_dec, str_len_limit}, utf8());
1037   auto cast_decimal =
1038       TreeExprBuilder::MakeFunction("castDECIMAL", {cast_varchar}, decimal_type);
1039 
1040   auto expr = TreeExprBuilder::MakeExpression(cast_decimal, field_dec_res);
1041 
1042   // Build a projector for the expressions.
1043   std::shared_ptr<Projector> projector;
1044 
1045   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
1046   EXPECT_TRUE(status.ok()) << status.message();
1047 
1048   // Create a row-batch with some sample data
1049   int num_records = 5;
1050   auto array_dec = MakeArrowArrayDecimal(
1051       decimal_type,
1052       MakeDecimalVector({"10.51", "1.23", "100.23", "-1000.23", "-0000.10"}, scale),
1053       {true, false, true, true, true});
1054 
1055   // prepare input record batch
1056   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_dec});
1057 
1058   // Evaluate expression
1059   arrow::ArrayVector outputs;
1060   status = projector->Evaluate(*in_batch, pool_, &outputs);
1061   EXPECT_TRUE(status.ok()) << status.message();
1062 
1063   // Validate results
1064   auto array_dec_res = MakeArrowArrayDecimal(
1065       decimal_type,
1066       MakeDecimalVector({"10.51", "1.23", "100.20", "-1000.00", "-0.10"}, scale),
1067       {true, false, true, true, true});
1068   EXPECT_ARROW_ARRAY_EQUALS(array_dec_res, outputs[0]);
1069 }
1070 
TEST_F(TestDecimal,TestCastDecimalOverflow)1071 TEST_F(TestDecimal, TestCastDecimalOverflow) {
1072   // schema for input fields
1073   constexpr int32_t precision_in = 5;
1074   constexpr int32_t scale_in = 2;
1075   constexpr int32_t precision_out = 3;
1076   constexpr int32_t scale_out = 1;
1077   auto decimal_5_2 = std::make_shared<arrow::Decimal128Type>(precision_in, scale_in);
1078   auto decimal_3_1 = std::make_shared<arrow::Decimal128Type>(precision_out, scale_out);
1079 
1080   auto field_dec = field("dec", decimal_5_2);
1081   auto schema = arrow::schema({field_dec});
1082 
1083   // build expressions
1084   auto exprs = std::vector<ExpressionPtr>{
1085       TreeExprBuilder::MakeExpression("castDECIMAL", {field_dec},
1086                                       field("dec_to_dec", decimal_3_1)),
1087       TreeExprBuilder::MakeExpression("castDECIMALNullOnOverflow", {field_dec},
1088                                       field("dec_to_dec_null_overflow", decimal_3_1)),
1089   };
1090 
1091   // Build a projector for the expression.
1092   std::shared_ptr<Projector> projector;
1093   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
1094   DCHECK_OK(status);
1095 
1096   // Create a row-batch with some sample data
1097   int num_records = 4;
1098   auto validity = {true, true, true, true};
1099 
1100   auto array_dec = MakeArrowArrayDecimal(
1101       decimal_5_2, MakeDecimalVector({"1.23", "671.58", "-1.23", "-1.58"}, scale_in),
1102       validity);
1103 
1104   // prepare input record batch
1105   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_dec});
1106 
1107   // Evaluate expression
1108   arrow::ArrayVector outputs;
1109   status = projector->Evaluate(*in_batch, pool_, &outputs);
1110   DCHECK_OK(status);
1111 
1112   // Validate results
1113   // castDECIMAL(decimal)
1114   EXPECT_ARROW_ARRAY_EQUALS(
1115       MakeArrowArrayDecimal(arrow::decimal(precision_out, 1),
1116                             MakeDecimalVector({"1.2", "0.0", "-1.2", "-1.6"}, 1),
1117                             validity),
1118       outputs[0]);
1119 
1120   // castDECIMALNullOnOverflow(decimal)
1121   EXPECT_ARROW_ARRAY_EQUALS(
1122       MakeArrowArrayDecimal(arrow::decimal(precision_out, 1),
1123                             MakeDecimalVector({"1.2", "1.6", "-1.2", "-1.6"}, 1),
1124                             {true, false, true, true}),
1125       outputs[1]);
1126 }
1127 
TEST_F(TestDecimal,TestSha)1128 TEST_F(TestDecimal, TestSha) {
1129   // schema for input fields
1130   const std::shared_ptr<arrow::DataType>& decimal_5_2 = arrow::decimal128(5, 2);
1131   auto field_a = field("a", decimal_5_2);
1132   auto schema = arrow::schema({field_a});
1133 
1134   // output fields
1135   auto res_0 = field("res0", utf8());
1136   auto res_1 = field("res1", utf8());
1137 
1138   // build expressions.
1139   // hashSHA1(a)
1140   auto node_a = TreeExprBuilder::MakeField(field_a);
1141   auto hashSha1 = TreeExprBuilder::MakeFunction("hashSHA1", {node_a}, utf8());
1142   auto expr_0 = TreeExprBuilder::MakeExpression(hashSha1, res_0);
1143 
1144   auto hashSha256 = TreeExprBuilder::MakeFunction("hashSHA256", {node_a}, utf8());
1145   auto expr_1 = TreeExprBuilder::MakeExpression(hashSha256, res_1);
1146 
1147   // Build a projector for the expressions.
1148   std::shared_ptr<Projector> projector;
1149   auto status =
1150       Projector::Make(schema, {expr_0, expr_1}, TestConfiguration(), &projector);
1151   ASSERT_OK(status) << status.message();
1152 
1153   // Create a row-batch with some sample data
1154   int num_records = 3;
1155   auto validity_array = {false, true, true};
1156 
1157   auto array_dec = MakeArrowArrayDecimal(
1158       decimal_5_2, MakeDecimalVector({"3.45", "0", "0.01"}, 2), validity_array);
1159 
1160   // prepare input record batch
1161   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_dec});
1162 
1163   // Evaluate expression
1164   arrow::ArrayVector outputs;
1165   status = projector->Evaluate(*in_batch, pool_, &outputs);
1166   ASSERT_OK(status);
1167 
1168   auto response = outputs.at(0);
1169   EXPECT_EQ(response->null_count(), 0);
1170   EXPECT_NE(response->GetScalar(0).ValueOrDie()->ToString(), "");
1171 
1172   // Checks if the hash size in response is correct
1173   const int sha1_hash_size = 40;
1174   for (int i = 1; i < num_records; ++i) {
1175     const auto& value_at_position = response->GetScalar(i).ValueOrDie()->ToString();
1176 
1177     EXPECT_EQ(value_at_position.size(), sha1_hash_size);
1178     EXPECT_NE(value_at_position, response->GetScalar(i - 1).ValueOrDie()->ToString());
1179   }
1180 
1181   response = outputs.at(1);
1182   EXPECT_EQ(response->null_count(), 0);
1183   EXPECT_NE(response->GetScalar(0).ValueOrDie()->ToString(), "");
1184 
1185   // Checks if the hash size in response is correct
1186   const int sha256_hash_size = 64;
1187   for (int i = 1; i < num_records; ++i) {
1188     const auto& value_at_position = response->GetScalar(i).ValueOrDie()->ToString();
1189 
1190     EXPECT_EQ(value_at_position.size(), sha256_hash_size);
1191     EXPECT_NE(value_at_position, response->GetScalar(i - 1).ValueOrDie()->ToString());
1192   }
1193 }
1194 }  // namespace gandiva
1195