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