[ 
https://issues.apache.org/jira/browse/SPARK-59147?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

ASF GitHub Bot updated SPARK-59147:
-----------------------------------
    Labels: pull-request-available  (was: )

> Nested SELECT * EXCEPT turns NULL structs into non-NULL structs
> ---------------------------------------------------------------
>
>                 Key: SPARK-59147
>                 URL: https://issues.apache.org/jira/browse/SPARK-59147
>             Project: Spark
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 4.2.0, 4.3.0
>            Reporter: Joel Robin
>            Priority: Major
>              Labels: pull-request-available
>
> h3. Problem
> Nested-field SELECT * EXCEPT reconstructs a nullable struct even when the 
> original struct is NULL. This silently changes the parent struct from NULL to 
> a non-NULL struct whose remaining fields are NULL.
> h3. Reproduction
> Reproduced on Apache Spark master at commit 
> cdab5402f9f5890117d6156b6f0e7c0ed8e1aca6.
> {code:sql}
> WITH input AS (
>   SELECT id,
>     CASE
>       WHEN id = 0 THEN CAST(NULL AS STRUCT<a: INT, b: INT>)
>       ELSE named_struct('a', id, 'b', id + 10)
>     END AS s
>   FROM VALUES (0), (1) AS t(id)
> ),
> actual AS (
>   SELECT * EXCEPT (s.a) FROM input
> )
> SELECT
>   i.id,
>   i.s IS NULL AS before_except,
>   a.s IS NULL AS after_except,
>   a.s.b
> FROM input i
> JOIN actual a USING (id)
> ORDER BY id;
> {code}
> h3. Actual behavior
> {noformat}
> (0, true,  false, NULL)
> (1, false, false, 11)
> {noformat}
> For id 0, the input struct is NULL, but the struct returned by SELECT * 
> EXCEPT (s.a) is non-NULL.
> h3. Expected behavior
> {noformat}
> (0, true,  true,  NULL)
> (1, false, false, 11)
> {noformat}
> Removing a nested field should preserve the nullness of the parent struct. 
> For id 0, the result should remain CAST(NULL AS STRUCT<b: INT>), not 
> named_struct('b', NULL).
> h3. Customer impact
> This is a silent SQL correctness issue. Nullable structs commonly come from 
> parsed JSON and from the null-producing side of outer joins. Customers use 
> nested-field SELECT * EXCEPT to remove unwanted fields from wide records; 
> afterward, IS NULL checks, filters, joins, COALESCE expressions, and 
> serialized output can behave differently because Spark has changed a NULL 
> struct into a present struct containing NULL fields.
> The same behavior was reproduced with NULL structs produced by from_json and 
> with null-extended structs from outer joins.
> h3. Technical analysis
> UnresolvedStarExceptOrReplace.filterColumns handles a nested exclusion by 
> extracting the retained fields and unconditionally wrapping them in 
> CreateStruct. CreateStruct resolves to CreateNamedStruct, whose nullable 
> property is always false. Consequently, the reconstructed struct cannot 
> preserve the nullness of the original nullable parent expression.
> Relevant locations:
> * 
> sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala,
>  nested exclusion reconstruction in filterColumns
> * 
> sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/complexTypeCreator.scala,
>  CreateNamedStruct.nullable



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to