This is an automated email from the ASF dual-hosted git repository.

pitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 01cb4315cc7 GH-50910: [Parquet] Tolerate unrecognized logical/physical 
type combinations when reading (#50909)
01cb4315cc7 is described below

commit 01cb4315cc7b6f6ef6971682617023f592be1f94
Author: Divjot Arora <[email protected]>
AuthorDate: Thu Oct 1 09:09:27 2026 +0200

    GH-50910: [Parquet] Tolerate unrecognized logical/physical type 
combinations when reading (#50909)
    
    ### Rationale for this change
    See https://github.com/apache/parquet-format/issues/607 for rationale.
    
    ### What changes are included in this PR?
    This PR gracefully handles unrecognized logical/physical type combinations 
by dropping the logical type during the read and dropping any associated 
statistics for the relevant columns. Note that unrecognized logical types are 
already handled gracefully and no changes were required.
    
    ### Are these changes tested?
    Yes, via unit tests and an e2e test that reads a real file that contains an 
invalid type combination.
    
    ### Are there any user-facing changes?
    No
    
    * GitHub Issue: #50910
    
    Lead-authored-by: Divjot Arora <[email protected]>
    Co-authored-by: Isaac <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/parquet/arrow/arrow_schema_test.cc | 26 ++++++++++++++++++++++++++
 cpp/src/parquet/schema.cc                  | 15 +++++++++++----
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/cpp/src/parquet/arrow/arrow_schema_test.cc 
b/cpp/src/parquet/arrow/arrow_schema_test.cc
index 6fbde992463..0ec94384161 100644
--- a/cpp/src/parquet/arrow/arrow_schema_test.cc
+++ b/cpp/src/parquet/arrow/arrow_schema_test.cc
@@ -25,6 +25,7 @@
 #include "parquet/arrow/reader.h"
 #include "parquet/arrow/reader_internal.h"
 #include "parquet/arrow/schema.h"
+#include "parquet/column_reader.h"
 #include "parquet/file_reader.h"
 #include "parquet/schema.h"
 #include "parquet/schema_internal.h"
@@ -2205,6 +2206,31 @@ TEST(TestFromParquetSchema, UndefinedLogicalType) {
             *::arrow::field("column with unknown type", ::arrow::binary()));
 }
 
+TEST(TestFromParquetSchema, IncompatibleLogicalTypeDropped) {
+  // A file with INT32 annotated as UUID. The reader should succeed and ignore 
the logical
+  // type and stats.
+  auto path = test::get_data_file("int32_with_uuid_logical_type.parquet");
+  std::unique_ptr<parquet::ParquetFileReader> reader =
+      parquet::ParquetFileReader::OpenFile(path);
+
+  const auto* pq_schema = reader->metadata()->schema();
+  ASSERT_EQ(pq_schema->num_columns(), 1);
+
+  const auto* col_desc = pq_schema->Column(0);
+  ASSERT_EQ(col_desc->physical_type(), parquet::Type::INT32);
+  ASSERT_FALSE(col_desc->logical_type()->is_valid());
+  ASSERT_FALSE(col_desc->can_use_min_max());
+
+  auto row_group = reader->RowGroup(0);
+  auto col_reader = 
std::static_pointer_cast<parquet::Int32Reader>(row_group->Column(0));
+  const auto num_rows = 10;
+  std::vector<int32_t> values(num_rows);
+  int64_t values_read = 0;
+  col_reader->ReadBatch(num_rows, nullptr, nullptr, values.data(), 
&values_read);
+  ASSERT_EQ(values_read, num_rows);
+  for (int32_t i = 0; i < num_rows; ++i) ASSERT_EQ(values[i], i);
+}
+
 //
 // Test LevelInfo computation from a Parquet schema
 // (for Parquet -> Arrow reading).
diff --git a/cpp/src/parquet/schema.cc b/cpp/src/parquet/schema.cc
index 3cb91f9a84e..882c615ed07 100644
--- a/cpp/src/parquet/schema.cc
+++ b/cpp/src/parquet/schema.cc
@@ -454,10 +454,17 @@ std::unique_ptr<Node> PrimitiveNode::FromParquet(const 
void* opaque_element) {
   std::unique_ptr<PrimitiveNode> primitive_node;
   if (element->__isset.logicalType) {
     // updated writer with logical type present
-    primitive_node = std::unique_ptr<PrimitiveNode>(
-        new PrimitiveNode(element->name, 
LoadEnumSafe(&element->repetition_type),
-                          LogicalType::FromThrift(element->logicalType),
-                          LoadEnumSafe(&element->type), element->type_length, 
field_id));
+    auto physical_type = LoadEnumSafe(&element->type);
+    auto logical_type = LogicalType::FromThrift(element->logicalType);
+    // Tolerate unrecognized logical/physical type combinations by dropping 
the logical
+    // type annotation.
+    if (logical_type &&
+        !logical_type->is_applicable(physical_type, element->type_length)) {
+      logical_type = UndefinedLogicalType::Make();
+    }
+    primitive_node = std::unique_ptr<PrimitiveNode>(new PrimitiveNode(
+        element->name, LoadEnumSafe(&element->repetition_type), 
std::move(logical_type),
+        physical_type, element->type_length, field_id));
   } else if (element->__isset.converted_type) {
     // legacy writer with converted type present
     primitive_node = std::unique_ptr<PrimitiveNode>(new PrimitiveNode(

Reply via email to