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 <gtest/gtest.h>
19 #include "arrow/memory_pool.h"
20 #include "arrow/status.h"
21 
22 #include "gandiva/projector.h"
23 #include "gandiva/tests/test_util.h"
24 #include "gandiva/tree_expr_builder.h"
25 
26 namespace gandiva {
27 
28 using arrow::boolean;
29 using arrow::date64;
30 using arrow::int32;
31 using arrow::int64;
32 using arrow::utf8;
33 
34 class TestUtf8 : public ::testing::Test {
35  public:
SetUp()36   void SetUp() { pool_ = arrow::default_memory_pool(); }
37 
38  protected:
39   arrow::MemoryPool* pool_;
40 };
41 
TEST_F(TestUtf8,TestSimple)42 TEST_F(TestUtf8, TestSimple) {
43   // schema for input fields
44   auto field_a = field("a", utf8());
45   auto schema = arrow::schema({field_a});
46 
47   // output fields
48   auto res_1 = field("res1", int32());
49   auto res_2 = field("res2", boolean());
50   auto res_3 = field("res3", int32());
51 
52   // build expressions.
53   // octet_length(a)
54   // octet_length(a) == bit_length(a) / 8
55   // length(a)
56   auto expr_a = TreeExprBuilder::MakeExpression("octet_length", {field_a}, res_1);
57 
58   auto node_a = TreeExprBuilder::MakeField(field_a);
59   auto octet_length = TreeExprBuilder::MakeFunction("octet_length", {node_a}, int32());
60   auto literal_8 = TreeExprBuilder::MakeLiteral((int32_t)8);
61   auto bit_length = TreeExprBuilder::MakeFunction("bit_length", {node_a}, int32());
62   auto div_8 = TreeExprBuilder::MakeFunction("divide", {bit_length, literal_8}, int32());
63   auto is_equal =
64       TreeExprBuilder::MakeFunction("equal", {octet_length, div_8}, boolean());
65   auto expr_b = TreeExprBuilder::MakeExpression(is_equal, res_2);
66   auto expr_c = TreeExprBuilder::MakeExpression("length", {field_a}, res_3);
67 
68   // Build a projector for the expressions.
69   std::shared_ptr<Projector> projector;
70   auto status =
71       Projector::Make(schema, {expr_a, expr_b, expr_c}, TestConfiguration(), &projector);
72   EXPECT_TRUE(status.ok()) << status.message();
73 
74   // Create a row-batch with some sample data
75   int num_records = 5;
76   auto array_a = MakeArrowArrayUtf8({"foo", "hello", "bye", "hi", "मदन"},
77                                     {true, true, false, true, true});
78 
79   // expected output
80   auto exp_1 = MakeArrowArrayInt32({3, 5, 0, 2, 9}, {true, true, false, true, true});
81   auto exp_2 = MakeArrowArrayBool({true, true, false, true, true},
82                                   {true, true, false, true, true});
83   auto exp_3 = MakeArrowArrayInt32({3, 5, 0, 2, 3}, {true, true, false, true, true});
84 
85   // prepare input record batch
86   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
87 
88   // Evaluate expression
89   arrow::ArrayVector outputs;
90   status = projector->Evaluate(*in_batch, pool_, &outputs);
91   EXPECT_TRUE(status.ok());
92 
93   // Validate results
94   EXPECT_ARROW_ARRAY_EQUALS(exp_1, outputs.at(0));
95   EXPECT_ARROW_ARRAY_EQUALS(exp_2, outputs.at(1));
96   EXPECT_ARROW_ARRAY_EQUALS(exp_3, outputs.at(2));
97 }
98 
TEST_F(TestUtf8,TestLiteral)99 TEST_F(TestUtf8, TestLiteral) {
100   // schema for input fields
101   auto field_a = field("a", utf8());
102   auto schema = arrow::schema({field_a});
103 
104   // output fields
105   auto res = field("res", boolean());
106 
107   // build expressions.
108   // a == literal(s)
109 
110   auto node_a = TreeExprBuilder::MakeField(field_a);
111   auto literal_s = TreeExprBuilder::MakeStringLiteral("hello");
112   auto is_equal = TreeExprBuilder::MakeFunction("equal", {node_a, literal_s}, boolean());
113   auto expr = TreeExprBuilder::MakeExpression(is_equal, res);
114 
115   // Build a projector for the expressions.
116   std::shared_ptr<Projector> projector;
117   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
118   EXPECT_TRUE(status.ok()) << status.message();
119 
120   // Create a row-batch with some sample data
121   int num_records = 4;
122   auto array_a =
123       MakeArrowArrayUtf8({"foo", "hello", "bye", "hi"}, {true, true, true, false});
124 
125   // expected output
126   auto exp = MakeArrowArrayBool({false, true, false, false}, {true, true, true, false});
127 
128   // prepare input record batch
129   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
130 
131   // Evaluate expression
132   arrow::ArrayVector outputs;
133   status = projector->Evaluate(*in_batch, pool_, &outputs);
134   EXPECT_TRUE(status.ok());
135 
136   // Validate results
137   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
138 }
139 
TEST_F(TestUtf8,TestNullLiteral)140 TEST_F(TestUtf8, TestNullLiteral) {
141   // schema for input fields
142   auto field_a = field("a", utf8());
143   auto schema = arrow::schema({field_a});
144 
145   // output fields
146   auto res = field("res", boolean());
147 
148   // build expressions.
149   // a == literal(null)
150 
151   auto node_a = TreeExprBuilder::MakeField(field_a);
152   auto literal_null = TreeExprBuilder::MakeNull(arrow::utf8());
153   auto is_equal =
154       TreeExprBuilder::MakeFunction("equal", {node_a, literal_null}, boolean());
155   auto expr = TreeExprBuilder::MakeExpression(is_equal, res);
156 
157   // Build a projector for the expressions.
158   std::shared_ptr<Projector> projector;
159   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
160   EXPECT_TRUE(status.ok()) << status.message();
161 
162   // Create a row-batch with some sample data
163   int num_records = 4;
164   auto array_a =
165       MakeArrowArrayUtf8({"foo", "hello", "bye", "hi"}, {true, true, true, false});
166 
167   // expected output
168   auto exp =
169       MakeArrowArrayBool({false, false, false, false}, {false, false, false, false});
170 
171   // prepare input record batch
172   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
173 
174   // Evaluate expression
175   arrow::ArrayVector outputs;
176   status = projector->Evaluate(*in_batch, pool_, &outputs);
177   EXPECT_TRUE(status.ok());
178 
179   // Validate results
180   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
181 }
182 
TEST_F(TestUtf8,TestLike)183 TEST_F(TestUtf8, TestLike) {
184   // schema for input fields
185   auto field_a = field("a", utf8());
186   auto schema = arrow::schema({field_a});
187 
188   // output fields
189   auto res = field("res", boolean());
190 
191   // build expressions.
192   // like(literal(s), a)
193 
194   auto node_a = TreeExprBuilder::MakeField(field_a);
195   auto literal_s = TreeExprBuilder::MakeStringLiteral("%spark%");
196   auto is_like = TreeExprBuilder::MakeFunction("like", {node_a, literal_s}, boolean());
197   auto expr = TreeExprBuilder::MakeExpression(is_like, res);
198 
199   // Build a projector for the expressions.
200   std::shared_ptr<Projector> projector;
201   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
202   EXPECT_TRUE(status.ok()) << status.message();
203 
204   // Create a row-batch with some sample data
205   int num_records = 4;
206   auto array_a = MakeArrowArrayUtf8({"park", "sparkle", "bright spark and fire", "spark"},
207                                     {true, true, true, true});
208 
209   // expected output
210   auto exp = MakeArrowArrayBool({false, true, true, true}, {true, true, true, true});
211 
212   // prepare input record batch
213   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
214 
215   // Evaluate expression
216   arrow::ArrayVector outputs;
217   status = projector->Evaluate(*in_batch, pool_, &outputs);
218   EXPECT_TRUE(status.ok()) << status.message();
219 
220   // Validate results
221   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
222 }
223 
TEST_F(TestUtf8,TestBeginsEnds)224 TEST_F(TestUtf8, TestBeginsEnds) {
225   // schema for input fields
226   auto field_a = field("a", utf8());
227   auto schema = arrow::schema({field_a});
228 
229   // output fields
230   auto res1 = field("res1", boolean());
231   auto res2 = field("res2", boolean());
232 
233   // build expressions.
234   // like(literal("spark%"), a)
235   // like(literal("%spark"), a)
236 
237   auto node_a = TreeExprBuilder::MakeField(field_a);
238   auto literal_begin = TreeExprBuilder::MakeStringLiteral("spark%");
239   auto is_like1 =
240       TreeExprBuilder::MakeFunction("like", {node_a, literal_begin}, boolean());
241   auto expr1 = TreeExprBuilder::MakeExpression(is_like1, res1);
242 
243   auto literal_end = TreeExprBuilder::MakeStringLiteral("%spark");
244   auto is_like2 = TreeExprBuilder::MakeFunction("like", {node_a, literal_end}, boolean());
245   auto expr2 = TreeExprBuilder::MakeExpression(is_like2, res2);
246 
247   // Build a projector for the expressions.
248   std::shared_ptr<Projector> projector;
249   auto status = Projector::Make(schema, {expr1, expr2}, TestConfiguration(), &projector);
250   EXPECT_TRUE(status.ok()) << status.message();
251 
252   // Create a row-batch with some sample data
253   int num_records = 4;
254   auto array_a =
255       MakeArrowArrayUtf8({"park", "sparkle", "bright spark and fire", "fiery spark"},
256                          {true, true, true, true});
257 
258   // expected output
259   auto exp1 = MakeArrowArrayBool({false, true, false, false}, {true, true, true, true});
260   auto exp2 = MakeArrowArrayBool({false, false, false, true}, {true, true, true, true});
261 
262   // prepare input record batch
263   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
264 
265   // Evaluate expression
266   arrow::ArrayVector outputs;
267   status = projector->Evaluate(*in_batch, pool_, &outputs);
268   EXPECT_TRUE(status.ok()) << status.message();
269 
270   // Validate results
271   EXPECT_ARROW_ARRAY_EQUALS(exp1, outputs.at(0));
272   EXPECT_ARROW_ARRAY_EQUALS(exp2, outputs.at(1));
273 }
274 
TEST_F(TestUtf8,TestInternalAllocs)275 TEST_F(TestUtf8, TestInternalAllocs) {
276   // schema for input fields
277   auto field_a = field("a", utf8());
278   auto schema = arrow::schema({field_a});
279 
280   // output fields
281   auto res = field("res", boolean());
282 
283   // build expressions.
284   // like(upper(a), literal("%SPARK%"))
285 
286   auto node_a = TreeExprBuilder::MakeField(field_a);
287   auto upper_a = TreeExprBuilder::MakeFunction("upper", {node_a}, utf8());
288   auto literal_spark = TreeExprBuilder::MakeStringLiteral("%SPARK%");
289   auto is_like =
290       TreeExprBuilder::MakeFunction("like", {upper_a, literal_spark}, boolean());
291   auto expr = TreeExprBuilder::MakeExpression(is_like, res);
292 
293   // Build a projector for the expressions.
294   std::shared_ptr<Projector> projector;
295   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
296   EXPECT_TRUE(status.ok()) << status.message();
297 
298   // Create a row-batch with some sample data
299   int num_records = 5;
300   auto array_a = MakeArrowArrayUtf8(
301       {"park", "Sparkle", "bright spark and fire", "fiery SPARK", "मदन"},
302       {true, true, false, true, true});
303 
304   // expected output
305   auto exp = MakeArrowArrayBool({false, true, false, true, false},
306                                 {true, true, false, true, true});
307 
308   // prepare input record batch
309   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
310 
311   // Evaluate expression
312   arrow::ArrayVector outputs;
313   status = projector->Evaluate(*in_batch, pool_, &outputs);
314   EXPECT_TRUE(status.ok()) << status.message();
315 
316   // Validate results
317   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
318 }
319 
TEST_F(TestUtf8,TestCastDate)320 TEST_F(TestUtf8, TestCastDate) {
321   // schema for input fields
322   auto field_a = field("a", utf8());
323   auto schema = arrow::schema({field_a});
324 
325   // output fields
326   auto res_1 = field("res1", int64());
327 
328   // build expressions.
329   // extractYear(castDATE(a))
330   auto node_a = TreeExprBuilder::MakeField(field_a);
331   auto cast_function = TreeExprBuilder::MakeFunction("castDATE", {node_a}, date64());
332   auto extract_year =
333       TreeExprBuilder::MakeFunction("extractYear", {cast_function}, int64());
334   auto expr = TreeExprBuilder::MakeExpression(extract_year, res_1);
335 
336   // Build a projector for the expressions.
337   std::shared_ptr<Projector> projector;
338   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
339   EXPECT_TRUE(status.ok()) << status.message();
340 
341   // Create a row-batch with some sample data
342   int num_records = 4;
343   auto array_a = MakeArrowArrayUtf8({"1967-12-1", "67-12-01", "incorrect", "67-45-11"},
344                                     {true, true, false, true});
345 
346   // expected output
347   auto exp_1 = MakeArrowArrayInt64({1967, 2067, 0, 0}, {true, true, false, false});
348 
349   // prepare input record batch
350   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
351 
352   // Evaluate expression
353   arrow::ArrayVector outputs;
354   status = projector->Evaluate(*in_batch, pool_, &outputs);
355   EXPECT_EQ(status.code(), StatusCode::ExecutionError);
356   std::string expected_error = "Not a valid date value ";
357   EXPECT_TRUE(status.message().find(expected_error) != std::string::npos);
358 
359   auto array_a_2 = MakeArrowArrayUtf8({"1967-12-1", "67-12-01", "67-1-1", "91-1-1"},
360                                       {true, true, true, true});
361   auto exp_2 = MakeArrowArrayInt64({1967, 2067, 2067, 1991}, {true, true, true, true});
362   auto in_batch_2 = arrow::RecordBatch::Make(schema, num_records, {array_a_2});
363   arrow::ArrayVector outputs2;
364   status = projector->Evaluate(*in_batch_2, pool_, &outputs2);
365   EXPECT_TRUE(status.ok()) << status.message();
366 
367   // Validate results
368   EXPECT_ARROW_ARRAY_EQUALS(exp_2, outputs2.at(0));
369 }
370 
TEST_F(TestUtf8,TestToDateNoError)371 TEST_F(TestUtf8, TestToDateNoError) {
372   // schema for input fields
373   auto field_a = field("a", utf8());
374   auto schema = arrow::schema({field_a});
375 
376   // output fields
377   auto res_1 = field("res1", int64());
378 
379   // build expressions.
380   // extractYear(castDATE(a))
381   auto node_a = TreeExprBuilder::MakeField(field_a);
382   auto node_b = TreeExprBuilder::MakeStringLiteral("YYYY-MM-DD");
383   auto node_c = TreeExprBuilder::MakeLiteral(1);
384 
385   auto cast_function =
386       TreeExprBuilder::MakeFunction("to_date", {node_a, node_b, node_c}, date64());
387   auto extract_year =
388       TreeExprBuilder::MakeFunction("extractYear", {cast_function}, int64());
389   auto expr = TreeExprBuilder::MakeExpression(extract_year, res_1);
390 
391   // Build a projector for the expressions.
392   std::shared_ptr<Projector> projector;
393   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
394   EXPECT_TRUE(status.ok()) << status.message();
395 
396   // Create a row-batch with some sample data
397   int num_records = 4;
398   auto array_a = MakeArrowArrayUtf8({"1967-12-1", "67-12-01", "incorrect", "67-45-11"},
399                                     {true, true, false, true});
400 
401   // expected output
402   auto exp_1 = MakeArrowArrayInt64({1967, 67, 0, 0}, {true, true, false, false});
403 
404   // prepare input record batch
405   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
406 
407   // Evaluate expression
408   arrow::ArrayVector outputs;
409   status = projector->Evaluate(*in_batch, pool_, &outputs);
410   EXPECT_TRUE(status.ok()) << status.message();
411   EXPECT_ARROW_ARRAY_EQUALS(exp_1, outputs.at(0));
412 
413   // Create a row-batch with some sample data
414   auto array_a_2 = MakeArrowArrayUtf8(
415       {"1967-12-1", "1967-12-01", "1967-11-11", "1991-11-11"}, {true, true, true, true});
416   auto exp_2 = MakeArrowArrayInt64({1967, 1967, 1967, 1991}, {true, true, true, true});
417   auto in_batch_2 = arrow::RecordBatch::Make(schema, num_records, {array_a_2});
418   arrow::ArrayVector outputs2;
419   status = projector->Evaluate(*in_batch_2, pool_, &outputs2);
420   EXPECT_TRUE(status.ok()) << status.message();
421 
422   // Validate results
423   EXPECT_ARROW_ARRAY_EQUALS(exp_2, outputs2.at(0));
424 }
425 
TEST_F(TestUtf8,TestToDateError)426 TEST_F(TestUtf8, TestToDateError) {
427   // schema for input fields
428   auto field_a = field("a", utf8());
429   auto schema = arrow::schema({field_a});
430 
431   // output fields
432   auto res_1 = field("res1", int64());
433 
434   // build expressions.
435   // extractYear(castDATE(a))
436   auto node_a = TreeExprBuilder::MakeField(field_a);
437   auto node_b = TreeExprBuilder::MakeStringLiteral("YYYY-MM-DD");
438   auto node_c = TreeExprBuilder::MakeLiteral(0);
439 
440   auto cast_function =
441       TreeExprBuilder::MakeFunction("to_date", {node_a, node_b, node_c}, date64());
442   auto extract_year =
443       TreeExprBuilder::MakeFunction("extractYear", {cast_function}, int64());
444   auto expr = TreeExprBuilder::MakeExpression(extract_year, res_1);
445 
446   // Build a projector for the expressions.
447   std::shared_ptr<Projector> projector;
448   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
449   EXPECT_TRUE(status.ok()) << status.message();
450 
451   // Create a row-batch with some sample data
452   int num_records = 4;
453   auto array_a = MakeArrowArrayUtf8({"1967-12-1", "67-12-01", "incorrect", "67-45-11"},
454                                     {true, true, false, true});
455 
456   // expected output
457   auto exp_1 = MakeArrowArrayInt64({1967, 67, 0, 0}, {true, true, false, false});
458 
459   // prepare input record batch
460   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
461 
462   // Evaluate expression
463   arrow::ArrayVector outputs;
464   status = projector->Evaluate(*in_batch, pool_, &outputs);
465   EXPECT_EQ(status.code(), StatusCode::ExecutionError);
466   std::string expected_error = "Error parsing value 67-45-11 for given format";
467   EXPECT_TRUE(status.message().find(expected_error) != std::string::npos)
468       << status.message();
469 }
470 
TEST_F(TestUtf8,TestIsNull)471 TEST_F(TestUtf8, TestIsNull) {
472   // schema for input fields
473   auto field_a = field("a", utf8());
474   auto schema = arrow::schema({field_a});
475 
476   // build expressions
477   auto exprs = std::vector<ExpressionPtr>{
478       TreeExprBuilder::MakeExpression("isnull", {field_a}, field("is_null", boolean())),
479       TreeExprBuilder::MakeExpression("isnotnull", {field_a},
480                                       field("is_not_null", boolean())),
481   };
482 
483   // Build a projector for the expressions.
484   std::shared_ptr<Projector> projector;
485   auto status = Projector::Make(schema, exprs, TestConfiguration(), &projector);
486   DCHECK_OK(status);
487 
488   // Create a row-batch with some sample data
489   int num_records = 4;
490   auto array_a = MakeArrowArrayUtf8({"hello", "world", "incorrect", "universe"},
491                                     {true, true, false, true});
492 
493   // prepare input record batch
494   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a});
495 
496   // Evaluate expression
497   arrow::ArrayVector outputs;
498   status = projector->Evaluate(*in_batch, pool_, &outputs);
499 
500   // validate results
501   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({false, false, true, false}),
502                             outputs[0]);  // isnull
503   EXPECT_ARROW_ARRAY_EQUALS(MakeArrowArrayBool({true, true, false, true}),
504                             outputs[1]);  // isnotnull
505 }
506 
TEST_F(TestUtf8,TestVarlenOutput)507 TEST_F(TestUtf8, TestVarlenOutput) {
508   // schema for input fields
509   auto field_a = field("a", boolean());
510   auto schema = arrow::schema({field_a});
511 
512   // build expressions.
513   // if (a) literal_hi else literal_bye
514   auto if_node = TreeExprBuilder::MakeIf(
515       TreeExprBuilder::MakeField(field_a), TreeExprBuilder::MakeStringLiteral("hi"),
516       TreeExprBuilder::MakeStringLiteral("bye"), utf8());
517   auto expr = TreeExprBuilder::MakeExpression(if_node, field("res", utf8()));
518 
519   // Build a projector for the expressions.
520   std::shared_ptr<Projector> projector;
521 
522   // assert that it fails gracefully.
523   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
524 
525   // Create a row-batch with some sample data
526   int num_records = 4;
527   auto array_in =
528       MakeArrowArrayBool({true, false, false, false}, {true, true, true, false});
529   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_in});
530 
531   // Evaluate expression
532   arrow::ArrayVector outputs;
533   ASSERT_OK(projector->Evaluate(*in_batch, pool_, &outputs));
534 
535   // expected output
536   auto exp = MakeArrowArrayUtf8({"hi", "bye", "bye", "bye"}, {true, true, true, true});
537 
538   // Validate results
539   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs.at(0));
540 }
541 
TEST_F(TestUtf8,TestCastVarChar)542 TEST_F(TestUtf8, TestCastVarChar) {
543   // schema for input fields
544   auto field_a = field("a", utf8());
545   auto field_c = field("c", utf8());
546   auto schema = arrow::schema({field_a, field_c});
547 
548   // output fields
549   auto res = field("res", boolean());
550 
551   // build expressions.
552   auto node_a = TreeExprBuilder::MakeField(field_a);
553   auto node_c = TreeExprBuilder::MakeField(field_c);
554   // truncates the string to input length
555   auto node_b = TreeExprBuilder::MakeLiteral(static_cast<int64_t>(10));
556   auto cast_varchar =
557       TreeExprBuilder::MakeFunction("castVARCHAR", {node_a, node_b}, utf8());
558   auto equals = TreeExprBuilder::MakeFunction("equal", {cast_varchar, node_c}, boolean());
559   auto expr = TreeExprBuilder::MakeExpression(equals, res);
560 
561   // Build a projector for the expressions.
562   std::shared_ptr<Projector> projector;
563   auto status = Projector::Make(schema, {expr}, TestConfiguration(), &projector);
564   EXPECT_TRUE(status.ok()) << status.message();
565 
566   // Create a row-batch with some sample data
567   int num_records = 5;
568   auto array_a = MakeArrowArrayUtf8(
569       {"park", "Sparkle", "bright spark and fire", "fiery SPARK", "मदन"},
570       {true, true, false, true, true});
571 
572   auto array_b =
573       MakeArrowArrayUtf8({"park", "Sparkle", "bright spar", "fiery SPAR", "मदन"},
574                          {true, true, true, true, true});
575 
576   // prepare input record batch
577   auto in_batch = arrow::RecordBatch::Make(schema, num_records, {array_a, array_b});
578 
579   // Evaluate expression
580   arrow::ArrayVector outputs;
581   status = projector->Evaluate(*in_batch, pool_, &outputs);
582   EXPECT_TRUE(status.ok()) << status.message();
583 
584   auto exp = MakeArrowArrayBool({true, true, false, true, true},
585                                 {true, true, false, true, true});
586   // Validate results
587   EXPECT_ARROW_ARRAY_EQUALS(exp, outputs[0]);
588 }
589 
590 }  // namespace gandiva
591