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


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/parameters.scala:
##########
@@ -203,6 +226,64 @@ object BindParameters extends Rule[LogicalPlan] with 
QueryErrorsBase {
             args(posToIndex(pos))
         }
 
+      case GeneralParameterizedQuery(child, args, paramNames)
+        if !child.containsPattern(UNRESOLVED_WITH) &&
+          args.forall(_.resolved) =>
+
+        // Collect parameter types used in the query and validate no mixing
+        val namedParams = scala.collection.mutable.Set.empty[String]
+        val positionalParams = scala.collection.mutable.Set.empty[Int]
+        bind(child) {
+          case NamedParameter(name) => namedParams.add(name); 
NamedParameter(name)
+          case p @ PosParameter(pos) => positionalParams.add(pos); p
+        }
+
+        // Validate: no mixing of positional and named parameters
+        if (namedParams.nonEmpty && positionalParams.nonEmpty) {
+          throw QueryCompilationErrors.invalidQueryMixedQueryParameters()
+        }
+
+        // Validate: if query uses named parameters, all USING expressions 
must have names
+        if (namedParams.nonEmpty && positionalParams.isEmpty) {
+          val unnamedExpressions = paramNames.zipWithIndex.collect {
+            case (null, index) => index
+            case ("", index) => index // empty strings are unnamed
+          }
+          if (unnamedExpressions.nonEmpty) {
+            val unnamedExprs = unnamedExpressions.map(args(_))
+            throw 
QueryCompilationErrors.invalidQueryAllParametersMustBeNamed(unnamedExprs)
+          }
+        }
+
+        // Check all arguments for validity (args are already evaluated 
expressions/literals)
+        val allArgs = args.zipWithIndex.map { case (arg, idx) =>
+          val name = if (idx < paramNames.length && paramNames(idx) != null) {
+            paramNames(idx)
+          } else {
+            s"_$idx"
+          }
+          (name, arg)
+        }
+        checkArgs(allArgs)
+
+        // Single pass binding - args are already literals/evaluated 
expressions
+        val namedArgsMap = paramNames.zipWithIndex.collect {
+          case (name, index) if name != null => name -> args(index)
+        }.toMap
+        val positionalArgsMap = if (positionalParams.nonEmpty) {
+          val sortedPositions = positionalParams.toSeq.sorted
+          sortedPositions.zipWithIndex.collect { case (pos, index) if index < 
args.length =>
+            pos -> args(index)
+          }.toMap
+        } else Map.empty[Int, Expression]
+
+        bind(child) {

Review Comment:
   can we do everything in one pass? Something like this
   ```
   val namedArgsMap = if (paramNames.isEmpty) Map.empty else ...
   var hasNamedParameter = false
   bind(child) {
     case p @ NamedParameter(name) =>
       if (namedArgsMap.isEmpty) throw 
QueryCompilationErrors.invalidQueryAllParametersMustBeNamed
       hasNamedParameter = true
       namedArgsMap.getOrElse(name, p)
     case PosParameter(pos) =>
       if (hasNamedParameter) throw 
QueryCompilationErrors.invalidQueryMixedQueryParameters()
       ...
   }
   ```



-- 
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-unsubscr...@spark.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org

Reply via email to