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

lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new d3126943af [spark] Fix view resolution for CTE and ORDER BY ordinal 
(#7552)
d3126943af is described below

commit d3126943af308d6faf7e82794c6f3686f8b11d92
Author: Zouxxyy <[email protected]>
AuthorDate: Tue Mar 31 21:07:29 2026 +0800

    [spark] Fix view resolution for CTE and ORDER BY ordinal (#7552)
    
    Fix PaimonViewResolver to apply early analysis rules (CTESubstitution,
    SubstituteUnresolvedOrdinals) to parsed view plans. These rules run in
    Spark's earlyBatches before the Resolution batch, so they won't re-run
    for plans injected by PaimonViewResolver during resolution.
    
    Without this fix:
    - Views with CTE (`WITH t AS ...`) fail with `TABLE_OR_VIEW_NOT_FOUND`
    - Views with `ORDER BY 1` (ordinal) produce incorrect results
---
 .../catalyst/analysis/PaimonViewResolver.scala     |  8 +++--
 .../paimon/spark/sql/PaimonViewTestBase.scala      | 38 ++++++++++++++++++++++
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonViewResolver.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonViewResolver.scala
index 45de6a1c76..b45463e916 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonViewResolver.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonViewResolver.scala
@@ -24,7 +24,7 @@ import org.apache.paimon.spark.catalog.SupportView
 import org.apache.paimon.view.View
 
 import org.apache.spark.sql.SparkSession
-import org.apache.spark.sql.catalyst.analysis.{GetColumnByOrdinal, 
UnresolvedRelation, UnresolvedTableOrView}
+import org.apache.spark.sql.catalyst.analysis.{CTESubstitution, 
GetColumnByOrdinal, SubstituteUnresolvedOrdinals, UnresolvedRelation, 
UnresolvedTableOrView}
 import org.apache.spark.sql.catalyst.expressions.{Alias, Attribute, UpCast}
 import org.apache.spark.sql.catalyst.parser.ParseException
 import org.apache.spark.sql.catalyst.parser.extensions.{CurrentOrigin, Origin}
@@ -62,6 +62,10 @@ case class PaimonViewResolver(spark: SparkSession)
     val parsedPlan =
       parseViewText(nameParts.toArray.mkString("."), 
view.query(SupportView.DIALECT))
 
+    // Apply early analysis rules that won't re-run for plans injected during 
Resolution batch.
+    val earlyRules = Seq(CTESubstitution, SubstituteUnresolvedOrdinals)
+    val rewritten = earlyRules.foldLeft(parsedPlan)((plan, rule) => 
rule.apply(plan))
+
     val aliases = 
SparkTypeUtils.fromPaimonRowType(view.rowType()).fields.zipWithIndex.map {
       case (expected, pos) =>
         val attr = GetColumnByOrdinal(pos, expected.dataType)
@@ -69,7 +73,7 @@ case class PaimonViewResolver(spark: SparkSession)
           Some(expected.metadata))
     }
 
-    SubqueryAlias(nameParts, Project(aliases, parsedPlan))
+    SubqueryAlias(nameParts, Project(aliases, rewritten))
   }
 
   private def parseViewText(name: String, viewText: String): LogicalPlan = {
diff --git 
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonViewTestBase.scala
 
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonViewTestBase.scala
index b276af89b5..7c503d98a5 100644
--- 
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonViewTestBase.scala
+++ 
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonViewTestBase.scala
@@ -204,4 +204,42 @@ abstract class PaimonViewTestBase extends 
PaimonHiveTestBase {
       }
     }
   }
+
+  test("Paimon View: create view with CTE") {
+    Seq(sparkCatalogName, paimonHiveCatalogName).foreach {
+      catalogName =>
+        sql(s"USE $catalogName")
+        withDatabase("test_db") {
+          sql("CREATE DATABASE test_db")
+          sql("USE test_db")
+          withView("v1") {
+            sql("""
+                  |CREATE VIEW v1 AS
+                  |    WITH t(a, b, c, d) AS (SELECT 1, 2, 3, 4)
+                  |    SELECT * FROM t
+                  |""".stripMargin)
+            checkAnswer(sql("SELECT * FROM v1"), Seq(Row(1, 2, 3, 4)))
+          }
+        }
+    }
+  }
+
+  test("Paimon View: create view with ORDER BY ordinal") {
+    Seq(sparkCatalogName, paimonHiveCatalogName).foreach {
+      catalogName =>
+        sql(s"USE $catalogName")
+        withDatabase("test_db") {
+          sql("CREATE DATABASE test_db")
+          sql("USE test_db")
+          withTable("t") {
+            withView("v_ord") {
+              sql("CREATE TABLE t (id INT, name STRING) USING paimon")
+              sql("INSERT INTO t VALUES (2, 'b'), (1, 'a')")
+              sql("CREATE VIEW v_ord AS SELECT * FROM t ORDER BY 1")
+              checkAnswer(sql("SELECT * FROM v_ord"), Seq(Row(1, "a"), Row(2, 
"b")))
+            }
+          }
+        }
+    }
+  }
 }

Reply via email to