matanper opened a new issue, #69930:
URL: https://github.com/apache/doris/issues/69930

   ### Search before asking
   
   - [x] I had searched in the issues and found no similar issues.
   
   ### Version
   
   4.1.x (the same code is on master)
   
   ### What's Wrong?
   
   A query whose lambda reads both an outer column and a struct field of its 
own argument fails to plan when the array comes from the other side of a join 
(here an uncorrelated scalar subquery):
   
   ```sql
   SELECT k,
          STRUCT_ELEMENT(ARRAY_FIRST(p -> STRUCT_ELEMENT(p, 1) = k,
            (SELECT ARRAY_ZIP(COLLECT_LIST(v), COLLECT_LIST(r))
             FROM (SELECT 'a' AS v, 'x' AS r UNION ALL SELECT 'b', 'y') s)), 2) 
AS h,
          COUNT() AS c
   FROM (SELECT 'a' AS k UNION ALL SELECT 'b') t
   GROUP BY k;
   -- errCode = 2, detailMessage = Cannot invoke 
"org.apache.doris.analysis.Expr.getChildren()" because "root" is null
   ```
   
   Without `GROUP BY` the error is `Cannot read field "type" because the return 
value of "java.util.ArrayList.get(int)" is null`. `COLLECT_LIST(STRUCT(v, r))` 
instead of `ARRAY_ZIP` fails the same way. It works when the lambda reads no 
outer column, when the array is `ARRAY<STRING>` (`p -> p = k`), or with `SET 
enable_prune_nested_column = false`.
   
   Cause: `PushDownProject` (`PUSH_DOWN_PROJECT_THROUGH_JOIN`) moves a 
`PreferPushDownProject` expression to the first child whose output contains all 
of the expression's input slots:
   
   ```java
   if (child.getOutputSet().containsAll(e.getInputSlots())) {
   ```
   
   `Expression.getInputSlots()` leaves out lambda arguments (`ArrayItemSlot`), 
so `element_at(p, 'col1')` inside the lambda has no input slots, and the check 
passes for any child. The rewritten plan pushes it into the join's left side, 
where `p` does not exist:
   
   ```
   LogicalJoin ( type=CROSS_JOIN )
   |--LogicalUnion ( outputs=[k#10, element_at(p, 'col1')#18],
   |                 constantExprsList=[['a' AS `k`#1, element_at(p#16, 'col1') 
AS `element_at(p, 'col1')`#22], ...] )
   +--LogicalProject ( projects=[array_zip(...) AS `ARRAY_ZIP(...)`#13] )
   ```
   
   `PhysicalPlanTranslator.visitPhysicalProject` then gets a null `Expr` for 
`p#16`, and `Expr.extractSlots` throws.
   
   ### What You Expected?
   
   The query returns `a, x, 1` and `b, y, 1`.
   
   ### How to Reproduce?
   
   Run the query above on a default session (`enable_prune_nested_column = 
true`). It needs no table.
   
   ### Anything Else?
   
   A possible fix: in `PushDownProject`, don't push an expression that uses a 
lambda argument it does not bind itself. A whole lambda function such as 
`array_map(p -> element_at(p, 'a'), arr)` binds its own argument and can still 
be pushed toward the side that produces `arr`.
   
   ### Are you willing to submit PR?
   
   - [x] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's Code of Conduct
   


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