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 bc6531dfba [spark] Allow partition and bucket metadata queries during
merge reads (#10481)
bc6531dfba is described below
commit bc6531dfba4e568d65298c5b46e7485376f595eb
Author: Ran Tao <[email protected]>
AuthorDate: Sat Oct 10 14:35:46 2026 +0800
[spark] Allow partition and bucket metadata queries during merge reads
(#10481)
---
.../paimon/spark/PaimonRecordReaderIterator.scala | 8 +--
.../apache/paimon/spark/sql/PaimonQueryTest.scala | 60 +++++++++++++++++-----
2 files changed, 52 insertions(+), 16 deletions(-)
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonRecordReaderIterator.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonRecordReaderIterator.scala
index 93256df2c0..d2c758e93e 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonRecordReaderIterator.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonRecordReaderIterator.scala
@@ -133,7 +133,7 @@ case class PaimonRecordReaderIterator(
currentIterator.asInstanceOf[ScoreRecordIterator[PaimonInternalRow]])
currentResult = joinedRow.replace(dataRow, metadataRow)
} else if (needMetadata) {
-
updateMetadataRow(currentIterator.asInstanceOf[FileRecordIterator[PaimonInternalRow]])
+ updateMetadataRow(currentIterator)
currentResult = joinedRow.replace(dataRow, metadataRow)
} else {
currentResult = dataRow
@@ -160,12 +160,14 @@ case class PaimonRecordReaderIterator(
}
}
- private def updateMetadataRow(fileRecordIterator:
FileRecordIterator[PaimonInternalRow]): Unit = {
+ private def updateMetadataRow(iterator:
RecordReader.RecordIterator[PaimonInternalRow]): Unit = {
metadataColumns.zipWithIndex.foreach {
case (metadataColumn, index) =>
metadataColumn.name match {
case PaimonMetadataColumn.ROW_INDEX_COLUMN =>
- metadataRow.setField(index, fileRecordIterator.returnedPosition())
+ metadataRow.setField(
+ index,
+
iterator.asInstanceOf[FileRecordIterator[PaimonInternalRow]].returnedPosition())
case PaimonMetadataColumn.FILE_PATH_COLUMN =>
metadataRow.setField(index,
BinaryString.fromString(lastFilePath.toString))
case PaimonMetadataColumn.PARTITION_COLUMN =>
diff --git
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonQueryTest.scala
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonQueryTest.scala
index f94313f5e7..24287d5417 100644
---
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonQueryTest.scala
+++
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/PaimonQueryTest.scala
@@ -384,22 +384,56 @@ class PaimonQueryTest extends PaimonSparkTestBase {
)
}
- test("Paimon Query: not support querying metadata columns for pk table") {
- spark.sql("""
- |CREATE TABLE T (id INT, name STRING)
- |TBLPROPERTIES ('primary-key' = 'id', 'bucket' = '1')
- |""".stripMargin)
+ test("Paimon Query: query partition and bucket metadata columns for pk
table") {
+ withTable("T") {
+ sql("""
+ |CREATE TABLE T (id INT, name STRING, pt STRING) PARTITIONED BY
(pt)
+ |TBLPROPERTIES (
+ | 'primary-key' = 'pt,id',
+ | 'bucket' = '1',
+ | 'write-only' = 'true',
+ | 'deletion-vectors.enabled' = 'false')
+ |""".stripMargin)
- spark.sql("INSERT INTO T VALUES(1,'a')")
- assertThat(spark.sql("SELECT *,__paimon_file_path FROM
T").collect()).hasSize(1)
+ sql("INSERT INTO T VALUES (1, 'old', 'p1')")
+ checkAnswer(
+ sql("SELECT id, name, __paimon_bucket, __paimon_partition FROM T"),
+ Row(1, "old", 0, Row("p1")))
+
+ // Updating the same key in a separate file requires merging; write-only
disables compaction.
+ sql("INSERT INTO T VALUES (1, 'new', 'p1')")
+ checkAnswer(sql("SELECT id, name FROM T"), Row(1, "new"))
+ checkAnswer(sql("SELECT __paimon_bucket FROM T"), Row(0))
+ checkAnswer(sql("SELECT __paimon_partition FROM T"), Row(Row("p1")))
+ checkAnswer(
+ sql("SELECT id, name, __paimon_bucket, __paimon_partition FROM T"),
+ Row(1, "new", 0, Row("p1")))
+ checkAnswer(
+ sql("SELECT __paimon_bucket, __paimon_partition FROM T WHERE id =
999"),
+ Seq.empty)
+ }
+ }
+
+ test("Paimon Query: reject file path and row index metadata when merging pk
files") {
+ sql("""
+ |CREATE TABLE T (id INT, name STRING)
+ |TBLPROPERTIES ('primary-key' = 'id', 'bucket' = '1')
+ |""".stripMargin)
+
+ sql("INSERT INTO T VALUES(1,'a')")
+ assertThat(sql("SELECT *, __paimon_file_path, __paimon_row_index FROM
T").collect()).hasSize(1)
// query failed if more than one file in a bucket
- spark.sql("INSERT INTO T VALUES(2,'b')")
- assert(
- intercept[SparkException] {
- spark.sql("SELECT *,__paimon_file_path FROM T").collect()
- }.getMessage
- .contains("Only append table or deletion vector table support querying
metadata columns."))
+ sql("INSERT INTO T VALUES(2,'b')")
+ Seq("__paimon_file_path", "__paimon_row_index").foreach {
+ column =>
+ assert(
+ intercept[SparkException] {
+ sql(s"SELECT *, $column FROM T").collect()
+ }.getMessage
+ .contains(
+ "Only append table or deletion vector table support querying
metadata columns."))
+ }
}
test("Paimon Query: disallow full scan") {