diff --git a/cpp/src/arrow/json/parser.cc b/cpp/src/arrow/json/parser.cc index 53f856d8012..1d50b13cca1 100644 --- a/cpp/src/arrow/json/parser.cc +++ b/cpp/src/arrow/json/parser.cc @@ -529,50 +529,51 @@ class RawBuilderSet { /// Appending null is slightly tricky since null count is stored inline /// for builders of Kind::kNull. Append nulls using this helper - Status AppendNull(BuilderPtr parent, int field_index, BuilderPtr builder) { - if (ARROW_PREDICT_FALSE(!builder.nullable)) { + Status AppendNull(BuilderPtr parent, int field_index, BuilderPtr* builder) { + if (ARROW_PREDICT_FALSE(!builder->nullable)) { return ParseError("a required field was null"); } - switch (builder.kind) { + switch (builder->kind) { case Kind::kNull: { - DCHECK_EQ(builder, parent.kind == Kind::kArray - ? Cast(parent)->value_builder() - : Cast(parent)->field_builder(field_index)); + DCHECK_EQ(*builder, + parent.kind == Kind::kArray + ? Cast(parent)->value_builder() + : Cast(parent)->field_builder(field_index)); // increment null count stored inline - builder.index += 1; + builder->index += 1; // update the parent, since changing builder doesn't affect parent if (parent.kind == Kind::kArray) { - Cast(parent)->value_builder(builder); + Cast(parent)->value_builder(*builder); } else { - Cast(parent)->field_builder(field_index, builder); + Cast(parent)->field_builder(field_index, *builder); } return Status::OK(); } case Kind::kBoolean: - return Cast(builder)->AppendNull(); + return Cast(*builder)->AppendNull(); case Kind::kNumber: - return Cast(builder)->AppendNull(); + return Cast(*builder)->AppendNull(); case Kind::kString: - return Cast(builder)->AppendNull(); + return Cast(*builder)->AppendNull(); case Kind::kNumberOrString: { - return Cast(builder)->AppendNull(); + return Cast(*builder)->AppendNull(); } case Kind::kArray: - return Cast(builder)->AppendNull(); + return Cast(*builder)->AppendNull(); case Kind::kObject: { - auto struct_builder = Cast(builder); + auto struct_builder = Cast(*builder); RETURN_NOT_OK(struct_builder->AppendNull()); for (int i = 0; i < struct_builder->num_fields(); ++i) { auto field_builder = struct_builder->field_builder(i); - RETURN_NOT_OK(AppendNull(builder, i, field_builder)); + RETURN_NOT_OK(AppendNull(*builder, i, &field_builder)); } return Status::OK(); } @@ -672,7 +673,7 @@ class HandlerBase : public BlockParser, /// /// @{ bool Null() { - status_ = builder_set_.AppendNull(builder_stack_.back(), field_index_, builder_); + status_ = builder_set_.AppendNull(builder_stack_.back(), field_index_, &builder_); return status_.ok(); } @@ -869,7 +870,7 @@ class HandlerBase : public BlockParser, if (ARROW_PREDICT_FALSE(!field_builder.nullable)) { return ParseError("a required field was absent"); } - RETURN_NOT_OK(builder_set_.AppendNull(parent, i, field_builder)); + RETURN_NOT_OK(builder_set_.AppendNull(parent, i, &field_builder)); } absent_fields_stack_.Pop(); EndNested(); diff --git a/cpp/src/arrow/json/parser_test.cc b/cpp/src/arrow/json/parser_test.cc index 1b107aa020f..e10b6c73f9d 100644 --- a/cpp/src/arrow/json/parser_test.cc +++ b/cpp/src/arrow/json/parser_test.cc @@ -235,6 +235,17 @@ TEST(BlockParserWithSchema, FailOnIncompleteJson) { ASSERT_RAISES(Invalid, ParseFromString(options, "{\"a\":0, \"b\"", &parsed)); } +TEST(BlockParserWithSchema, NullsInList) { + auto options = ParseOptions::Defaults(); + options.explicit_schema = schema({field("a", list(null()))}); + for (auto behavior : + {UnexpectedFieldBehavior::Error, UnexpectedFieldBehavior::Ignore}) { + options.unexpected_field_behavior = behavior; + AssertParseColumns(options, R"({"a": [null, null]})", {field("a", list(null()))}, + {"[[null, null]]"}); + } +} + TEST(BlockParser, Basics) { auto options = ParseOptions::Defaults(); options.unexpected_field_behavior = UnexpectedFieldBehavior::InferType; @@ -267,6 +278,14 @@ TEST(BlockParser, Null) { R"([{"plain": null}, {"plain": null}])"}); } +TEST(BlockParser, NullsInList) { + auto options = ParseOptions::Defaults(); + options.unexpected_field_behavior = UnexpectedFieldBehavior::InferType; + AssertParseColumns(options, R"({"a": [null, null], "b": [null, "hi", null]})", + {field("a", list(null())), field("b", list(utf8()))}, + {"[[null, null]]", R"([[null, "hi", null]])"}); +} + TEST(BlockParser, InferNewFields) { std::string src = R"( {}