andygrove opened a new issue, #6674:
URL: https://github.com/apache/datafusion-comet/issues/6674

   ### Describe the bug
   
   When a scalar subquery sits inside an expression that Comet routes to the 
JVM codegen dispatcher, such as a Scala UDF, or `to_json` on Spark 4, the task 
fails with `requirement failed: Subquery subquery#N, [id=#M] has not finished`. 
Spark runs the same query fine.
   
   `CometScalaUDF.emitJvmCodegenDispatch` closure-serializes the bound 
expression tree into the `JvmScalarUdf` proto while `CometExecRule` converts 
the plan. That happens before the operator's `waitForSubqueries` runs, so the 
serialized `ScalarSubquery` still has `updated = false`. On the executor, 
`CometBatchKernelCodegen.generateSource` calls `ScalarSubquery.doGenCode`, 
which calls `toLiteral` and fails its `require(updated)` check.
   
   The comment in `CometBatchKernelCodegen.canHandle` says 
`ExecSubqueryExpression` is accepted because the surrounding operator populates 
the result before the bridge serializes the expression, but the serialization 
happens at planning time. The existing test `ScalaUDF composed with reused 
scalar subquery across projection and filter` keeps the subquery outside the 
UDF, so no subquery ever ends up inside a kernel there.
   
   The same plan-time serialization is on `branch-1.0` and `branch-1.1`, where 
the dispatcher is also on by default, so the released versions are likely 
affected too.
   
   ### Steps to reproduce
   
   ```scala
   spark.udf.register("plus1", (x: Int) => x + 1)
   sql("CREATE TABLE t USING parquet AS SELECT cast(id AS int) AS a FROM 
range(10)")
   sql("SELECT plus1((SELECT max(a) FROM t)) FROM t").collect()
   ```
   
   ```
   java.lang.IllegalArgumentException: requirement failed: Subquery subquery#2, 
[id=#79] has not finished
     at 
org.apache.spark.sql.execution.ScalarSubquery.toLiteral(subquery.scala:108)
     at 
org.apache.spark.sql.execution.ScalarSubquery.doGenCode(subquery.scala:104)
     ...
     at 
org.apache.comet.codegen.CometBatchKernelCodegen$.generateSource(CometBatchKernelCodegen.scala:292)
     at 
org.apache.comet.codegen.CometBatchKernelCodegen$.compile(CometBatchKernelCodegen.scala:225)
     at 
org.apache.comet.udf.codegen.CometScalaUDFCodegen.lookupOrCompile(CometScalaUDFCodegen.scala:169)
   ```
   
   On Spark 4.x, `SELECT to_json(named_struct('m', (SELECT max(a) FROM t))) 
FROM t` fails the same way, since `to_json` lowers to an `Invoke` that goes 
through the dispatcher.
   
   Reproduced on `main` at 8a7e66441 with the default Spark 4.1 profile. The 
same failure shows up on the 3.5 and 4.2 profiles.
   
   ### Expected behavior
   
   The query returns Spark's result, either by keeping the subquery out of the 
dispatched kernel or by falling back.
   
   ### Additional context
   
   Adding `case _: ExecSubqueryExpression => true` to the rejection list in 
`CometBatchKernelCodegen.canHandle` makes these queries fall back and match 
Spark, and `CometCodegenSuite` still passes with that change. A longer-term 
option is to pass the subquery value into the kernel as a data argument that 
native evaluates, rather than serializing the subquery into the kernel.
   
   #5889 makes this easier to hit, because struct-typed scalar subqueries, 
including the ones `MergeScalarSubqueries` creates, stop falling back. For 
example, `SELECT plus1((SELECT max(a) FROM t)), plus1((SELECT min(a) FROM t)) 
FROM t` falls back on `main` because of the struct-typed merged subquery, and 
fails with #5889.
   
   Related: #5572
   


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