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 <cstdint>
19 #include <memory>
20 #include <vector>
21
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24
25 #include "arrow/array.h"
26 #include "arrow/record_batch.h"
27 #include "arrow/status.h"
28 #include "arrow/table.h"
29 #include "arrow/testing/gtest_common.h"
30 #include "arrow/testing/gtest_util.h"
31 #include "arrow/testing/random.h"
32 #include "arrow/testing/util.h"
33 #include "arrow/type.h"
34 #include "arrow/util/key_value_metadata.h"
35
36 namespace arrow {
37
38 class TestChunkedArray : public TestBase {
39 protected:
Construct()40 virtual void Construct() {
41 one_ = std::make_shared<ChunkedArray>(arrays_one_);
42 if (!arrays_another_.empty()) {
43 another_ = std::make_shared<ChunkedArray>(arrays_another_);
44 }
45 }
46
47 ArrayVector arrays_one_;
48 ArrayVector arrays_another_;
49
50 std::shared_ptr<ChunkedArray> one_;
51 std::shared_ptr<ChunkedArray> another_;
52 };
53
TEST_F(TestChunkedArray,BasicEquals)54 TEST_F(TestChunkedArray, BasicEquals) {
55 std::vector<bool> null_bitmap(100, true);
56 std::vector<int32_t> data(100, 1);
57 std::shared_ptr<Array> array;
58 ArrayFromVector<Int32Type, int32_t>(null_bitmap, data, &array);
59 arrays_one_.push_back(array);
60 arrays_another_.push_back(array);
61
62 Construct();
63 ASSERT_TRUE(one_->Equals(one_));
64 ASSERT_FALSE(one_->Equals(nullptr));
65 ASSERT_TRUE(one_->Equals(another_));
66 ASSERT_TRUE(one_->Equals(*another_.get()));
67 }
68
TEST_F(TestChunkedArray,EqualsDifferingTypes)69 TEST_F(TestChunkedArray, EqualsDifferingTypes) {
70 std::vector<bool> null_bitmap(100, true);
71 std::vector<int32_t> data32(100, 1);
72 std::vector<int64_t> data64(100, 1);
73 std::shared_ptr<Array> array;
74 ArrayFromVector<Int32Type, int32_t>(null_bitmap, data32, &array);
75 arrays_one_.push_back(array);
76 ArrayFromVector<Int64Type, int64_t>(null_bitmap, data64, &array);
77 arrays_another_.push_back(array);
78
79 Construct();
80 ASSERT_FALSE(one_->Equals(another_));
81 ASSERT_FALSE(one_->Equals(*another_.get()));
82 }
83
TEST_F(TestChunkedArray,EqualsDifferingLengths)84 TEST_F(TestChunkedArray, EqualsDifferingLengths) {
85 std::vector<bool> null_bitmap100(100, true);
86 std::vector<bool> null_bitmap101(101, true);
87 std::vector<int32_t> data100(100, 1);
88 std::vector<int32_t> data101(101, 1);
89 std::shared_ptr<Array> array;
90 ArrayFromVector<Int32Type, int32_t>(null_bitmap100, data100, &array);
91 arrays_one_.push_back(array);
92 ArrayFromVector<Int32Type, int32_t>(null_bitmap101, data101, &array);
93 arrays_another_.push_back(array);
94
95 Construct();
96 ASSERT_FALSE(one_->Equals(another_));
97 ASSERT_FALSE(one_->Equals(*another_.get()));
98
99 std::vector<bool> null_bitmap1(1, true);
100 std::vector<int32_t> data1(1, 1);
101 ArrayFromVector<Int32Type, int32_t>(null_bitmap1, data1, &array);
102 arrays_one_.push_back(array);
103
104 Construct();
105 ASSERT_TRUE(one_->Equals(another_));
106 ASSERT_TRUE(one_->Equals(*another_.get()));
107 }
108
TEST_F(TestChunkedArray,EqualsDifferingMetadata)109 TEST_F(TestChunkedArray, EqualsDifferingMetadata) {
110 auto left_ty = list(field("item", int32()));
111
112 auto metadata = key_value_metadata({"foo"}, {"bar"});
113 auto right_ty = list(field("item", int32(), true, metadata));
114
115 std::vector<std::shared_ptr<Array>> left_chunks = {ArrayFromJSON(left_ty, "[[]]")};
116 std::vector<std::shared_ptr<Array>> right_chunks = {ArrayFromJSON(right_ty, "[[]]")};
117
118 ChunkedArray left(left_chunks);
119 ChunkedArray right(right_chunks);
120 ASSERT_TRUE(left.Equals(right));
121 }
122
TEST_F(TestChunkedArray,SliceEquals)123 TEST_F(TestChunkedArray, SliceEquals) {
124 arrays_one_.push_back(MakeRandomArray<Int32Array>(100));
125 arrays_one_.push_back(MakeRandomArray<Int32Array>(50));
126 arrays_one_.push_back(MakeRandomArray<Int32Array>(50));
127 Construct();
128
129 std::shared_ptr<ChunkedArray> slice = one_->Slice(125, 50);
130 ASSERT_EQ(slice->length(), 50);
131 AssertChunkedEqual(*one_->Slice(125, 50), *slice);
132
133 std::shared_ptr<ChunkedArray> slice2 = one_->Slice(75)->Slice(25)->Slice(25, 50);
134 ASSERT_EQ(slice2->length(), 50);
135 AssertChunkedEqual(*slice, *slice2);
136
137 // Making empty slices of a ChunkedArray
138 std::shared_ptr<ChunkedArray> slice3 = one_->Slice(one_->length(), 99);
139 ASSERT_EQ(slice3->length(), 0);
140 ASSERT_EQ(slice3->num_chunks(), 1);
141 ASSERT_TRUE(slice3->type()->Equals(one_->type()));
142
143 std::shared_ptr<ChunkedArray> slice4 = one_->Slice(10, 0);
144 ASSERT_EQ(slice4->length(), 0);
145 ASSERT_EQ(slice4->num_chunks(), 1);
146 ASSERT_TRUE(slice4->type()->Equals(one_->type()));
147
148 // Slicing an empty ChunkedArray
149 std::shared_ptr<ChunkedArray> slice5 = slice4->Slice(0, 10);
150 ASSERT_EQ(slice5->length(), 0);
151 ASSERT_EQ(slice5->num_chunks(), 1);
152 ASSERT_TRUE(slice5->type()->Equals(one_->type()));
153 }
154
TEST_F(TestChunkedArray,ZeroChunksIssues)155 TEST_F(TestChunkedArray, ZeroChunksIssues) {
156 ArrayVector empty = {};
157 auto no_chunks = std::make_shared<ChunkedArray>(empty, int8());
158
159 // ARROW-8911, assert that slicing is a no-op when there are zero-chunks
160 auto sliced = no_chunks->Slice(0, 0);
161 auto sliced2 = no_chunks->Slice(0, 5);
162 AssertChunkedEqual(*no_chunks, *sliced);
163 AssertChunkedEqual(*no_chunks, *sliced2);
164 }
165
TEST_F(TestChunkedArray,Validate)166 TEST_F(TestChunkedArray, Validate) {
167 // Valid if empty
168 ArrayVector empty = {};
169 auto no_chunks = std::make_shared<ChunkedArray>(empty, utf8());
170 ASSERT_OK(no_chunks->ValidateFull());
171
172 random::RandomArrayGenerator gen(0);
173 arrays_one_.push_back(gen.Int32(50, 0, 100, 0.1));
174 Construct();
175 ASSERT_OK(one_->ValidateFull());
176
177 arrays_one_.push_back(gen.Int32(50, 0, 100, 0.1));
178 Construct();
179 ASSERT_OK(one_->ValidateFull());
180
181 arrays_one_.push_back(gen.String(50, 0, 10, 0.1));
182 Construct();
183 ASSERT_RAISES(Invalid, one_->ValidateFull());
184 }
185
TEST_F(TestChunkedArray,View)186 TEST_F(TestChunkedArray, View) {
187 auto in_ty = int32();
188 auto out_ty = fixed_size_binary(4);
189 #if ARROW_LITTLE_ENDIAN
190 auto arr = ArrayFromJSON(in_ty, "[2020568934, 2054316386, null]");
191 auto arr2 = ArrayFromJSON(in_ty, "[2020568934, 2054316386]");
192 #else
193 auto arr = ArrayFromJSON(in_ty, "[1718579064, 1650553466, null]");
194 auto arr2 = ArrayFromJSON(in_ty, "[1718579064, 1650553466]");
195 #endif
196 auto ex = ArrayFromJSON(out_ty, R"(["foox", "barz", null])");
197 auto ex2 = ArrayFromJSON(out_ty, R"(["foox", "barz"])");
198
199 ArrayVector chunks = {arr, arr2};
200 ArrayVector ex_chunks = {ex, ex2};
201 auto carr = std::make_shared<ChunkedArray>(chunks);
202 auto expected = std::make_shared<ChunkedArray>(ex_chunks);
203
204 ASSERT_OK_AND_ASSIGN(auto result, carr->View(out_ty));
205 AssertChunkedEqual(*expected, *result);
206
207 // Zero length
208 ArrayVector empty = {};
209 carr = std::make_shared<ChunkedArray>(empty, in_ty);
210 expected = std::make_shared<ChunkedArray>(empty, out_ty);
211 ASSERT_OK_AND_ASSIGN(result, carr->View(out_ty));
212 AssertChunkedEqual(*expected, *result);
213 }
214
215 class TestTable : public TestBase {
216 public:
MakeExample1(int length)217 void MakeExample1(int length) {
218 auto f0 = field("f0", int32());
219 auto f1 = field("f1", uint8());
220 auto f2 = field("f2", int16());
221
222 std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
223 schema_ = std::make_shared<Schema>(fields);
224
225 arrays_ = {MakeRandomArray<Int32Array>(length), MakeRandomArray<UInt8Array>(length),
226 MakeRandomArray<Int16Array>(length)};
227
228 columns_ = {std::make_shared<ChunkedArray>(arrays_[0]),
229 std::make_shared<ChunkedArray>(arrays_[1]),
230 std::make_shared<ChunkedArray>(arrays_[2])};
231 }
232
233 protected:
234 std::shared_ptr<Table> table_;
235 std::shared_ptr<Schema> schema_;
236
237 std::vector<std::shared_ptr<Array>> arrays_;
238 std::vector<std::shared_ptr<ChunkedArray>> columns_;
239 };
240
TEST_F(TestTable,EmptySchema)241 TEST_F(TestTable, EmptySchema) {
242 auto empty_schema = ::arrow::schema({});
243 table_ = Table::Make(empty_schema, columns_);
244 ASSERT_OK(table_->ValidateFull());
245 ASSERT_EQ(0, table_->num_rows());
246 ASSERT_EQ(0, table_->num_columns());
247 }
248
TEST_F(TestTable,Ctors)249 TEST_F(TestTable, Ctors) {
250 const int length = 100;
251 MakeExample1(length);
252
253 table_ = Table::Make(schema_, columns_);
254 ASSERT_OK(table_->ValidateFull());
255 ASSERT_EQ(length, table_->num_rows());
256 ASSERT_EQ(3, table_->num_columns());
257
258 auto array_ctor = Table::Make(schema_, arrays_);
259 ASSERT_TRUE(table_->Equals(*array_ctor));
260
261 table_ = Table::Make(schema_, columns_, length);
262 ASSERT_OK(table_->ValidateFull());
263 ASSERT_EQ(length, table_->num_rows());
264
265 table_ = Table::Make(schema_, arrays_);
266 ASSERT_OK(table_->ValidateFull());
267 ASSERT_EQ(length, table_->num_rows());
268 ASSERT_EQ(3, table_->num_columns());
269 }
270
TEST_F(TestTable,Metadata)271 TEST_F(TestTable, Metadata) {
272 const int length = 100;
273 MakeExample1(length);
274
275 table_ = Table::Make(schema_, columns_);
276
277 ASSERT_TRUE(table_->schema()->Equals(*schema_));
278
279 auto col = table_->column(0);
280 ASSERT_EQ(schema_->field(0)->type(), col->type());
281 }
282
TEST_F(TestTable,InvalidColumns)283 TEST_F(TestTable, InvalidColumns) {
284 // Check that columns are all the same length
285 const int length = 100;
286 MakeExample1(length);
287
288 table_ = Table::Make(schema_, columns_, length - 1);
289 ASSERT_RAISES(Invalid, table_->ValidateFull());
290
291 columns_.clear();
292
293 // Wrong number of columns
294 table_ = Table::Make(schema_, columns_, length);
295 ASSERT_RAISES(Invalid, table_->ValidateFull());
296
297 columns_ = {std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length)),
298 std::make_shared<ChunkedArray>(MakeRandomArray<UInt8Array>(length)),
299 std::make_shared<ChunkedArray>(MakeRandomArray<Int16Array>(length - 1))};
300
301 table_ = Table::Make(schema_, columns_, length);
302 ASSERT_RAISES(Invalid, table_->ValidateFull());
303 }
304
TEST_F(TestTable,AllColumnsAndFields)305 TEST_F(TestTable, AllColumnsAndFields) {
306 const int length = 100;
307 MakeExample1(length);
308 table_ = Table::Make(schema_, columns_);
309
310 auto columns = table_->columns();
311 auto fields = table_->fields();
312
313 for (int i = 0; i < table_->num_columns(); ++i) {
314 AssertChunkedEqual(*table_->column(i), *columns[i]);
315 AssertFieldEqual(*table_->field(i), *fields[i]);
316 }
317
318 // Zero length
319 std::vector<std::shared_ptr<Array>> t2_columns;
320 auto t2 = Table::Make(::arrow::schema({}), t2_columns);
321 columns = t2->columns();
322 fields = t2->fields();
323
324 ASSERT_EQ(0, columns.size());
325 ASSERT_EQ(0, fields.size());
326 }
327
TEST_F(TestTable,Equals)328 TEST_F(TestTable, Equals) {
329 const int length = 100;
330 MakeExample1(length);
331
332 table_ = Table::Make(schema_, columns_);
333
334 ASSERT_TRUE(table_->Equals(*table_));
335 // Differing schema
336 auto f0 = field("f3", int32());
337 auto f1 = field("f4", uint8());
338 auto f2 = field("f5", int16());
339 std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
340 auto other_schema = std::make_shared<Schema>(fields);
341 auto other = Table::Make(other_schema, columns_);
342 ASSERT_FALSE(table_->Equals(*other));
343 // Differing columns
344 std::vector<std::shared_ptr<ChunkedArray>> other_columns = {
345 std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length, 10)),
346 std::make_shared<ChunkedArray>(MakeRandomArray<UInt8Array>(length, 10)),
347 std::make_shared<ChunkedArray>(MakeRandomArray<Int16Array>(length, 10))};
348
349 other = Table::Make(schema_, other_columns);
350 ASSERT_FALSE(table_->Equals(*other));
351
352 // Differring schema metadata
353 other_schema = schema_->WithMetadata(::arrow::key_value_metadata({"key"}, {"value"}));
354 other = Table::Make(other_schema, columns_);
355 ASSERT_TRUE(table_->Equals(*other));
356 ASSERT_FALSE(table_->Equals(*other, /*check_metadata=*/true));
357 }
358
TEST_F(TestTable,FromRecordBatches)359 TEST_F(TestTable, FromRecordBatches) {
360 const int64_t length = 10;
361 MakeExample1(length);
362
363 auto batch1 = RecordBatch::Make(schema_, length, arrays_);
364
365 ASSERT_OK_AND_ASSIGN(auto result, Table::FromRecordBatches({batch1}));
366
367 auto expected = Table::Make(schema_, columns_);
368 ASSERT_TRUE(result->Equals(*expected));
369
370 std::vector<std::shared_ptr<ChunkedArray>> other_columns;
371 for (int i = 0; i < schema_->num_fields(); ++i) {
372 std::vector<std::shared_ptr<Array>> col_arrays = {arrays_[i], arrays_[i]};
373 other_columns.push_back(std::make_shared<ChunkedArray>(col_arrays));
374 }
375
376 ASSERT_OK_AND_ASSIGN(result, Table::FromRecordBatches({batch1, batch1}));
377 expected = Table::Make(schema_, other_columns);
378 ASSERT_TRUE(result->Equals(*expected));
379
380 // Error states
381 std::vector<std::shared_ptr<RecordBatch>> empty_batches;
382 ASSERT_RAISES(Invalid, Table::FromRecordBatches(empty_batches));
383
384 auto other_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
385
386 std::vector<std::shared_ptr<Array>> other_arrays = {arrays_[0], arrays_[1]};
387 auto batch2 = RecordBatch::Make(other_schema, length, other_arrays);
388 ASSERT_RAISES(Invalid, Table::FromRecordBatches({batch1, batch2}));
389 }
390
TEST_F(TestTable,FromRecordBatchesZeroLength)391 TEST_F(TestTable, FromRecordBatchesZeroLength) {
392 // ARROW-2307
393 MakeExample1(10);
394
395 ASSERT_OK_AND_ASSIGN(auto result, Table::FromRecordBatches(schema_, {}));
396
397 ASSERT_EQ(0, result->num_rows());
398 ASSERT_TRUE(result->schema()->Equals(*schema_));
399 }
400
TEST_F(TestTable,CombineChunksEmptyTable)401 TEST_F(TestTable, CombineChunksEmptyTable) {
402 MakeExample1(10);
403
404 ASSERT_OK_AND_ASSIGN(auto table, Table::FromRecordBatches(schema_, {}));
405 ASSERT_EQ(0, table->num_rows());
406
407 ASSERT_OK_AND_ASSIGN(auto compacted, table->CombineChunks());
408
409 EXPECT_TRUE(compacted->Equals(*table));
410 }
411
TEST_F(TestTable,CombineChunks)412 TEST_F(TestTable, CombineChunks) {
413 MakeExample1(10);
414 auto batch1 = RecordBatch::Make(schema_, 10, arrays_);
415
416 MakeExample1(15);
417 auto batch2 = RecordBatch::Make(schema_, 15, arrays_);
418
419 ASSERT_OK_AND_ASSIGN(auto table, Table::FromRecordBatches({batch1, batch2}));
420 for (int i = 0; i < table->num_columns(); ++i) {
421 ASSERT_EQ(2, table->column(i)->num_chunks());
422 }
423
424 ASSERT_OK_AND_ASSIGN(auto compacted, table->CombineChunks());
425
426 EXPECT_TRUE(compacted->Equals(*table));
427 for (int i = 0; i < compacted->num_columns(); ++i) {
428 EXPECT_EQ(1, compacted->column(i)->num_chunks());
429 }
430 }
431
TEST_F(TestTable,ConcatenateTables)432 TEST_F(TestTable, ConcatenateTables) {
433 const int64_t length = 10;
434
435 MakeExample1(length);
436 auto batch1 = RecordBatch::Make(schema_, length, arrays_);
437
438 // generate different data
439 MakeExample1(length);
440 auto batch2 = RecordBatch::Make(schema_, length, arrays_);
441
442 ASSERT_OK_AND_ASSIGN(auto t1, Table::FromRecordBatches({batch1}));
443 ASSERT_OK_AND_ASSIGN(auto t2, Table::FromRecordBatches({batch2}));
444
445 ASSERT_OK_AND_ASSIGN(auto result, ConcatenateTables({t1, t2}));
446 ASSERT_OK_AND_ASSIGN(auto expected, Table::FromRecordBatches({batch1, batch2}));
447 AssertTablesEqual(*expected, *result);
448
449 // Error states
450 std::vector<std::shared_ptr<Table>> empty_tables;
451 ASSERT_RAISES(Invalid, ConcatenateTables(empty_tables));
452
453 auto other_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
454
455 std::vector<std::shared_ptr<Array>> other_arrays = {arrays_[0], arrays_[1]};
456 auto batch3 = RecordBatch::Make(other_schema, length, other_arrays);
457 ASSERT_OK_AND_ASSIGN(auto t3, Table::FromRecordBatches({batch3}));
458
459 ASSERT_RAISES(Invalid, ConcatenateTables({t1, t3}));
460 }
461
MakeTableWithOneNullFilledColumn(const std::string & column_name,const std::shared_ptr<DataType> & data_type,const int length)462 std::shared_ptr<Table> MakeTableWithOneNullFilledColumn(
463 const std::string& column_name, const std::shared_ptr<DataType>& data_type,
464 const int length) {
465 auto array_of_nulls = *MakeArrayOfNull(data_type, length);
466 return Table::Make(schema({field(column_name, data_type)}), {array_of_nulls});
467 }
468
469 using TestPromoteTableToSchema = TestTable;
470
TEST_F(TestPromoteTableToSchema,IdenticalSchema)471 TEST_F(TestPromoteTableToSchema, IdenticalSchema) {
472 const int length = 10;
473 auto metadata =
474 std::shared_ptr<KeyValueMetadata>(new KeyValueMetadata({"foo"}, {"bar"}));
475 MakeExample1(length);
476 std::shared_ptr<Table> table = Table::Make(schema_, arrays_);
477
478 ASSERT_OK_AND_ASSIGN(auto result,
479 PromoteTableToSchema(table, schema_->WithMetadata(metadata)));
480
481 std::shared_ptr<Table> expected = table->ReplaceSchemaMetadata(metadata);
482
483 ASSERT_TRUE(result->Equals(*expected));
484 }
485
486 // The promoted table's fields are ordered the same as the promote-to schema.
TEST_F(TestPromoteTableToSchema,FieldsReorderedAfterPromotion)487 TEST_F(TestPromoteTableToSchema, FieldsReorderedAfterPromotion) {
488 const int length = 10;
489 MakeExample1(length);
490
491 std::vector<std::shared_ptr<Field>> reversed_fields(schema_->fields().crbegin(),
492 schema_->fields().crend());
493 std::vector<std::shared_ptr<Array>> reversed_arrays(arrays_.crbegin(), arrays_.crend());
494
495 std::shared_ptr<Table> table = Table::Make(schema(reversed_fields), reversed_arrays);
496
497 ASSERT_OK_AND_ASSIGN(auto result, PromoteTableToSchema(table, schema_));
498
499 ASSERT_TRUE(result->schema()->Equals(*schema_));
500 }
501
TEST_F(TestPromoteTableToSchema,PromoteNullTypeField)502 TEST_F(TestPromoteTableToSchema, PromoteNullTypeField) {
503 const int length = 10;
504 auto metadata =
505 std::shared_ptr<KeyValueMetadata>(new KeyValueMetadata({"foo"}, {"bar"}));
506 auto table_with_null_column = MakeTableWithOneNullFilledColumn("field", null(), length)
507 ->ReplaceSchemaMetadata(metadata);
508 auto promoted_schema = schema({field("field", int32())});
509
510 ASSERT_OK_AND_ASSIGN(auto result,
511 PromoteTableToSchema(table_with_null_column, promoted_schema));
512
513 ASSERT_TRUE(
514 result->Equals(*MakeTableWithOneNullFilledColumn("field", int32(), length)));
515 }
516
TEST_F(TestPromoteTableToSchema,AddMissingField)517 TEST_F(TestPromoteTableToSchema, AddMissingField) {
518 const int length = 10;
519 auto f0 = field("f0", int32());
520 auto table = Table::Make(schema({}), std::vector<std::shared_ptr<Array>>(), length);
521 auto promoted_schema = schema({field("field", int32())});
522
523 ASSERT_OK_AND_ASSIGN(auto result, PromoteTableToSchema(table, promoted_schema));
524
525 ASSERT_TRUE(
526 result->Equals(*MakeTableWithOneNullFilledColumn("field", int32(), length)));
527 }
528
TEST_F(TestPromoteTableToSchema,IncompatibleTypes)529 TEST_F(TestPromoteTableToSchema, IncompatibleTypes) {
530 const int length = 10;
531 auto table = MakeTableWithOneNullFilledColumn("field", int32(), length);
532
533 // Invalid promotion: int32 to null.
534 ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", null())})));
535
536 // Invalid promotion: int32 to uint32.
537 ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", uint32())})));
538 }
539
TEST_F(TestPromoteTableToSchema,IncompatibleNullity)540 TEST_F(TestPromoteTableToSchema, IncompatibleNullity) {
541 const int length = 10;
542 auto table = MakeTableWithOneNullFilledColumn("field", int32(), length);
543 ASSERT_RAISES(Invalid,
544 PromoteTableToSchema(
545 table, schema({field("field", uint32())->WithNullable(false)})));
546 }
547
TEST_F(TestPromoteTableToSchema,DuplicateFieldNames)548 TEST_F(TestPromoteTableToSchema, DuplicateFieldNames) {
549 const int length = 10;
550
551 auto table = Table::Make(
552 schema({field("field", int32()), field("field", null())}),
553 {MakeRandomArray<Int32Array>(length), MakeRandomArray<NullArray>(length)});
554
555 ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", int32())})));
556 }
557
TEST_F(TestPromoteTableToSchema,TableFieldAbsentFromSchema)558 TEST_F(TestPromoteTableToSchema, TableFieldAbsentFromSchema) {
559 const int length = 10;
560
561 auto table =
562 Table::Make(schema({field("f0", int32())}), {MakeRandomArray<Int32Array>(length)});
563
564 std::shared_ptr<Table> result;
565 ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("f1", int32())})));
566 }
567
568 class ConcatenateTablesWithPromotionTest : public TestTable {
569 protected:
GetOptions()570 ConcatenateTablesOptions GetOptions() {
571 ConcatenateTablesOptions options;
572 options.unify_schemas = true;
573 return options;
574 }
575
MakeExample2(int length)576 void MakeExample2(int length) {
577 auto f0 = field("f0", int32());
578 auto f1 = field("f1", null());
579
580 std::vector<std::shared_ptr<Field>> fields = {f0, f1};
581 schema_ = std::make_shared<Schema>(fields);
582
583 arrays_ = {MakeRandomArray<Int32Array>(length), MakeRandomArray<NullArray>(length)};
584
585 columns_ = {std::make_shared<ChunkedArray>(arrays_[0]),
586 std::make_shared<ChunkedArray>(arrays_[1])};
587 }
588
AssertTablesEqualUnorderedFields(const Table & lhs,const Table & rhs)589 void AssertTablesEqualUnorderedFields(const Table& lhs, const Table& rhs) {
590 ASSERT_EQ(lhs.schema()->num_fields(), rhs.schema()->num_fields());
591 if (lhs.schema()->metadata()) {
592 ASSERT_NE(nullptr, rhs.schema()->metadata());
593 ASSERT_TRUE(lhs.schema()->metadata()->Equals(*rhs.schema()->metadata()));
594 } else {
595 ASSERT_EQ(nullptr, rhs.schema()->metadata());
596 }
597 for (int i = 0; i < lhs.schema()->num_fields(); ++i) {
598 const auto& lhs_field = lhs.schema()->field(i);
599 const auto& rhs_field = rhs.schema()->GetFieldByName(lhs_field->name());
600 ASSERT_NE(nullptr, rhs_field);
601 ASSERT_TRUE(lhs_field->Equals(rhs_field, true));
602 const auto& lhs_column = lhs.column(i);
603 const auto& rhs_column = rhs.GetColumnByName(lhs_field->name());
604 AssertChunkedEqual(*lhs_column, *rhs_column);
605 }
606 }
607 };
608
TEST_F(ConcatenateTablesWithPromotionTest,Simple)609 TEST_F(ConcatenateTablesWithPromotionTest, Simple) {
610 const int64_t length = 10;
611
612 MakeExample1(length);
613 auto batch1 = RecordBatch::Make(schema_, length, arrays_);
614
615 ASSERT_OK_AND_ASSIGN(auto f1_nulls, MakeArrayOfNull(schema_->field(1)->type(), length));
616 ASSERT_OK_AND_ASSIGN(auto f2_nulls, MakeArrayOfNull(schema_->field(2)->type(), length));
617
618 MakeExample2(length);
619 auto batch2 = RecordBatch::Make(schema_, length, arrays_);
620
621 auto batch2_null_filled =
622 RecordBatch::Make(batch1->schema(), length, {arrays_[0], f1_nulls, f2_nulls});
623
624 ASSERT_OK_AND_ASSIGN(auto t1, Table::FromRecordBatches({batch1}));
625 ASSERT_OK_AND_ASSIGN(auto t2, Table::FromRecordBatches({batch2}));
626 ASSERT_OK_AND_ASSIGN(auto t3, Table::FromRecordBatches({batch2_null_filled}));
627
628 ASSERT_OK_AND_ASSIGN(auto result, ConcatenateTables({t1, t2}, GetOptions()));
629 ASSERT_OK_AND_ASSIGN(auto expected, ConcatenateTables({t1, t3}));
630 AssertTablesEqualUnorderedFields(*expected, *result);
631
632 ASSERT_OK_AND_ASSIGN(result, ConcatenateTables({t2, t1}, GetOptions()));
633 ASSERT_OK_AND_ASSIGN(expected, ConcatenateTables({t3, t1}));
634 AssertTablesEqualUnorderedFields(*expected, *result);
635 }
636
TEST_F(TestTable,Slice)637 TEST_F(TestTable, Slice) {
638 const int64_t length = 10;
639
640 MakeExample1(length);
641 auto batch = RecordBatch::Make(schema_, length, arrays_);
642
643 ASSERT_OK_AND_ASSIGN(auto half, Table::FromRecordBatches({batch}));
644 ASSERT_OK_AND_ASSIGN(auto whole, Table::FromRecordBatches({batch, batch}));
645 ASSERT_OK_AND_ASSIGN(auto three, Table::FromRecordBatches({batch, batch, batch}));
646
647 AssertTablesEqual(*whole->Slice(0, length), *half);
648 AssertTablesEqual(*whole->Slice(length), *half);
649 AssertTablesEqual(*whole->Slice(length / 3, 2 * (length - length / 3)),
650 *three->Slice(length + length / 3, 2 * (length - length / 3)));
651 }
652
TEST_F(TestTable,RemoveColumn)653 TEST_F(TestTable, RemoveColumn) {
654 const int64_t length = 10;
655 MakeExample1(length);
656
657 auto table_sp = Table::Make(schema_, columns_);
658 const Table& table = *table_sp;
659
660 ASSERT_OK_AND_ASSIGN(auto result, table.RemoveColumn(0));
661
662 auto ex_schema = ::arrow::schema({schema_->field(1), schema_->field(2)});
663 std::vector<std::shared_ptr<ChunkedArray>> ex_columns = {table.column(1),
664 table.column(2)};
665
666 auto expected = Table::Make(ex_schema, ex_columns);
667 ASSERT_TRUE(result->Equals(*expected));
668
669 ASSERT_OK_AND_ASSIGN(result, table.RemoveColumn(1));
670 ex_schema = ::arrow::schema({schema_->field(0), schema_->field(2)});
671 ex_columns = {table.column(0), table.column(2)};
672
673 expected = Table::Make(ex_schema, ex_columns);
674 ASSERT_TRUE(result->Equals(*expected));
675
676 ASSERT_OK_AND_ASSIGN(result, table.RemoveColumn(2));
677 ex_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
678 ex_columns = {table.column(0), table.column(1)};
679 expected = Table::Make(ex_schema, ex_columns);
680 ASSERT_TRUE(result->Equals(*expected));
681 }
682
TEST_F(TestTable,SetColumn)683 TEST_F(TestTable, SetColumn) {
684 const int64_t length = 10;
685 MakeExample1(length);
686
687 auto table_sp = Table::Make(schema_, columns_);
688 const Table& table = *table_sp;
689
690 ASSERT_OK_AND_ASSIGN(auto result,
691 table.SetColumn(0, schema_->field(1), table.column(1)));
692
693 auto ex_schema =
694 ::arrow::schema({schema_->field(1), schema_->field(1), schema_->field(2)});
695
696 auto expected =
697 Table::Make(ex_schema, {table.column(1), table.column(1), table.column(2)});
698 ASSERT_TRUE(result->Equals(*expected));
699 }
700
TEST_F(TestTable,RenameColumns)701 TEST_F(TestTable, RenameColumns) {
702 MakeExample1(10);
703 auto table = Table::Make(schema_, columns_);
704 EXPECT_THAT(table->ColumnNames(), testing::ElementsAre("f0", "f1", "f2"));
705
706 ASSERT_OK_AND_ASSIGN(auto renamed, table->RenameColumns({"zero", "one", "two"}));
707 EXPECT_THAT(renamed->ColumnNames(), testing::ElementsAre("zero", "one", "two"));
708 ASSERT_OK(renamed->ValidateFull());
709
710 ASSERT_RAISES(Invalid, table->RenameColumns({"hello", "world"}));
711 }
712
TEST_F(TestTable,RemoveColumnEmpty)713 TEST_F(TestTable, RemoveColumnEmpty) {
714 // ARROW-1865
715 const int64_t length = 10;
716
717 auto f0 = field("f0", int32());
718 auto schema = ::arrow::schema({f0});
719 auto a0 = MakeRandomArray<Int32Array>(length);
720
721 auto table = Table::Make(schema, {std::make_shared<ChunkedArray>(a0)});
722
723 ASSERT_OK_AND_ASSIGN(auto empty, table->RemoveColumn(0));
724
725 ASSERT_EQ(table->num_rows(), empty->num_rows());
726
727 ASSERT_OK_AND_ASSIGN(auto added, empty->AddColumn(0, f0, table->column(0)));
728 ASSERT_EQ(table->num_rows(), added->num_rows());
729 }
730
TEST_F(TestTable,AddColumn)731 TEST_F(TestTable, AddColumn) {
732 const int64_t length = 10;
733 MakeExample1(length);
734
735 auto table_sp = Table::Make(schema_, columns_);
736 const Table& table = *table_sp;
737
738 auto f0 = schema_->field(0);
739
740 // Some negative tests with invalid index
741 ASSERT_RAISES(Invalid, table.AddColumn(10, f0, columns_[0]));
742 ASSERT_RAISES(Invalid, table.AddColumn(4, f0, columns_[0]));
743 ASSERT_RAISES(Invalid, table.AddColumn(-1, f0, columns_[0]));
744
745 // Add column with wrong length
746 auto longer_col =
747 std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length + 1));
748 ASSERT_RAISES(Invalid, table.AddColumn(0, f0, longer_col));
749
750 // Add column 0 in different places
751 ASSERT_OK_AND_ASSIGN(auto result, table.AddColumn(0, f0, columns_[0]));
752 auto ex_schema = ::arrow::schema(
753 {schema_->field(0), schema_->field(0), schema_->field(1), schema_->field(2)});
754
755 auto expected = Table::Make(
756 ex_schema, {table.column(0), table.column(0), table.column(1), table.column(2)});
757 ASSERT_TRUE(result->Equals(*expected));
758
759 ASSERT_OK_AND_ASSIGN(result, table.AddColumn(1, f0, columns_[0]));
760 ex_schema = ::arrow::schema(
761 {schema_->field(0), schema_->field(0), schema_->field(1), schema_->field(2)});
762
763 expected = Table::Make(
764 ex_schema, {table.column(0), table.column(0), table.column(1), table.column(2)});
765 ASSERT_TRUE(result->Equals(*expected));
766
767 ASSERT_OK_AND_ASSIGN(result, table.AddColumn(2, f0, columns_[0]));
768 ex_schema = ::arrow::schema(
769 {schema_->field(0), schema_->field(1), schema_->field(0), schema_->field(2)});
770 expected = Table::Make(
771 ex_schema, {table.column(0), table.column(1), table.column(0), table.column(2)});
772 ASSERT_TRUE(result->Equals(*expected));
773
774 ASSERT_OK_AND_ASSIGN(result, table.AddColumn(3, f0, columns_[0]));
775 ex_schema = ::arrow::schema(
776 {schema_->field(0), schema_->field(1), schema_->field(2), schema_->field(0)});
777 expected = Table::Make(
778 ex_schema, {table.column(0), table.column(1), table.column(2), table.column(0)});
779 ASSERT_TRUE(result->Equals(*expected));
780 }
781
782 class TestRecordBatch : public TestBase {};
783
TEST_F(TestRecordBatch,Equals)784 TEST_F(TestRecordBatch, Equals) {
785 const int length = 10;
786
787 auto f0 = field("f0", int32());
788 auto f1 = field("f1", uint8());
789 auto f2 = field("f2", int16());
790
791 auto metadata = key_value_metadata({"foo"}, {"bar"});
792
793 std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
794 auto schema = ::arrow::schema({f0, f1, f2});
795 auto schema2 = ::arrow::schema({f0, f1});
796 auto schema3 = ::arrow::schema({f0, f1, f2}, metadata);
797
798 auto a0 = MakeRandomArray<Int32Array>(length);
799 auto a1 = MakeRandomArray<UInt8Array>(length);
800 auto a2 = MakeRandomArray<Int16Array>(length);
801
802 auto b1 = RecordBatch::Make(schema, length, {a0, a1, a2});
803 auto b2 = RecordBatch::Make(schema3, length, {a0, a1, a2});
804 auto b3 = RecordBatch::Make(schema2, length, {a0, a1});
805 auto b4 = RecordBatch::Make(schema, length, {a0, a1, a1});
806
807 ASSERT_TRUE(b1->Equals(*b1));
808 ASSERT_FALSE(b1->Equals(*b3));
809 ASSERT_FALSE(b1->Equals(*b4));
810
811 // Different metadata
812 ASSERT_TRUE(b1->Equals(*b2));
813 ASSERT_FALSE(b1->Equals(*b2, /*check_metadata=*/true));
814 }
815
TEST_F(TestRecordBatch,Validate)816 TEST_F(TestRecordBatch, Validate) {
817 const int length = 10;
818
819 auto f0 = field("f0", int32());
820 auto f1 = field("f1", uint8());
821 auto f2 = field("f2", int16());
822
823 auto schema = ::arrow::schema({f0, f1, f2});
824
825 auto a0 = MakeRandomArray<Int32Array>(length);
826 auto a1 = MakeRandomArray<UInt8Array>(length);
827 auto a2 = MakeRandomArray<Int16Array>(length);
828 auto a3 = MakeRandomArray<Int16Array>(5);
829
830 auto b1 = RecordBatch::Make(schema, length, {a0, a1, a2});
831
832 ASSERT_OK(b1->ValidateFull());
833
834 // Length mismatch
835 auto b2 = RecordBatch::Make(schema, length, {a0, a1, a3});
836 ASSERT_RAISES(Invalid, b2->ValidateFull());
837
838 // Type mismatch
839 auto b3 = RecordBatch::Make(schema, length, {a0, a1, a0});
840 ASSERT_RAISES(Invalid, b3->ValidateFull());
841 }
842
TEST_F(TestRecordBatch,Slice)843 TEST_F(TestRecordBatch, Slice) {
844 const int length = 10;
845
846 auto f0 = field("f0", int32());
847 auto f1 = field("f1", uint8());
848
849 std::vector<std::shared_ptr<Field>> fields = {f0, f1};
850 auto schema = ::arrow::schema(fields);
851
852 auto a0 = MakeRandomArray<Int32Array>(length);
853 auto a1 = MakeRandomArray<UInt8Array>(length);
854
855 auto batch = RecordBatch::Make(schema, length, {a0, a1});
856
857 auto batch_slice = batch->Slice(2);
858 auto batch_slice2 = batch->Slice(1, 5);
859
860 ASSERT_EQ(batch_slice->num_rows(), batch->num_rows() - 2);
861
862 for (int i = 0; i < batch->num_columns(); ++i) {
863 ASSERT_EQ(2, batch_slice->column(i)->offset());
864 ASSERT_EQ(length - 2, batch_slice->column(i)->length());
865
866 ASSERT_EQ(1, batch_slice2->column(i)->offset());
867 ASSERT_EQ(5, batch_slice2->column(i)->length());
868 }
869 }
870
TEST_F(TestRecordBatch,AddColumn)871 TEST_F(TestRecordBatch, AddColumn) {
872 const int length = 10;
873
874 auto field1 = field("f1", int32());
875 auto field2 = field("f2", uint8());
876 auto field3 = field("f3", int16());
877
878 auto schema1 = ::arrow::schema({field1, field2});
879 auto schema2 = ::arrow::schema({field2, field3});
880 auto schema3 = ::arrow::schema({field2});
881
882 auto array1 = MakeRandomArray<Int32Array>(length);
883 auto array2 = MakeRandomArray<UInt8Array>(length);
884 auto array3 = MakeRandomArray<Int16Array>(length);
885
886 auto batch1 = RecordBatch::Make(schema1, length, {array1, array2});
887 auto batch2 = RecordBatch::Make(schema2, length, {array2, array3});
888 auto batch3 = RecordBatch::Make(schema3, length, {array2});
889
890 const RecordBatch& batch = *batch3;
891
892 // Negative tests with invalid index
893 ASSERT_RAISES(Invalid, batch.AddColumn(5, field1, array1));
894 ASSERT_RAISES(Invalid, batch.AddColumn(2, field1, array1));
895 ASSERT_RAISES(Invalid, batch.AddColumn(-1, field1, array1));
896
897 // Negative test with wrong length
898 auto longer_col = MakeRandomArray<Int32Array>(length + 1);
899 ASSERT_RAISES(Invalid, batch.AddColumn(0, field1, longer_col));
900
901 // Negative test with mismatch type
902 ASSERT_RAISES(Invalid, batch.AddColumn(0, field1, array2));
903
904 ASSERT_OK_AND_ASSIGN(auto new_batch, batch.AddColumn(0, field1, array1));
905 AssertBatchesEqual(*new_batch, *batch1);
906
907 ASSERT_OK_AND_ASSIGN(new_batch, batch.AddColumn(1, field3, array3));
908 AssertBatchesEqual(*new_batch, *batch2);
909
910 ASSERT_OK_AND_ASSIGN(auto new_batch2, batch.AddColumn(1, "f3", array3));
911 AssertBatchesEqual(*new_batch2, *new_batch);
912
913 ASSERT_TRUE(new_batch2->schema()->field(1)->nullable());
914 }
915
TEST_F(TestRecordBatch,RemoveColumn)916 TEST_F(TestRecordBatch, RemoveColumn) {
917 const int length = 10;
918
919 auto field1 = field("f1", int32());
920 auto field2 = field("f2", uint8());
921 auto field3 = field("f3", int16());
922
923 auto schema1 = ::arrow::schema({field1, field2, field3});
924 auto schema2 = ::arrow::schema({field2, field3});
925 auto schema3 = ::arrow::schema({field1, field3});
926 auto schema4 = ::arrow::schema({field1, field2});
927
928 auto array1 = MakeRandomArray<Int32Array>(length);
929 auto array2 = MakeRandomArray<UInt8Array>(length);
930 auto array3 = MakeRandomArray<Int16Array>(length);
931
932 auto batch1 = RecordBatch::Make(schema1, length, {array1, array2, array3});
933 auto batch2 = RecordBatch::Make(schema2, length, {array2, array3});
934 auto batch3 = RecordBatch::Make(schema3, length, {array1, array3});
935 auto batch4 = RecordBatch::Make(schema4, length, {array1, array2});
936
937 const RecordBatch& batch = *batch1;
938 std::shared_ptr<RecordBatch> result;
939
940 // Negative tests with invalid index
941 ASSERT_RAISES(Invalid, batch.RemoveColumn(3));
942 ASSERT_RAISES(Invalid, batch.RemoveColumn(-1));
943
944 ASSERT_OK_AND_ASSIGN(auto new_batch, batch.RemoveColumn(0));
945 AssertBatchesEqual(*new_batch, *batch2);
946
947 ASSERT_OK_AND_ASSIGN(new_batch, batch.RemoveColumn(1));
948 AssertBatchesEqual(*new_batch, *batch3);
949
950 ASSERT_OK_AND_ASSIGN(new_batch, batch.RemoveColumn(2));
951 AssertBatchesEqual(*new_batch, *batch4);
952 }
953
TEST_F(TestRecordBatch,RemoveColumnEmpty)954 TEST_F(TestRecordBatch, RemoveColumnEmpty) {
955 const int length = 10;
956
957 auto field1 = field("f1", int32());
958 auto schema1 = ::arrow::schema({field1});
959 auto array1 = MakeRandomArray<Int32Array>(length);
960 auto batch1 = RecordBatch::Make(schema1, length, {array1});
961
962 ASSERT_OK_AND_ASSIGN(auto empty, batch1->RemoveColumn(0));
963 ASSERT_EQ(batch1->num_rows(), empty->num_rows());
964
965 ASSERT_OK_AND_ASSIGN(auto added, empty->AddColumn(0, field1, array1));
966 AssertBatchesEqual(*added, *batch1);
967 }
968
969 class TestTableBatchReader : public TestBase {};
970
TEST_F(TestTableBatchReader,ReadNext)971 TEST_F(TestTableBatchReader, ReadNext) {
972 ArrayVector c1, c2;
973
974 auto a1 = MakeRandomArray<Int32Array>(10);
975 auto a2 = MakeRandomArray<Int32Array>(20);
976 auto a3 = MakeRandomArray<Int32Array>(30);
977 auto a4 = MakeRandomArray<Int32Array>(10);
978
979 auto sch1 = arrow::schema({field("f1", int32()), field("f2", int32())});
980
981 std::vector<std::shared_ptr<ChunkedArray>> columns;
982
983 std::shared_ptr<RecordBatch> batch;
984
985 std::vector<std::shared_ptr<Array>> arrays_1 = {a1, a4, a2};
986 std::vector<std::shared_ptr<Array>> arrays_2 = {a2, a2};
987 columns = {std::make_shared<ChunkedArray>(arrays_1),
988 std::make_shared<ChunkedArray>(arrays_2)};
989 auto t1 = Table::Make(sch1, columns);
990
991 TableBatchReader i1(*t1);
992
993 ASSERT_OK(i1.ReadNext(&batch));
994 ASSERT_EQ(10, batch->num_rows());
995
996 ASSERT_OK(i1.ReadNext(&batch));
997 ASSERT_EQ(10, batch->num_rows());
998
999 ASSERT_OK(i1.ReadNext(&batch));
1000 ASSERT_EQ(20, batch->num_rows());
1001
1002 ASSERT_OK(i1.ReadNext(&batch));
1003 ASSERT_EQ(nullptr, batch);
1004
1005 arrays_1 = {a1};
1006 arrays_2 = {a4};
1007 columns = {std::make_shared<ChunkedArray>(arrays_1),
1008 std::make_shared<ChunkedArray>(arrays_2)};
1009 auto t2 = Table::Make(sch1, columns);
1010
1011 TableBatchReader i2(*t2);
1012
1013 ASSERT_OK(i2.ReadNext(&batch));
1014 ASSERT_EQ(10, batch->num_rows());
1015
1016 // Ensure non-sliced
1017 ASSERT_EQ(a1->data().get(), batch->column_data(0).get());
1018 ASSERT_EQ(a4->data().get(), batch->column_data(1).get());
1019
1020 ASSERT_OK(i1.ReadNext(&batch));
1021 ASSERT_EQ(nullptr, batch);
1022 }
1023
TEST_F(TestTableBatchReader,Chunksize)1024 TEST_F(TestTableBatchReader, Chunksize) {
1025 auto a1 = MakeRandomArray<Int32Array>(10);
1026 auto a2 = MakeRandomArray<Int32Array>(20);
1027 auto a3 = MakeRandomArray<Int32Array>(10);
1028
1029 auto sch1 = arrow::schema({field("f1", int32())});
1030
1031 std::vector<std::shared_ptr<Array>> arrays = {a1, a2, a3};
1032 auto t1 = Table::Make(sch1, {std::make_shared<ChunkedArray>(arrays)});
1033
1034 TableBatchReader i1(*t1);
1035
1036 i1.set_chunksize(15);
1037
1038 std::shared_ptr<RecordBatch> batch;
1039 ASSERT_OK(i1.ReadNext(&batch));
1040 ASSERT_OK(batch->ValidateFull());
1041 ASSERT_EQ(10, batch->num_rows());
1042
1043 ASSERT_OK(i1.ReadNext(&batch));
1044 ASSERT_OK(batch->ValidateFull());
1045 ASSERT_EQ(15, batch->num_rows());
1046
1047 ASSERT_OK(i1.ReadNext(&batch));
1048 ASSERT_OK(batch->ValidateFull());
1049 ASSERT_EQ(5, batch->num_rows());
1050
1051 ASSERT_OK(i1.ReadNext(&batch));
1052 ASSERT_OK(batch->ValidateFull());
1053 ASSERT_EQ(10, batch->num_rows());
1054
1055 ASSERT_OK(i1.ReadNext(&batch));
1056 ASSERT_EQ(nullptr, batch);
1057 }
1058
1059 } // namespace arrow
1060