diff --git a/cpp/src/parquet/arrow/arrow_reader_writer_test.cc b/cpp/src/parquet/arrow/arrow_reader_writer_test.cc index d858962d472..74ee0fc1c83 100644 --- a/cpp/src/parquet/arrow/arrow_reader_writer_test.cc +++ b/cpp/src/parquet/arrow/arrow_reader_writer_test.cc @@ -3811,6 +3811,22 @@ TEST(TestArrowReadWrite, DictionaryIndexBitwidthRoundtrip) { } } +TEST(TestArrowReadWrite, DictionaryValueTypeRoundtrip) { + // GH-37875: the binary layout of dictionary values should be preserved + for (const auto& value_type : {::arrow::utf8(), ::arrow::large_utf8(), + ::arrow::binary(), ::arrow::large_binary()}) { + ARROW_SCOPED_TRACE("value_type = ", *value_type); + auto dict_type = ::arrow::dictionary(::arrow::int32(), value_type); + auto schema = ::arrow::schema({field("dictionary", dict_type)}); + auto array = DictArrayFromJSON(dict_type, R"([0, 1, null, 0])", R"(["foo", "bar"])"); + auto table = Table::Make(schema, {array}); + auto arrow_writer_props = + parquet::ArrowWriterProperties::Builder().store_schema()->build(); + + CheckSimpleRoundtrip(table, table->num_rows(), arrow_writer_props); + } +} + TEST(TestArrowWrite, CheckChunkSize) { const int num_columns = 2; const int num_rows = 128; diff --git a/cpp/src/parquet/arrow/schema.cc b/cpp/src/parquet/arrow/schema.cc index bc4de6c39b5..d25a3f73a24 100644 --- a/cpp/src/parquet/arrow/schema.cc +++ b/cpp/src/parquet/arrow/schema.cc @@ -1110,8 +1110,17 @@ Result ApplyOriginalStorageMetadata(const Field& origin_field, // so no need to recurse on value types. const auto& dict_origin_type = checked_cast(*origin_type); + auto value_type = inferred_type; + const auto& origin_value_type = dict_origin_type.value_type(); + // Restore large dictionary values (GH-37875) + if ((origin_value_type->id() == ::arrow::Type::LARGE_STRING && + inferred_type->id() == ::arrow::Type::STRING) || + (origin_value_type->id() == ::arrow::Type::LARGE_BINARY && + inferred_type->id() == ::arrow::Type::BINARY)) { + value_type = origin_value_type; + } inferred->field = inferred->field->WithType(::arrow::dictionary( - dict_origin_type.index_type(), inferred_type, dict_origin_type.ordered())); + dict_origin_type.index_type(), value_type, dict_origin_type.ordered())); modified = true; }