viirya commented on code in PR #24680:
URL: https://github.com/apache/datafusion/pull/24680#discussion_r3864814890


##########
datafusion/physical-expr-adapter/src/schema_rewriter.rs:
##########
@@ -309,26 +313,58 @@ fn resolve_field_path<'a>(
     }
 }
 
+/// Retain a field path without changing its ancestors' metadata or 
nullability.
+fn retain_field_path(field: &FieldRef, path: &[&str]) -> Option<FieldRef> {

Review Comment:
   `retain_field_path` and the existing `resolve_field_path` sit next to each 
other and read as near-synonyms, but they do different jobs: one resolves a key 
path to a leaf for inspection, the other rebuilds a trimmed cast target that 
keeps the ancestors intact. The doc comment explains the *what* ("retain a 
field path without changing its ancestors' metadata or nullability"); a clause 
on *why it exists* — to exclude unselected siblings from a conversion while 
keeping the Struct ancestors for Arrow's all-null shortcut — would connect it 
to the decimal case that motivates it. A name closer to that purpose 
(`trim_cast_target_to_path`, say) would also help, though renaming is entirely 
your call.



##########
datafusion/physical-expr-adapter/src/schema_rewriter.rs:
##########
@@ -271,6 +272,9 @@ impl PhysicalExprAdapter for DefaultPhysicalExprAdapter {
 struct DefaultPhysicalExprAdapterRewriter {
     logical_file_schema: SchemaRef,
     physical_file_schema: SchemaRef,
+    // Retain generated casts so their pointer identity remains reliable even
+    // after a wider cast has been removed from the expression tree.
+    generated_struct_casts: HashMap<*const (), Arc<dyn PhysicalExpr>>,

Review Comment:
   This map's soundness rests on three things, and only the second is currently 
stated:
   
   1. `rewrite()` uses `expr.transform(...)`, which is bottom-up, so a `Column` 
becomes a generated cast *before* the parent `get_field` is visited — that is 
what makes the child `Arc` the parent sees the same allocation that was 
recorded.
   2. The map holds an owned `Arc` clone, so the allocation cannot be freed and 
its address recycled (the part the current comment covers).
   3. The rewriter is constructed per `rewrite()` call, so keys never leak 
across expressions.
   
   Point 1 is the fragile one: switching to `transform_down`, or hoisting the 
rewriter to be reused across expressions, would silently stop narrowing. The 
failure is fail-closed — it would under-optimise rather than mis-narrow — so 
this isn't a correctness worry, but it is a silent performance regression that 
no test would catch. Could the comment name the traversal-order dependency 
explicitly?
   
   Separately, and only if it isn't invasive: was a structural marker 
considered instead of pointer identity — threading "this cast was generated" 
out through the rewrite result, or a thin wrapper type around generated casts? 
That would remove this whole class of concern rather than documenting around 
it. If you tried it and it spread too far through the rewriter, saying so in 
the comment would save the next person from re-litigating 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