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

cloud-fan pushed a commit to branch branch-4.3
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.3 by this push:
     new ef4fd13fd6b3 [SPARK-58894][SQL] Detect cyclic view references in 
nested subqueries
ef4fd13fd6b3 is described below

commit ef4fd13fd6b3161869048adb7f8a5604c5efeb50
Author: Manu Zhang <[email protected]>
AuthorDate: Sat Aug 22 02:42:36 2026 +0800

    [SPARK-58894][SQL] Detect cyclic view references in nested subqueries
    
    ### What changes were proposed in this pull request?
    
    Update `ViewHelper.checkCyclicViewReference` to traverse complete 
expression trees when
    looking for subquery expressions. Add a regression case where a scalar 
subquery that
    references the altered view is nested below an equality predicate.
    
    ### Why are the changes needed?
    
    The current check only inspects top-level plan expressions. It detects an 
`EXISTS`
    subquery when the subquery is the expression root, but misses scalar and 
other subqueries
    nested inside larger expressions. A recursive view definition can therefore 
be accepted
    and fail later during view resolution with the maximum nested-view-depth 
error.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. `CREATE OR REPLACE VIEW` and `ALTER VIEW` now reject recursive 
references from
    subqueries nested inside larger expressions with `RECURSIVE_VIEW`, matching 
root-level
    subquery behavior.
    
    ### How was this patch tested?
    
    Added a regression assertion to `SimpleSQLViewSuite` and ran:
    
    ```
    SPARK_LOCAL_IP=127.0.0.1 build/sbt \
      'sql/testOnly org.apache.spark.sql.execution.SimpleSQLViewSuite -- -z 
"correctly handle a cyclic view reference"'
    build/sbt 'sql/scalastyle' 'sql/Test/scalastyle'
    ```
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Codex (GPT-5)
    
    Closes #58146 from manuzhang/codex/fix-nested-view-cycle.
    
    Authored-by: Manu Zhang <[email protected]>
    Signed-off-by: Wenchen Fan <[email protected]>
    (cherry picked from commit 02c21a6f9c87b70fa166b34c131353f74e1b7dc9)
    Signed-off-by: Wenchen Fan <[email protected]>
---
 .../org/apache/spark/sql/execution/command/views.scala      |  4 ++--
 .../scala/org/apache/spark/sql/execution/SQLViewSuite.scala | 13 +++++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git 
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/views.scala 
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/views.scala
index 411682f35f6d..4338bd367fe0 100644
--- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/views.scala
+++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/views.scala
@@ -599,9 +599,9 @@ object ViewHelper extends SQLConfHelper with Logging with 
CapturesConfig {
         plan.children.foreach(child => checkCyclicViewReference(child, path, 
viewIdent))
     }
 
-    // Detect cyclic references from subqueries.
+    // Detect cyclic references from subqueries nested in expressions.
     plan.expressions.foreach { expr =>
-      expr match {
+      expr.foreach {
         case s: SubqueryExpression =>
           checkCyclicViewReference(s.plan, path, viewIdent)
         case _ => // Do nothing.
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala 
b/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
index 3fb54d7c43d5..aef97c2a9314 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
@@ -1018,6 +1018,19 @@ abstract class SQLViewSuite extends QueryTest {
             s"`$SESSION_CATALOG_NAME`.`default`.`view2` -> " +
             s"`$SESSION_CATALOG_NAME`.`default`.`view1`"))
       )
+
+      // Detect cyclic view references from subqueries nested in larger 
expressions.
+      checkError(
+        exception = intercept[AnalysisException] {
+          sql("ALTER VIEW view1 AS SELECT * FROM jt WHERE id = (SELECT id FROM 
view2)")
+        },
+        condition = "RECURSIVE_VIEW",
+        parameters = Map(
+          "viewIdent" -> s"`$SESSION_CATALOG_NAME`.`default`.`view1`",
+          "newPath" -> (s"`$SESSION_CATALOG_NAME`.`default`.`view1` -> " +
+            s"`$SESSION_CATALOG_NAME`.`default`.`view2` -> " +
+            s"`$SESSION_CATALOG_NAME`.`default`.`view1`"))
+      )
     }
   }
 


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

Reply via email to