You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by we...@apache.org on 2026/06/11 20:51:21 UTC
(spark) branch master updated: [SPARK-57369][SQL] Move main EXECUTE IMMEDIATE resolution logic to common code
This is an automated email from the ASF dual-hosted git repository.
cloud-fan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new a1922b5e2b15 [SPARK-57369][SQL] Move main EXECUTE IMMEDIATE resolution logic to common code
a1922b5e2b15 is described below
commit a1922b5e2b1507206a4ecbcf65bb62870a3934b3
Author: Mihailo Aleksic <mi...@databricks.com>
AuthorDate: Thu Jun 11 13:51:00 2026 -0700
[SPARK-57369][SQL] Move main EXECUTE IMMEDIATE resolution logic to common code
### What changes were proposed in this pull request?
In this PR I propose to move main EXECUTE IMMEDIATE resolution logic to common code in order to ease the single-pass implementation.
### Why are the changes needed?
In order to ease the single-pass implementation.
### Does this PR introduce _any_ user-facing change?
No, it's just a refactor.
### How was this patch tested?
Existing tests.
### Was this patch authored or co-authored using generative AI tooling?
Yes.
Closes #56429 from mihailoale-db/execimmrefactor.
Authored-by: Mihailo Aleksic <mi...@databricks.com>
Signed-off-by: Wenchen Fan <we...@databricks.com>
---
.../analysis/ResolveExecuteImmediate.scala | 50 ++++++++++++++++------
1 file changed, 38 insertions(+), 12 deletions(-)
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveExecuteImmediate.scala b/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveExecuteImmediate.scala
index bf57d8df5229..c09498b41c97 100644
--- a/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveExecuteImmediate.scala
+++ b/sql/core/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveExecuteImmediate.scala
@@ -35,6 +35,9 @@ import org.apache.spark.sql.types.StringType
* Analysis rule that resolves and executes EXECUTE IMMEDIATE statements during analysis,
* replacing them with the results, similar to how CALL statements work.
* This rule combines resolution and execution in a single pass.
+ *
+ * When sub-expressions are not yet resolved, the node is returned unchanged so that the
+ * fixed-point analyzer re-applies this rule on the next iteration.
*/
case class ResolveExecuteImmediate(sparkSession: SparkSession, catalogManager: CatalogManager)
extends Rule[LogicalPlan] {
@@ -43,23 +46,45 @@ case class ResolveExecuteImmediate(sparkSession: SparkSession, catalogManager: C
plan.resolveOperatorsWithPruning(_.containsPattern(EXECUTE_IMMEDIATE), ruleId) {
case node @ UnresolvedExecuteImmediate(sqlStmtStr, args, targetVariables) =>
if (sqlStmtStr.resolved && targetVariables.forall(_.resolved) && args.forall(_.resolved)) {
- // All resolved - execute immediately and handle INTO clause if present
- if (targetVariables.nonEmpty) {
- // EXECUTE IMMEDIATE ... INTO should generate SetVariable plan with eagerly executed
- // source
- val finalTargetVars = extractTargetVariables(targetVariables)
- val executedSource = executeImmediateQuery(sqlStmtStr, args, hasIntoClause = true)
- SetVariable(finalTargetVars, executedSource)
- } else {
- // Regular EXECUTE IMMEDIATE without INTO - execute and return result directly
- executeImmediateQuery(sqlStmtStr, args, hasIntoClause = false)
- }
+ ResolveExecuteImmediate.resolveExecuteImmediate(
+ sparkSession, sqlStmtStr, args, targetVariables)
} else {
- // Not all resolved yet - wait for next iteration
node
}
}
}
+}
+
+/**
+ * Companion object containing shared resolution logic for `EXECUTE IMMEDIATE` statements.
+ */
+object ResolveExecuteImmediate {
+
+ /**
+ * Resolves an [[UnresolvedExecuteImmediate]] node into an executable plan.
+ *
+ * All expressions (`sqlStmtStr`, `args`, `targetVariables`) must already be resolved
+ * before calling this method.
+ *
+ * When an `INTO` clause is present, the dynamic SQL is eagerly parsed and analyzed, and
+ * the analyzed plan is wrapped in a [[SetVariable]] plan that assigns output columns to
+ * the target variables. Without `INTO`, the resulting plan is returned directly
+ * (commands are executed eagerly; queries are returned analyzed but unexecuted).
+ */
+ def resolveExecuteImmediate(
+ sparkSession: SparkSession,
+ sqlStmtStr: Expression,
+ args: Seq[Expression],
+ targetVariables: Seq[Expression]): LogicalPlan = {
+ if (targetVariables.nonEmpty) {
+ val finalTargetVars = extractTargetVariables(targetVariables)
+ val executedSource = executeImmediateQuery(
+ sparkSession, sqlStmtStr, args, hasIntoClause = true)
+ SetVariable(finalTargetVars, executedSource)
+ } else {
+ executeImmediateQuery(sparkSession, sqlStmtStr, args, hasIntoClause = false)
+ }
+ }
private def extractTargetVariables(targetVariables: Seq[Expression]): Seq[VariableReference] = {
targetVariables.map {
@@ -81,6 +106,7 @@ case class ResolveExecuteImmediate(sparkSession: SparkSession, catalogManager: C
}
private def executeImmediateQuery(
+ sparkSession: SparkSession,
sqlStmtStr: Expression,
args: Seq[Expression],
hasIntoClause: Boolean): LogicalPlan = {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org