diff --git a/cpp/src/arrow/json/parser.cc b/cpp/src/arrow/json/parser.cc index 69373d07fb6..ad2d3781e4c 100644 --- a/cpp/src/arrow/json/parser.cc +++ b/cpp/src/arrow/json/parser.cc @@ -526,50 +526,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(); } @@ -669,7 +670,7 @@ class ParseImpl : public BlockParser { Status Null() { DCHECK(!builder_stack_.empty()); - return builder_set_.AppendNull(builder_stack_.back(), field_index_, builder_); + return builder_set_.AppendNull(builder_stack_.back(), field_index_, &builder_); } Status HandleUnexpectedField(std::string_view key, sj::value& value) { @@ -966,7 +967,7 @@ class ParseImpl : 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 6c32fd7cab3..1196e3a654e 100644 --- a/cpp/src/arrow/json/parser_test.cc +++ b/cpp/src/arrow/json/parser_test.cc @@ -236,6 +236,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(BlockParserWithSchema, ValidateIgnoredFields) { auto options = ParseOptions::Defaults(); options.explicit_schema = schema({field("known", int64())}); @@ -286,6 +297,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"( {}