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

   ### What changes were proposed in this pull request?
   
   `ConstantFolding` folds `size(array(...))` and `size(map(...))` into the 
number of elements when every element is free of side effects. 
`hasNoSideEffect` treated a `Cast` as free of side effects whenever the session 
had ANSI mode off, without looking at the cast's own eval mode. A cast keeps 
the eval mode it was analyzed with, so an ANSI cast analyzed with ANSI on (in a 
view, a SQL function, or an eagerly analyzed DataFrame) was folded away when 
the optimizer ran under a non-ANSI session, and its error was lost.
   
   This PR also checks the cast's own eval mode, so an ANSI cast is never 
treated as free of side effects:
   
   ```scala
   case c: Cast if !conf.ansiEnabled && c.evalMode != EvalMode.ANSI => 
hasNoSideEffect(c.child)
   ```
   
   The session check stays. Some LEGACY casts can still fail, such as 
`CAST(INTERVAL '1000' SECOND AS TINYINT)` (`CAST_OVERFLOW`). Checking only the 
cast's eval mode would start folding them in ANSI sessions, where they are not 
folded today, and drop those errors, for example for a view created with ANSI 
off and queried with ANSI on.
   
   ### Why are the changes needed?
   
   The last query below should fail with `CAST_INVALID_INPUT` like the one on 
`v2`, but returns `1`.
   
   ```sql
   CREATE TABLE src(a STRING) USING parquet;
   INSERT INTO src VALUES ('abc');
   
   SET spark.sql.ansi.enabled=true;
   CREATE VIEW v1 AS SELECT size(array(CAST(a AS INT))) AS d FROM src;
   CREATE VIEW v2 AS SELECT CAST(a AS INT) AS d FROM src;
   
   SET spark.sql.ansi.enabled=false;
   SELECT * FROM v2;  -- CAST_INVALID_INPUT
   SELECT * FROM v1;  -- It should fail with CAST_INVALID_INPUT, but returns 1
   ```
   
   A SQL function created with ANSI on and a DataFrame analyzed with ANSI on 
behave the same when they run with ANSI off.
   
   This was found in the review of #59965, which analyzes the generation 
expression of a DSv2 generated column with ANSI on. With that PR, a column `d 
INT GENERATED ALWAYS AS (size(array(CAST(a AS INT))))` still accepts `INSERT 
INTO t (a) VALUES ('abc')` from a non-ANSI writer and stores `d = 1`, while an 
ANSI writer gets `CAST_INVALID_INPUT`.
   
   The session-only check was added by SPARK-37392 (#34823) and has been in 
Spark since [v3.3.0](https://github.com/apache/spark/tree/v3.3.0) (2022-06-09).
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. Under a non-ANSI session, `size(array(...))` and `size(map(...))` over 
an ANSI cast now raise the cast's error instead of returning the number of 
elements. Nothing changes under an ANSI session, and LEGACY and TRY casts are 
folded as before.
   
   ### How was this patch tested?
   
   - Added `SPARK-60820: Do not fold the size of CreateArray over an ANSI cast 
in a non-ANSI session` to `ConstantFoldingSuite`. It checks every eval mode of 
a cast under ANSI on and off, and only LEGACY and TRY casts under a non-ANSI 
session are folded. Without this change, the ANSI cast under a non-ANSI session 
is folded to `1` and the test fails.
   - Ran all suites in `org.apache.spark.sql.catalyst.optimizer`, 
`SQLQueryTestSuite` for `array.sql`, `cast.sql`, `try_cast.sql`, `explain*.sql` 
and the `nonansi` variants, `GeneratorFunctionSuite`, `SimpleSQLViewSuite` and 
`DataFrameFunctionsSuite`. All pass and no golden files change.
   - Ran the view, SQL function and DataFrame cases above before and after this 
change. With this change, they fail with `CAST_INVALID_INPUT` under a non-ANSI 
session. A view created with ANSI off that casts an overflowing interval to 
`TINYINT` still fails with `CAST_OVERFLOW` under an ANSI session, as before.
   - Applied this change on top of #59965 and ran the generated column case 
above. Both writers now get `CAST_INVALID_INPUT`.
   
   ### 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