This is an automated email from the ASF dual-hosted git repository.

MaxGekk pushed a commit to branch branch-4.x
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.x by this push:
     new 477d916c59f9 [SPARK-57756][SQL] Move SQL UDF resolution SQLConf 
construction to common code
477d916c59f9 is described below

commit 477d916c59f94e0b672dbf7b2ac1585b018e8916
Author: daniel-lunin-db <[email protected]>
AuthorDate: Wed Jul 1 00:36:34 2026 +0200

    [SPARK-57756][SQL] Move SQL UDF resolution SQLConf construction to common 
code
    
    SessionCatalog.makeSQLFunctionPlan and the ResolveSQLFunctions / 
ResolveSQLTableFunctions analyzer rules each inline the same throwaway-SQLConf 
construction used to resolve a SQL UDF body: new SQLConf, seed from the 
function's stored configs, then either set ANSI unconditionally or overlay the 
session's retained resolution configs. Move it into a common 
Analyzer.buildSQLFunctionConf helper, parameterized by alwaysSetAnsiValue and 
applySessionOverrides, and have the three call sites de [...]
    
    ### What changes were proposed in this pull request?
    
    `SessionCatalog.makeSQLFunctionPlan` and the `ResolveSQLFunctions` /
    `ResolveSQLTableFunctions` analyzer rules each inline the same 
throwaway-`SQLConf`
    construction used to resolve a SQL UDF body. This moves it into a common
    `Analyzer.buildSQLFunctionConf` helper, parameterized by 
`alwaysSetAnsiValue` and
    `applySessionOverrides`, and has the three call sites delegate to it.
    
    ### Why are the changes needed?
    
    The three call sites carried the same conf-seeding logic. Unifying it 
removes the
    duplication and gives one place to reason about a SQL UDF body's resolution 
conf.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. The helper produces the same `SQLConf` the inline code did.
    
    ### How was this patch tested?
    
    Behavior-preserving extraction, covered by existing SQL UDF resolution 
tests; CI on
    this PR compiles and runs them.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Anthropic Claude Opus)
    
    Closes #56895 from daniel-lunin-db/SPARK-57756.
    
    Authored-by: daniel-lunin-db <[email protected]>
    Signed-off-by: Max Gekk <[email protected]>
    (cherry picked from commit e40dc30e4387fcd662069cb62b921c6470b6c548)
    Signed-off-by: Max Gekk <[email protected]>
---
 .../spark/sql/catalyst/analysis/Analyzer.scala     | 45 +++++++++++++++++-----
 .../sql/catalyst/catalog/SessionCatalog.scala      |  7 ++--
 2 files changed, 39 insertions(+), 13 deletions(-)

diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala
index 49d82e056f60..7fb7086449f6 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala
@@ -327,6 +327,33 @@ object Analyzer {
       }
     }
   }
+
+  /**
+   * Builds the throwaway [[SQLConf]] used to resolve a SQL UDF body, seeded 
from the function's
+   * stored configs. Call sites share this seeding but differ in how they 
apply ANSI and session
+   * overrides, so both are parameters:
+   *  - `alwaysSetAnsiValue` calls [[trySetAnsiValue]] unconditionally (the 
SessionCatalog plan
+   *    builders); when false, ANSI is set only as part of the session overlay 
below (the
+   *    [[Analyzer#ResolveSQLFunctions]] / 
[[Analyzer#ResolveSQLTableFunctions]] rules).
+   *  - `applySessionOverrides` overlays the active session's retained 
resolution configs via
+   *    [[retainResolutionConfigsForAnalysis]], gated on
+   *    [[SQLConf.APPLY_SESSION_CONF_OVERRIDES_TO_FUNCTION_RESOLUTION]].
+   */
+  def buildSQLFunctionConf(
+      function: SQLFunction,
+      applySessionOverrides: Boolean,
+      alwaysSetAnsiValue: Boolean): SQLConf = {
+    val functionConf = new SQLConf()
+    function.getSQLConfigs.foreach { case (k, v) => 
functionConf.settings.put(k, v) }
+    if (alwaysSetAnsiValue) {
+      trySetAnsiValue(functionConf)
+    }
+    if (applySessionOverrides &&
+        
conf.getConf(SQLConf.APPLY_SESSION_CONF_OVERRIDES_TO_FUNCTION_RESOLUTION)) {
+      retainResolutionConfigsForAnalysis(newConf = functionConf, existingConf 
= conf)
+    }
+    functionConf
+  }
 }
 
 /**
@@ -2700,11 +2727,10 @@ class Analyzer(
       val plan = v1SessionCatalog.makeSQLFunctionPlan(f.name, f.function, 
f.inputs)
       val resolved = SQLFunctionContext.withSQLFunction {
         // Resolve the SQL function plan using its context.
-        val newConf = new SQLConf()
-        f.function.getSQLConfigs.foreach { case (k, v) => 
newConf.settings.put(k, v) }
-        if 
(conf.getConf(SQLConf.APPLY_SESSION_CONF_OVERRIDES_TO_FUNCTION_RESOLUTION)) {
-          Analyzer.retainResolutionConfigsForAnalysis(newConf = newConf, 
existingConf = conf)
-        }
+        val newConf = Analyzer.buildSQLFunctionConf(
+          function = f.function,
+          applySessionOverrides = true,
+          alwaysSetAnsiValue = false)
         SQLConf.withExistingConf(newConf) {
           AnalysisContext.withAnalysisContext(f.function) {
             executeSameContext(plan)
@@ -3010,11 +3036,10 @@ class Analyzer(
       _.containsPattern(SQL_TABLE_FUNCTION)) {
       case SQLTableFunction(name, function, inputs, output) =>
         // Resolve the SQL table function plan using its function context.
-        val newConf = new SQLConf()
-        function.getSQLConfigs.foreach { case (k, v) => 
newConf.settings.put(k, v) }
-        if 
(conf.getConf(SQLConf.APPLY_SESSION_CONF_OVERRIDES_TO_FUNCTION_RESOLUTION)) {
-          Analyzer.retainResolutionConfigsForAnalysis(newConf = newConf, 
existingConf = conf)
-        }
+        val newConf = Analyzer.buildSQLFunctionConf(
+          function = function,
+          applySessionOverrides = true,
+          alwaysSetAnsiValue = false)
         val resolved = SQLConf.withExistingConf(newConf) {
           val plan = v1SessionCatalog.makeSQLTableFunctionPlan(name, function, 
inputs, output)
           SQLFunctionContext.withSQLFunction {
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala
index d8461300f927..ae56a811a158 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala
@@ -1893,9 +1893,10 @@ class SessionCatalog(
     val funcName = function.name.funcName
 
     // Use captured SQL configs when parsing a SQL function.
-    val conf = new SQLConf()
-    function.getSQLConfigs.foreach { case (k, v) => conf.settings.put(k, v) }
-    Analyzer.trySetAnsiValue(conf)
+    val conf = Analyzer.buildSQLFunctionConf(
+      function = function,
+      applySessionOverrides = false,
+      alwaysSetAnsiValue = true)
     SQLConf.withExistingConf(conf) {
       val inputParam = function.inputParam
       val returnType = function.getScalarFuncReturnType


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

Reply via email to