Skip to content

Commit

Permalink
apacheGH-33971: [C++] Fix AdaptiveIntBuilder to always populate data …
Browse files Browse the repository at this point in the history
…buffer (apache#33994)

If the AdaptiveIntBuilder was empty it would yield a null for the values buffer.  The byte_size.h utilities were not expecting this which led to the error reported in the issue.

Example:

```
>>> pa.array([], type=pa.dictionary(pa.int32(), pa.string())).buffers()
[None, None]
```
* Closes: apache#33971

Authored-by: Weston Pace <[email protected]>
Signed-off-by: Weston Pace <[email protected]>
  • Loading branch information
westonpace authored Feb 7, 2023
1 parent 4e89d9a commit a6ace68
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
12 changes: 12 additions & 0 deletions cpp/src/arrow/array/array_dict_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ TYPED_TEST(TestDictionaryBuilder, MakeBuilder) {
AssertArraysEqual(expected, *result);
}

TYPED_TEST(TestDictionaryBuilder, Empty) {
DictionaryBuilder<TypeParam> dictionary_builder;
ASSERT_OK_AND_ASSIGN(std::shared_ptr<Array> empty_arr, dictionary_builder.Finish());
std::shared_ptr<DictionaryArray> empty_dict_arr =
checked_pointer_cast<DictionaryArray>(empty_arr);
// Ensure that the indices value buffer is initialized
ASSERT_NE(nullptr, empty_dict_arr->data()->buffers[1]);
// Ensure that the dictionary's value buffer is initialized
ASSERT_NE(nullptr, empty_dict_arr->dictionary());
ASSERT_NE(nullptr, empty_dict_arr->dictionary()->data()->buffers[1]);
}

TYPED_TEST(TestDictionaryBuilder, ArrayConversion) {
auto type = std::make_shared<TypeParam>();

Expand Down
14 changes: 13 additions & 1 deletion cpp/src/arrow/array/array_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,17 @@ class TestAdaptiveIntBuilder : public TestBuilder {
builder_ = std::make_shared<AdaptiveIntBuilder>(pool_);
}

void Done() { FinishAndCheckPadding(builder_.get(), &result_); }
void EnsureValuesBufferNotNull(const ArrayData& data) {
// The values buffer should be initialized
ASSERT_EQ(2, data.buffers.size());
ASSERT_NE(nullptr, data.buffers[1]);
ASSERT_NE(nullptr, data.buffers[1]->data());
}

void Done() {
FinishAndCheckPadding(builder_.get(), &result_);
EnsureValuesBufferNotNull(*result_->data());
}

template <typename ExpectedType>
void TestAppendValues() {
Expand Down Expand Up @@ -2571,6 +2581,8 @@ TEST_F(TestAdaptiveIntBuilder, TestAppendEmptyValue) {
AssertArraysEqual(*result_, *ArrayFromJSON(int8(), "[null, null, 0, 42, 0, 0]"));
}

TEST_F(TestAdaptiveIntBuilder, Empty) { Done(); }

TEST(TestAdaptiveIntBuilderWithStartIntSize, TestReset) {
auto builder = std::make_shared<AdaptiveIntBuilder>(
static_cast<uint8_t>(sizeof(int16_t)), default_memory_pool());
Expand Down
8 changes: 7 additions & 1 deletion cpp/src/arrow/array/builder_adaptive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,13 @@ Status AdaptiveIntBuilder::FinishInternal(std::shared_ptr<ArrayData>* out) {
RETURN_NOT_OK(null_bitmap_builder_.Finish(&null_bitmap));
RETURN_NOT_OK(TrimBuffer(length_ * int_size_, data_.get()));

*out = ArrayData::Make(type(), length_, {null_bitmap, data_}, null_count_);
std::shared_ptr<Buffer> values_buffer = data_;
if (!values_buffer) {
ARROW_ASSIGN_OR_RAISE(values_buffer, AllocateBuffer(0, pool_));
}

*out = ArrayData::Make(type(), length_, {null_bitmap, std::move(values_buffer)},
null_count_);

data_ = nullptr;
capacity_ = length_ = null_count_ = 0;
Expand Down

0 comments on commit a6ace68

Please sign in to comment.