You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by "harshmotw-db (via GitHub)" <gi...@apache.org> on 2025/03/20 22:28:12 UTC
[PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
harshmotw-db opened a new pull request, #50343:
URL: https://github.com/apache/spark/pull/50343
<!--
Thanks for sending a pull request! Here are some tips for you:
1. If this is your first time, please read our contributor guidelines: https://spark.apache.org/contributing.html
2. Ensure you have added or run the appropriate tests for your PR: https://spark.apache.org/developer-tools.html
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP][SPARK-XXXX] Your PR title ...'.
4. Be sure to keep the PR description updated to reflect all changes.
5. Please write your PR title to summarize what this PR proposes.
6. If possible, provide a concise example to reproduce the issue for a faster review.
7. If you want to add a new configuration, please read the guideline first for naming configurations in
'core/src/main/scala/org/apache/spark/internal/config/ConfigEntry.scala'.
8. If you want to add or modify an error type or message, please read the guideline first in
'common/utils/src/main/resources/error/README.md'.
-->
### What changes were proposed in this pull request?
This PR prohibits ANSI cast from `ArrayType(VariantType, containsNull = false)` to `ArrayType(_, containsNull = false)`, or `StructField(VariantType, nullable = false)` to `StructField(_, nullable = true)` or `MapType(_, VariantType, valueContainsNull = false)` to `MapType(_, _, valueContainsNull = false)`.
### Why are the changes needed?
<!--
Please clarify why the changes are needed. For instance,
1. If you propose a new API, clarify the use case for a new API.
2. If you fix a bug, you can clarify why it is a bug.
-->
Variant is the only data type which can be ANSI cast from a non-null value to a null value. More specifically, variant nulls (generated using `parse_json('null')`) when cast to string result in `null`.
However, `array<variant, containsNull = false>` can be cast to `array<string, containsNull = true>`. This should not be allowed since `array(parse_json('null'))` would give `array(null)` after this cast.
Here is a demonstration of this problem where we create an `array<string, containsNull = true>` which in fact does not contain nulls:
```
>>> from pyspark.sql.functions import col
>>> from pyspark.sql.types import StringType, VariantType, ArrayType
>>>
>>> df = spark.sql("select array(parse_json('null')) arr")
>>> df.printSchema()
root
|-- arr: array (nullable = false)
| |-- element: variant (containsNull = false)
>>> df2 = df.select(col('arr').cast(ArrayType(StringType(), False)))
>>> df2.selectExpr("arr[0] is null").show()
+----------------+
|(arr[0] IS NULL)|
+----------------+
| true|
+----------------+
>>> df2.printSchema()
root
|-- arr: array (nullable = false)
| |-- element: string (containsNull = false)
```
### Does this PR introduce _any_ user-facing change?
<!--
Note that it means *any* user-facing change including all aspects such as new features, bug fixes, or other behavior changes. Documentation-only updates are not considered user-facing changes.
If yes, please clarify the previous behavior and the change this PR proposes - provide the console output, description and/or an example to show the behavior difference if possible.
If possible, please also clarify if this is a user-facing change compared to the released Spark versions or within the unreleased branches such as master.
If no, write 'No'.
-->
Yes, users can no longer ANSI cast from `array<variant, containsNull = false>` to `array<_, containsNull = false>`. However, it is unlikely that users were hardcoding `containsNull = false`.
### How was this patch tested?
Unit tests making sure that only `containsNull = false` cases fail.
### Was this patch authored or co-authored using generative AI tooling?
No.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2007022289
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
I think what we want to do is to follow `Cast.canCast`
```
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
canCast(fromType, toType) &&
resolvableNullability(fn || forceNullable(fromType, toType), tn)
```
`fromType == VariantType` makes sense, but shall we consider the deeply nested cases like array of array of variant?
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2008011266
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
Oh forceNullable causes it to fail for some reason. Looking into it.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576][SQL] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan closed pull request #50343: [SPARK-51576][SQL] Prohibit ANSI cast from `array<variant, containsNull = false>` to `array<_, containsNull = false>`
URL: https://github.com/apache/spark/pull/50343
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2007995933
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
I don't know if non-null `array<variant>` can cast to null. Yeah, I think resolveNullability is also complete in this case but only the variant case would apply in resolveNullability because every other type that fails in resolveNullability would also fail in canAnsiCast. I'll change it to resolveNullability because it is less brittle.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2007995933
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
I don't know if non-null `array<variant>` can cast to null. Yeah, I think resolveNullability is also complete in this case but only the variant case would apply in resolveNullability because every other type that fails in resolveNullability would also fail in canAnsiCast. I'll change it to resolveNullability.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2008041088
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
We cannot do forceNullable because `forceNullable(String, Boolean)` returns true and String to Boolean cast is allowed in ANSI - just that if it fails, the cast throws an error instead of giving nulls.
Variant is the only data type which can legally cast from non-null to null in ANSI.
I've changed it back to my original version. Let me know if you can think of any cases where it could cause problems.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2008041088
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
We cannot do forceNullable because `forceNullable(String, Boolean)` returns true and String to Boolean cast is allowed in ANSI - just that if it fails, the cast throws an error instead of giving nulls.
Variant is the only data type which can legally cast from non-null to null in ANSI.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576][SQL] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "cloud-fan (via GitHub)" <gi...@apache.org>.
cloud-fan commented on PR #50343:
URL: https://github.com/apache/spark/pull/50343#issuecomment-2748140600
thanks, merging to master/4.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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org
Re: [PR] [SPARK-51576] Prohibit ANSI cast from `array` to `array<_, containsNull = false>` [spark]
Posted by "harshmotw-db (via GitHub)" <gi...@apache.org>.
harshmotw-db commented on code in PR #50343:
URL: https://github.com/apache/spark/pull/50343#discussion_r2007995933
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -133,19 +133,23 @@ object Cast extends QueryErrorsBase {
// to convert data of these types to Variant Objects.
case (_, VariantType) => variant.VariantGet.checkDataType(from, allowStructsAndMaps = false)
+ // non-null variants can generate nulls even in ANSI mode
case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
- canAnsiCast(fromType, toType) && resolvableNullability(fn, tn)
+ canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType == VariantType), tn)
Review Comment:
I don't know if non-null `array<variant>` can cast to null. Yeah, I think forceNullable is also complete in this case but only the variant case would apply in forceNullable because every other type that fails in resolveNullability would also fail in canAnsiCast. I'll change it to resolveNullability because it is less brittle.
--
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: reviews-unsubscribe@spark.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org