dongjoon-hyun opened a new pull request, #59818:
URL: https://github.com/apache/spark/pull/59818

   ### What changes were proposed in this pull request?
   
   `FileSourceScanLike.metadata` builds `PushedFilters` for display. The scalar 
subqueries have not run yet at that point, so it replaces each one with the 
string literal `ScalarSubquery#<id>` and translates the data filters to V1 
filters. The `In` arm of the V1 translator 
(`DataSourceStrategy.translateLeafNodeFilter`) accepts an `In` once all its 
list items are literals, and converts them with the Scala converter of the 
column type. For a `DATE`, `TIMESTAMP`, `TIMESTAMP_NTZ` or `DECIMAL` column, 
converting the string throws `ClassCastException`.
   
   This PR leaves out of `PushedFilters` a data filter that has an `In` with a 
scalar subquery in its list. The filter is still pushed down at run time, where 
`pushedDownFilters` replaces each subquery with a literal of its result. 
Comparisons with scalar subqueries, like `GreaterThan(c,ScalarSubquery#1)`, are 
displayed as before, since they convert a value by the type of the literal.
   
   ### Why are the changes needed?
   
   With Parquet tables `t1(d DATE)` and `t2(d DATE)`, this query fails before 
any job runs:
   
   ```sql
   SELECT * FROM t1 WHERE d IN (DATE'2020-01-05', (SELECT max(d) FROM t2))
   ```
   
   ```
   java.lang.ClassCastException: class org.apache.spark.unsafe.types.UTF8String 
cannot be cast to class java.lang.Integer 
(org.apache.spark.unsafe.types.UTF8String is in unnamed module of loader 'app'; 
java.lang.Integer is in module java.base of loader 'bootstrap')
     at 
org.apache.spark.sql.catalyst.CatalystTypeConverters$DateConverter$.toScala(CatalystTypeConverters.scala:425)
     ...
     at 
org.apache.spark.sql.execution.datasources.DataSourceStrategy$.translateLeafNodeFilter(DataSourceStrategy.scala:680)
     ...
     at 
org.apache.spark.sql.execution.FileSourceScanLike.metadata(DataSourceScanExec.scala:553)
     ...
     at 
org.apache.spark.sql.execution.QueryExecution.explainString(QueryExecution.scala:531)
     at 
org.apache.spark.sql.execution.SQLExecution$.planDescription(SQLExecution.scala:197)
     ...
     at org.apache.spark.sql.classic.Dataset.collect(Dataset.scala:1623)
   ```
   
   `SQLExecution` builds the plan description of a query, which shows 
`PushedFilters`, when the query starts. `Dataset.explain` throws the same 
exception, and SQL `EXPLAIN` prints `Error occurred during query planning` 
instead of the plan. `NOT IN`, an `IN` under `OR`, and `d IN ((SELECT min(d) 
FROM t2), (SELECT max(d) FROM t2))` with 
`spark.sql.execution.reuseSubquery=false` fail the same way. With the default 
`true`, the two subqueries of the last query are merged into one, and the `IN` 
is not translated.
   
   This fails since 
[v4.0.0](https://github.com/apache/spark/releases/tag/v4.0.0) (2025-05-19), 
which added the pushdown of data filters with scalar subqueries (SPARK-43402) 
and their display as `ScalarSubquery#<id>` (SPARK-44655). Before that, such 
filters were not given to the scan.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. These queries run, and EXPLAIN shows their plans. `PushedFilters` no 
longer lists a filter with an `IN` that has scalar subqueries, whatever the 
column type. For example, `In(c, [5,ScalarSubquery#12])` on an `INT` column was 
displayed before. The filter is still pushed down to the data source, and query 
results do not change.
   
   ### How was this patch tested?
   
   Added a test to `SubquerySuite`, "SPARK-60577: FileSourceScanExec supports 
push down IN data filter with scalar subquery". On `DATE`, `TIMESTAMP` and 
`DECIMAL` columns of Parquet tables, it runs an `IN` with a literal and a 
subquery, and an `IN` with two subqueries under 
`spark.sql.execution.reuseSubquery=false`. It checks that EXPLAIN (simple and 
formatted) and the query run, that `PushedFilters` has no `In(`, and through 
the scan's `numOutputRows` that the `IN` still skips the row group. Without the 
main change, the test fails with `ClassCastException`.
   
   These also pass locally: `SubquerySuite`, `ExplainSuite`, `ExplainSuiteAE`, 
the TPC-DS and TPC-H plan stability suites (no approved plan changes), and the 
`explain*.sql` cases of `SQLQueryTestSuite`.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Opus 5.5


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