cloud-fan commented on code in PR #52334:
URL: https://github.com/apache/spark/pull/52334#discussion_r2436013087


##########
sql/core/src/main/scala/org/apache/spark/sql/classic/SparkSession.scala:
##########
@@ -430,6 +431,77 @@ class SparkSession private(
    |  Everything else  |
    * ----------------- */
 
+  /**
+   * Resolves and validates parameter expressions using a fake Project plan.
+   * This ensures parameters are properly resolved and constant-folded before 
being
+   * passed to the pre-parser.
+   *
+   * @param args Map of parameter names to expressions
+   * @return Map of parameter names to resolved literal expressions
+   */
+  private[sql] def resolveAndValidateParameters(
+      args: Map[String, Expression]): Map[String, Literal] = {
+    if (args.isEmpty) {
+      return Map.empty
+    }
+
+    // Create a fake Project plan: Project(parameters, OneRowRelation)
+    val aliases = args.map { case (name, expr) =>
+      Alias(expr, name)()
+    }.toSeq
+    val fakePlan = Project(aliases, OneRowRelation())
+
+    // Analyze and optimize to resolve and constant-fold
+    val analyzed = sessionState.analyzer.execute(fakePlan)
+    val optimized = sessionState.optimizer.execute(analyzed)
+
+    // Extract the resolved expressions from the project list
+    val resolvedParams = optimized.asInstanceOf[Project].projectList.map { 
alias =>
+      val resolvedExpr = alias.asInstanceOf[Alias].child
+
+      // Validate: the expression tree must only contain allowed expression 
types.
+      // This mirrors the validation in BindParameters.checkArgs.
+      // The validation happens on the analyzed (but not yet optimized) plan 
to catch
+      // unsupported functions like str_to_map before they get folded.
+      val analyzedExpr = analyzed.asInstanceOf[Project].projectList
+        .find(_.asInstanceOf[Alias].name == alias.name)
+        .get.asInstanceOf[Alias].child
+
+      def isNotAllowed(expr: Expression): Boolean = expr.exists {
+        case _: Literal | _: CreateArray | _: CreateNamedStruct |
+          _: CreateMap | _: MapFromArrays | _: MapFromEntries | _: 
VariableReference => false
+        case a: Alias => isNotAllowed(a.child)
+        case _ => true
+      }
+
+      if (isNotAllowed(analyzedExpr)) {
+        // Both modern and legacy modes use INVALID_SQL_ARG for sql() API 
argument validation.
+        // UNSUPPORTED_EXPR_FOR_PARAMETER is reserved for EXECUTE IMMEDIATE.
+        throw new AnalysisException(
+          errorClass = "INVALID_SQL_ARG",
+          messageParameters = Map("name" -> alias.name),
+          origin = analyzedExpr.origin)
+      }
+
+      // For non-literal allowed expressions, evaluate them to literals
+      val literal = resolvedExpr match {
+        case lit: Literal => lit
+        case foldable if foldable.foldable =>

Review Comment:
   I don't think this is needed, optimizer should have done it already.



##########
sql/core/src/main/scala/org/apache/spark/sql/classic/SparkSession.scala:
##########
@@ -430,6 +431,77 @@ class SparkSession private(
    |  Everything else  |
    * ----------------- */
 
+  /**
+   * Resolves and validates parameter expressions using a fake Project plan.
+   * This ensures parameters are properly resolved and constant-folded before 
being
+   * passed to the pre-parser.
+   *
+   * @param args Map of parameter names to expressions
+   * @return Map of parameter names to resolved literal expressions
+   */
+  private[sql] def resolveAndValidateParameters(
+      args: Map[String, Expression]): Map[String, Literal] = {
+    if (args.isEmpty) {
+      return Map.empty
+    }
+
+    // Create a fake Project plan: Project(parameters, OneRowRelation)
+    val aliases = args.map { case (name, expr) =>
+      Alias(expr, name)()
+    }.toSeq
+    val fakePlan = Project(aliases, OneRowRelation())
+
+    // Analyze and optimize to resolve and constant-fold
+    val analyzed = sessionState.analyzer.execute(fakePlan)
+    val optimized = sessionState.optimizer.execute(analyzed)
+
+    // Extract the resolved expressions from the project list
+    val resolvedParams = optimized.asInstanceOf[Project].projectList.map { 
alias =>
+      val resolvedExpr = alias.asInstanceOf[Alias].child

Review Comment:
   ```suggestion
         val optimizedExpr = alias.asInstanceOf[Alias].child
   ```



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