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")))
+ }
+ }
+ }
+ }
+ }
}