dongjoon-hyun commented on code in PR #59072:
URL: https://github.com/apache/spark/pull/59072#discussion_r4117295734


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala:
##########
@@ -7557,6 +7557,15 @@ object SQLConf {
       .booleanConf
       .createWithDefault(false)
 
+  val LEGACY_ALLOW_NON_FOLDABLE_OPTIONS =

Review Comment:
   This new config fails `SparkConfigBindingPolicySuite` in both `sql - other 
tests` and `hive - other tests` CI jobs.
   
   ```
   [info] - Config enforcement for bindingPolicy *** FAILED ***
   The following configs do not have bindingPolicy field set. ...
   spark.sql.legacy.allowNonFoldableOptions
   ```
   
   Could you add `.withBindingPolicy(ConfigBindingPolicy.SESSION)`? `PERSISTED` 
would not work for this legacy config because the existing views created by 
Spark 4.3 or older don't have a captured value of it. Those views would always 
use the default value `false`, so users couldn't use this config to read them.



##########
AGENTS.md:
##########
@@ -101,7 +101,7 @@ These are combined with a base above rather than used on 
their own:
 
 ## Build and Test
 
-Build and tests can take a long time. If the user explicitly asked to run 
tests, run them. Otherwise (you are running tests on your own to verify a 
change), first ask the user if they have more changes to make.
+Build and tests can take a long time, so prefer the narrowest relevant build 
or test command.

Review Comment:
   This looks unrelated to SPARK-59801. Could you spin off this `AGENTS.md` 
change to a separate PR?



##########
sql/core/src/test/scala/org/apache/spark/sql/CsvFunctionsSuite.scala:
##########
@@ -439,6 +439,66 @@ class CsvFunctionsSuite extends SharedSparkSession {
     checkAnswer(df1.selectExpr("to_csv(a)"), Row("1") :: Nil)
   }
 
+  test("to_csv with non-foldable options") {

Review Comment:
   Could you add the JIRA ID to the test name, e.g., `SPARK-59801: to_csv with 
non-foldable options`?
   
   In addition, this PR changes 9 call sites, and each has its own hard-coded 
function name. Only `to_csv`, `to_json` and `to_xml` are covered now. Could you 
add test cases for `from_csv`, `schema_of_csv`, `from_json`, `schema_of_json`, 
`from_xml` and `schema_of_xml` too? `sql-tests/inputs/csv-functions.sql` and 
`json-functions.sql` already have the other `INVALID_OPTIONS` cases, so they 
could be a good place as well.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ExprUtils.scala:
##########
@@ -59,12 +60,17 @@ object ExprUtils extends EvalHelper with QueryErrorsBase {
     dataType.asInstanceOf[StructType]
   }
 
-  def convertToMapData(exp: Expression): Map[String, String] = exp match {
+  def convertToMapData(exp: Expression, functionName: String): Map[String, 
String] = exp match {
     case m: CreateMap
       if AbstractMapType(
         StringTypeWithCollation(supportsTrimCollation = true),
         StringTypeWithCollation(supportsTrimCollation = true))
         .acceptsType(m.dataType) =>
+      if (!m.foldable &&

Review Comment:
   `RuntimeReplaceable` expressions like `nvl`, `nvl2` and `left` are 
non-foldable before `ReplaceExpressions`. So, constant options like 
`map('delimiter', nvl(NULL, '|'))` worked before but fail by default now. 
`ExprUtils` already extends `EvalHelper`, so what about checking 
`prepareForEval(m).foldable` instead? `nvl(NULL, '|')` becomes `Coalesce(NULL, 
'|')`, which is foldable. This would make the breaking change smaller.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ExprUtils.scala:
##########
@@ -59,12 +60,17 @@ object ExprUtils extends EvalHelper with QueryErrorsBase {
     dataType.asInstanceOf[StructType]
   }
 
-  def convertToMapData(exp: Expression): Map[String, String] = exp match {
+  def convertToMapData(exp: Expression, functionName: String): Map[String, 
String] = exp match {
     case m: CreateMap
       if AbstractMapType(
         StringTypeWithCollation(supportsTrimCollation = true),
         StringTypeWithCollation(supportsTrimCollation = true))
         .acceptsType(m.dataType) =>
+      if (!m.foldable &&
+          !SQLConf.get.getConf(SQLConf.LEGACY_ALLOW_NON_FOLDABLE_OPTIONS)) {
+        throw QueryCompilationErrors.nonFoldableArgumentError(
+          functionName, "options", m.dataType)

Review Comment:
   nit. The other errors from this method use `INVALID_OPTIONS.*` (SQLSTATE 
`42K06`), while this one uses `NON_FOLDABLE_ARGUMENT` (`42K08`). Reusing the 
existing condition is fine with me. I'm only mentioning it in case you want all 
option-map errors under `INVALID_OPTIONS`.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ExprUtils.scala:
##########
@@ -59,12 +60,17 @@ object ExprUtils extends EvalHelper with QueryErrorsBase {
     dataType.asInstanceOf[StructType]
   }
 
-  def convertToMapData(exp: Expression): Map[String, String] = exp match {
+  def convertToMapData(exp: Expression, functionName: String): Map[String, 
String] = exp match {
     case m: CreateMap
       if AbstractMapType(
         StringTypeWithCollation(supportsTrimCollation = true),
         StringTypeWithCollation(supportsTrimCollation = true))
         .acceptsType(m.dataType) =>
+      if (!m.foldable &&
+          !SQLConf.get.getConf(SQLConf.LEGACY_ALLOW_NON_FOLDABLE_OPTIONS)) {

Review Comment:
   When `spark.sql.legacy.allowNonFoldableOptions=true`, this falls back to 
`m.eval()` for row-dependent maps too. So, the legacy mode brings back the 
original bug.
   - A column reference, e.g., `to_csv(a, map('delimiter', delimiter))`, hits 
`INTERNAL_ERROR` again.
   - A lambda variable is silently evaluated as `null` 
(`NamedLambdaVariable.value` is not bound yet), e.g., `transform(array('|'), x 
-> to_csv(named_struct('a', 1, 'b', 2), map('delimiter', x)))` uses the string 
`null` as the delimiter.
   
   Shall we keep rejecting the maps with `m.references.nonEmpty` (it covers 
both `AttributeReference` and `NamedLambdaVariable`) even in the legacy mode, 
and relax only the evaluable constant cases?



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