zhuqi-lucas commented on code in PR #24125:
URL: https://github.com/apache/datafusion/pull/24125#discussion_r3730087936


##########
datafusion/physical-expr-adapter/src/schema_rewriter.rs:
##########
@@ -273,6 +273,35 @@ struct DefaultPhysicalExprAdapterRewriter {
     physical_file_schema: SchemaRef,
 }
 
+/// Outcome of walking a `get_field` key path through nested struct fields.
+enum FieldPathResolution<'a> {
+    /// The leaf field the path points at.
+    Found(&'a FieldRef),
+    /// Some key along the path does not exist, so the access reads as null.
+    Missing,
+    /// An intermediate field is not a struct, so the path cannot be resolved
+    /// statically.
+    NotAStruct,
+}
+
+/// Follow a `get_field` key path (`['a', 'b']` for `s['a']['b']`) through
+/// nested struct fields.
+fn resolve_field_path<'a>(fields: &'a Fields, path: &[&str]) -> 
FieldPathResolution<'a> {
+    let Some((field_name, rest)) = path.split_first() else {
+        return FieldPathResolution::NotAStruct;

Review Comment:
   Minor: an empty `path` here returns `NotAStruct`, which reads a little oddly 
— an empty path is not really "not a struct". It is unreachable given the 
non-empty `field_name_exprs` guard in `try_narrow_struct_cast`, so a one-line 
comment noting it is a defensive default would save the next reader a 
double-take.



##########
datafusion/physical-expr-adapter/src/schema_rewriter.rs:
##########
@@ -282,13 +311,130 @@ impl DefaultPhysicalExprAdapterRewriter {
             return Ok(Transformed::yes(transformed));
         }
 
+        if let Some(transformed) = self.try_narrow_struct_cast(&expr)? {
+            return Ok(Transformed::yes(transformed));
+        }
+
         if let Some(column) = expr.downcast_ref::<Column>() {
             return self.rewrite_column(Arc::clone(&expr), column);
         }
 
         Ok(Transformed::no(expr))
     }
 
+    /// Rewrite `get_field(cast(s AS Struct<..>), 'f')` into

Review Comment:
   Nice fix. One design question for the record: did you consider teaching the 
pushdown side (`PushdownChecker` / row-filter builder) to see through the cast 
— i.e. recognize `get_field(cast(col), 'f')` — instead of narrowing it here?
   
   I assume narrowing was chosen because (a) it avoids materializing the whole 
cast struct just to read one field, and (b) it fixes it at the source, so 
*every* consumer that pattern-matches `get_field(column, 'f')` benefits — not 
just the row filter — rather than loosening the pushdown contract to see 
through arbitrary casts. Worth capturing that rationale.
   
   Relatedly, the PR notes the broader planning-vs-runtime schema divergence is 
intentionally out of scope — a tracking issue for the "safe by construction" 
mechanism (e.g. post-decode filtering in `ParquetOpener`) would be good so it 
is not lost. Happy to file it.



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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to