comphead opened a new issue, #11612:
URL: https://github.com/apache/arrow-rs/issues/11612

   **Describe the bug**
   
   `Fields::filter_leaves` and `Fields::try_filter_leaves` treat `ListView` and 
`LargeListView` as leaves. The docs say the filter is invoked "for each 
[`FieldRef`] containing no child [`FieldRef`], a leaf field", but a list view 
has a child, its element. So the filter is called once for the list view field 
itself instead of for the leaves under its element, and the leaf index of every 
later field is off by that number of leaves minus one. `List`, `LargeList`, and 
`FixedSizeList` are descended into.
   
   **To Reproduce**
   
   With `arrow-schema = "=60.0.0"`:
   
   ```rust
   use std::sync::Arc;
   
   use arrow_schema::{DataType, Field, Fields};
   
   fn main() {
       // An element with two leaves, `a` and `b`.
       let element = Arc::new(Field::new(
           "element",
           DataType::Struct(Fields::from(vec![
               Field::new("a", DataType::Int32, true),
               Field::new("b", DataType::Int32, true),
           ])),
           true,
       ));
       for (name, list) in [
           ("List", DataType::List(Arc::clone(&element))),
           ("ListView", DataType::ListView(Arc::clone(&element))),
           ("LargeListView", DataType::LargeListView(Arc::clone(&element))),
       ] {
           let fields = Fields::from(vec![
               Field::new("l", list, true),
               Field::new("id", DataType::Int32, true),
           ]);
           let mut leaves = Vec::new();
           fields.filter_leaves(|idx, field| {
               leaves.push(format!("{idx}: {}", field.name()));
               false
           });
           let kept = fields.filter_leaves(|idx, _| idx == 0);
           println!("{name}: leaves {leaves:?}, keeping leaf 0 keeps {}", 
kept[0].data_type());
       }
   }
   ```
   
   ```text
   List: leaves ["0: a", "1: b", "2: id"], keeping leaf 0 keeps 
List(Struct("a": Int32), field: 'element')
   ListView: leaves ["0: l", "1: id"], keeping leaf 0 keeps 
ListView(Struct("a": Int32, "b": Int32), field: 'element')
   LargeListView: leaves ["0: l", "1: id"], keeping leaf 0 keeps 
LargeListView(Struct("a": Int32, "b": Int32), field: 'element')
   ```
   
   **Expected behavior**
   
   List views are descended into like `List` and `LargeList`. The leaves are 
`a`, `b`, and `id`, and keeping leaf 0 keeps `ListView(Struct("a": Int32))`. 
The match in `try_filter_leaves` on `main` (`fedfd0dbb`) has no list view arms, 
so adding `ListView` and `LargeListView` next to `List` and `LargeList` should 
be enough.
   
   **Additional context**
   
   iceberg-rust uses these leaf indices as Parquet leaf column indices for 
`ProjectionMask::leaves`. parquet-rs reads a Parquet LIST as `ListView` when 
the file's embedded Arrow schema says so, so the two numberings disagree. A 
list view column then read as NULL, and a column after a list view of structs 
was read from the wrong Parquet leaf (apache/iceberg-rust#3393). DataFusion's 
own leaf counting already descends into list views (`count_leaves` in 
`datafusion/datasource-parquet/src/nested_schema_pruning.rs`).
   


-- 
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