charliec05 opened a new pull request, #59078:
URL: https://github.com/apache/spark/pull/59078

   ### What changes were proposed in this pull request?
   
   Preserve non-key attribute nullability in `ReplaceDeduplicateWithAggregate`: 
wrap the generated `First` aggregate with `KnownNotNull` only when its input 
attribute is non-nullable. Retain the generated-alias cache and leave nullable 
attributes and streaming deduplication unchanged.
   
   This is safe specifically for this rewrite: the rule always produces a 
grouping aggregate, adding a literal grouping key when the deduplication key 
list is empty. Every output group therefore contains an input row. The general 
`First` expression is not changed.
   
   Add optimizer, batch aggregation, and Data Source V2 write regressions, plus 
a SQL migration note.
   
   ### Why are the changes needed?
   
   The rule currently replaces each non-key attribute with `first(attribute)`, 
whose result is nullable in general. This widens a non-nullable input column's 
schema during optimization. An otherwise-valid write to a Data Source V2 `NOT 
NULL` column then becomes unresolved and fails with 
`PLAN_VALIDATION_FAILED_RULE_IN_BATCH`.
   
   For example, a non-nullable `value` in `spark.range(3).selectExpr("id", "id 
+ 10 AS value").dropDuplicates("id")` becomes nullable in the optimized plan, 
and appending it to a table declared as `(id BIGINT NOT NULL, value BIGINT NOT 
NULL)` fails.
   
   This follows the scoped approach discussed by Josh Rosen in 
[SPARK-44517](https://issues.apache.org/jira/browse/SPARK-44517). Unlike the 
earlier, now-closed #42117 approach, it does not change `First.nullable` 
globally: global aggregation over empty input and `first(..., true)` over 
all-null input must remain nullable.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. Batch `dropDuplicates` preserves non-key column nullability through 
optimization, allowing writes to compatible `NOT NULL` columns. Empty-input 
deduplication still returns no rows. The normal `first` aggregate retains its 
existing null behavior.
   
   ### How was this patch tested?
   
   - Before the fix, the new optimizer regression failed; both codegen modes 
reproduced the schema change; the Data Source V2 append reproduced 
`PLAN_VALIDATION_FAILED_RULE_IN_BATCH`.
   - New coverage includes keyed and keyless deduplication, empty inputs, 
nullable columns, a successful `NOT NULL` table append, and unchanged null 
results from ordinary global `first` aggregates.
   - `build/sbt "catalyst/testOnly 
org.apache.spark.sql.catalyst.optimizer.ReplaceOperatorSuite"`: all 16 tests 
passed.
   - `build/sbt "sql/testOnly org.apache.spark.sql.DataFrameAggregateSuite"`: 
all 177 tests passed, including codegen-on/off and empty-input regressions.
   - `build/sbt "sql/testOnly 
org.apache.spark.sql.connector.DataSourceV2DataFrameSuite -- -z SPARK-44517"`: 
the `NOT NULL` table append regression passed.
   - `build/sbt "sql/testOnly org.apache.spark.sql.DataFrameSuite -- -z 
dropDuplicates"`: the existing deduplication regression passed.
   - `dev/lint-scala`: ScalaStyle and ScalaFmt checks passed. Tests ran on Java 
21.
   - [Full GitHub Actions 
CI](https://github.com/charliec05/spark/actions/runs/36294917010) is running on 
`9ee811036dc`; its result is pending.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: OpenAI Codex (GPT-5)
   
   This contribution is submitted under the project's Apache License 2.0.
   


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