Skip to content

Commit 37c9804

Browse files
wesmpitrou
authored andcommitted
ARROW-8863: [C++] Ensure that ArrayData::null_count is always set to 0 when using ArrayData::Make and supplying null validity bitmap
Closes apache#7450 from wesm/ARROW-8863 Authored-by: Wes McKinney <wesm@apache.org> Signed-off-by: Antoine Pitrou <antoine@python.org>
1 parent 442ed0f commit 37c9804

3 files changed

Lines changed: 33 additions & 12 deletions

File tree

‎cpp/src/arrow/array/array_binary_test.cc‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ class TestStringArray : public ::testing::Test {
109109
AssertZeroPadded(*strings_);
110110
}
111111

112+
void TestArrayCtors() {
113+
// ARROW-8863: ArrayData::null_count set to 0 when no validity bitmap
114+
// provided
115+
ArrayType arr(length_, offsets_buf_, value_buf_);
116+
ASSERT_EQ(arr.data()->null_count, 0);
117+
}
118+
112119
void TestTotalValuesLength() {
113120
auto ty = TypeTraits<T>::type_singleton();
114121
auto arr = ArrayFromJSON(ty, R"(["a", null, "bbb", "cccc", "ddddd"])");
@@ -293,6 +300,8 @@ TYPED_TEST_SUITE(TestStringArray, StringTypes);
293300

294301
TYPED_TEST(TestStringArray, TestArrayBasics) { this->TestArrayBasics(); }
295302

303+
TYPED_TEST(TestStringArray, TestArrayCtors) { this->TestArrayCtors(); }
304+
296305
TYPED_TEST(TestStringArray, TestType) { this->TestType(); }
297306

298307
TYPED_TEST(TestStringArray, TestListFunctions) { this->TestListFunctions(); }

‎cpp/src/arrow/array/array_test.cc‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ TEST_F(TestArray, ValidateBuffersPrimitive) {
363363
array = MakeArray(data);
364364
ASSERT_RAISES(Invalid, array->Validate());
365365

366-
// Null buffer absent but null_count > 0
366+
// Null buffer absent but null_count > 0.
367367
data = ArrayData::Make(int64(), 2, {nullptr, data_buffer}, 1);
368368
array = MakeArray(data);
369369
ASSERT_RAISES(Invalid, array->Validate());
@@ -410,6 +410,13 @@ TEST(TestNullBuilder, Basics) {
410410
// ----------------------------------------------------------------------
411411
// Primitive type tests
412412

413+
TEST(TestPrimitiveArray, CtorNoValidityBitmap) {
414+
// ARROW-8863
415+
std::shared_ptr<Buffer> data = *AllocateBuffer(40);
416+
Int32Array arr(10, data);
417+
ASSERT_EQ(arr.data()->null_count, 0);
418+
}
419+
413420
TEST_F(TestBuilder, TestReserve) {
414421
UInt8Builder builder(pool_);
415422

‎cpp/src/arrow/array/data.cc‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,24 @@ namespace arrow {
3636

3737
using internal::CountSetBits;
3838

39+
static inline void AdjustNonNullable(std::vector<std::shared_ptr<Buffer>>* buffers,
40+
int64_t* null_count) {
41+
if (buffers->size() > 0) {
42+
if (*null_count == 0) {
43+
// In case there are no nulls, don't keep an allocated null bitmap around
44+
(*buffers)[0] = nullptr;
45+
} else if (*null_count == kUnknownNullCount && buffers->at(0) == nullptr) {
46+
// Conversely, if no null bitmap is provided, set the null count to 0
47+
*null_count = 0;
48+
}
49+
}
50+
}
51+
3952
std::shared_ptr<ArrayData> ArrayData::Make(const std::shared_ptr<DataType>& type,
4053
int64_t length,
4154
std::vector<std::shared_ptr<Buffer>> buffers,
4255
int64_t null_count, int64_t offset) {
43-
// In case there are no nulls, don't keep an allocated null bitmap around
44-
if (buffers.size() > 0 && null_count == 0) {
45-
buffers[0] = nullptr;
46-
}
56+
AdjustNonNullable(&buffers, &null_count);
4757
return std::make_shared<ArrayData>(type, length, std::move(buffers), null_count,
4858
offset);
4959
}
@@ -53,10 +63,7 @@ std::shared_ptr<ArrayData> ArrayData::Make(
5363
std::vector<std::shared_ptr<Buffer>> buffers,
5464
std::vector<std::shared_ptr<ArrayData>> child_data, int64_t null_count,
5565
int64_t offset) {
56-
// In case there are no nulls, don't keep an allocated null bitmap around
57-
if (buffers.size() > 0 && null_count == 0) {
58-
buffers[0] = nullptr;
59-
}
66+
AdjustNonNullable(&buffers, &null_count);
6067
return std::make_shared<ArrayData>(type, length, std::move(buffers),
6168
std::move(child_data), null_count, offset);
6269
}
@@ -66,9 +73,7 @@ std::shared_ptr<ArrayData> ArrayData::Make(
6673
std::vector<std::shared_ptr<Buffer>> buffers,
6774
std::vector<std::shared_ptr<ArrayData>> child_data,
6875
std::shared_ptr<ArrayData> dictionary, int64_t null_count, int64_t offset) {
69-
if (buffers.size() > 0 && null_count == 0) {
70-
buffers[0] = nullptr;
71-
}
76+
AdjustNonNullable(&buffers, &null_count);
7277
auto data = std::make_shared<ArrayData>(type, length, std::move(buffers),
7378
std::move(child_data), null_count, offset);
7479
data->dictionary = std::move(dictionary);

0 commit comments

Comments
 (0)