This is an automated email from the ASF dual-hosted git repository.
JingsongLi 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 f6e1df7a4b [spark] Reject SET LOCATION for format tables (#9435)
f6e1df7a4b is described below
commit f6e1df7a4b8d6406ec9a8cf559a927f30c3ac3e3
Author: Dapeng Sun(孙大鹏) <[email protected]>
AuthorDate: Fri Aug 28 13:48:20 2026 +0800
[spark] Reject SET LOCATION for format tables (#9435)
---
.../spark/catalyst/analysis/PaimonAnalysis.scala | 6 +++
.../sql/CatalogManagedPartitionDdlParityTest.scala | 55 +++++++++++++++++++++-
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonAnalysis.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonAnalysis.scala
index 40276aca1c..6353422342 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonAnalysis.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/analysis/PaimonAnalysis.scala
@@ -84,6 +84,12 @@ class PaimonAnalysis(session: SparkSession) extends
Rule[LogicalPlan] {
throw new UnsupportedOperationException(
"ALTER TABLE ... SET LOCATION is not supported for Paimon tables.")
+ // Only the table-level form. Spark's own analyzer already rejects the
partition form with a
+ // structured AnalysisException, and replacing it here would be a worse
error.
+ case SetTableLocation(ResolvedTable(_, _, _: PaimonFormatTable, _),
None, _) =>
+ throw new UnsupportedOperationException(
+ "ALTER TABLE ... SET LOCATION is not supported for Paimon tables.")
+
case r: ReplaceColumns if r.resolved && isPaimonTable(r.table) =>
// Spark rewrites REPLACE COLUMNS into a batch that drops every
existing column and re-adds
// the new set. Re-adding columns assigns brand-new field ids while
existing data files keep
diff --git
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionDdlParityTest.scala
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionDdlParityTest.scala
index 4ce81c53db..fb77ab834b 100644
---
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionDdlParityTest.scala
+++
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionDdlParityTest.scala
@@ -19,10 +19,11 @@
package org.apache.paimon.spark.sql
import org.apache.paimon.catalog.Identifier
+import org.apache.paimon.fs.Path
import org.apache.paimon.spark.PaimonSparkTestWithRestCatalogBase
import org.apache.paimon.table.FormatTable
-import org.apache.spark.sql.Row
+import org.apache.spark.sql.{AnalysisException, Row}
import scala.collection.JavaConverters._
@@ -154,6 +155,58 @@ class CatalogManagedPartitionDdlParityTest extends
PaimonSparkTestWithRestCatalo
}
}
+ test("SET LOCATION is rejected without changing a catalog-managed Format
Table") {
+ val tableName = "ddl_set_location"
+ withTable(tableName) {
+ createTable(tableName)
+ val table = formatTable(tableName)
+ val originalLocation = table.location().toString
+ sql(s"ALTER TABLE ${qualified(tableName)} ADD PARTITION (dt =
'20260101', hour = '00')")
+ table
+ .fileIO()
+ .writeFile(new Path(table.location(),
"dt=20260101/hour=00/part-00001.csv"), "1,a\n", false)
+
+ val error = intercept[UnsupportedOperationException] {
+ sql(s"ALTER TABLE ${qualified(tableName)} SET LOCATION
'${originalLocation}_relocated'")
+ }
+
+ assert(error.getMessage == "ALTER TABLE ... SET LOCATION is not
supported for Paimon tables.")
+ assert(formatTable(tableName).location().toString == originalLocation)
+ assert(registered(tableName) == Set("20260101/00"))
+ checkAnswer(
+ sql(s"SELECT id, payload, dt, hour FROM ${qualified(tableName)}"),
+ Seq(Row(1, "a", "20260101", "00")))
+ }
+ }
+
+ test("partition SET LOCATION keeps Spark's structured rejection and table
state") {
+ val tableName = "ddl_partition_set_location"
+ withTable(tableName) {
+ createTable(tableName)
+ val table = formatTable(tableName)
+ val originalLocation = table.location().toString
+ sql(s"ALTER TABLE ${qualified(tableName)} ADD PARTITION (dt =
'20260101', hour = '00')")
+ table
+ .fileIO()
+ .writeFile(new Path(table.location(),
"dt=20260101/hour=00/part-00001.csv"), "1,a\n", false)
+
+ val error = intercept[AnalysisException] {
+ sql(
+ s"ALTER TABLE ${qualified(tableName)} PARTITION " +
+ s"(dt = '20260101', hour = '00') SET LOCATION
'${originalLocation}_relocated'")
+ }
+
+ // Spark 4 renamed getErrorClass to getCondition and is still moving
these legacy ids to
+ // named conditions, so match the message instead of the id.
+ assert(error.getMessage.contains("does not support partition"))
+ assert(formatTable(tableName).location().toString == originalLocation)
+ assert(registered(tableName) == Set("20260101/00"))
+ checkAnswer(
+ sql(s"SELECT id, payload, dt, hour FROM ${qualified(tableName)}"),
+ Seq(Row(1, "a", "20260101", "00")))
+ }
+ }
+
private def qualified(tableName: String): String =
s"paimon.$dbName0.$tableName"
private def createTable(tableName: String): Unit =