Copilot commented on code in PR #55348:
URL: https://github.com/apache/arrow/pull/55348#discussion_r4429053687


##########
cpp/src/parquet/arrow/schema.cc:
##########
@@ -100,6 +100,24 @@ Status ListToNode(const 
std::shared_ptr<::arrow::BaseListType>& type,
                   const std::string& name, bool nullable, int field_id,
                   const WriterProperties& properties,
                   const ArrowWriterProperties& arrow_properties, NodePtr* out) 
{
+  if (type->id() == ArrowTypeId::FIXED_SIZE_LIST &&
+      arrow_properties.vector_logical_type() &&
+      type->value_type()->id() != ArrowTypeId::DICTIONARY) {

Review Comment:
   The eligibility probe must exclude unsupported element storage types before 
calling `FieldToNode`: `FixedSizeList<null>` fails with `NullType Arrow field 
must be nullable`, while nested FixedSizeLists repeatedly convert the same 
subtree and cause exponential schema-conversion work. An extension backed by 
`dictionary<int32, float>` also bypasses the current guard, allowing referenced 
NaN/Inf values into a VECTOR file without validation. Unwrap extension storage 
and exclude null, dictionary, and nested types before the probe so they use the 
ordinary LIST path.



##########
cpp/src/parquet/arrow/schema.cc:
##########
@@ -842,11 +860,53 @@ Status ListToSchemaField(const GroupNode& group, 
LevelInfo current_levels,
   return Status::OK();
 }
 
+Status VectorToSchemaField(const GroupNode& group, LevelInfo current_levels,
+                           SchemaTreeContext* ctx, const SchemaField* parent,
+                           SchemaField* out) {
+  // The canonical structure is validated when the GroupNode is created:
+  //
+  // required/optional group name=whatever (VECTOR(N)) {
+  //   repeated group name=list {
+  //     required TYPE element;
+  //   }
+  // }
+  //
+  // yields fixed_size_list<element: TYPE not null>[N] ?nullable
+  const auto& vector_type = checked_cast<const 
VectorLogicalType&>(*group.logical_type());
+
+  if (group.is_optional()) {
+    current_levels.IncrementOptional();
+  }
+
+  out->children.resize(1);
+  SchemaField* child_field = &out->children[0];
+
+  ctx->LinkParent(out, parent);
+  ctx->LinkParent(child_field, out);
+
+  int16_t repeated_ancestor_def_level = current_levels.IncrementRepeated();
+  const auto& list_group = checked_cast<const GroupNode&>(*group.field(0));
+  RETURN_NOT_OK(
+      NodeToSchemaField(*list_group.field(0), current_levels, ctx, out, 
child_field));
+
+  out->field = ::arrow::field(
+      group.name(),
+      ::arrow::fixed_size_list(child_field->field, vector_type.num_elements()),
+      group.is_optional(), FieldIdMetadata(group.field_id()));

Review Comment:
   A required VECTOR inside a nullable struct fails to read when the struct is 
null, including `struct_with_required_vector` in the new Python test. 
`ListReader` creates a zero-length slot without a validity bitmap, so 
`FixedSizeListReader` treats it as a present vector and rejects its length. 
Update the reader to pad slots masked by null ancestors while continuing to 
reject wrong-sized present vectors.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to