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 3d6275653 [spark] Add show tags sql syntax (#4316)
3d6275653 is described below

commit 3d6275653ffea606ede804c00869d0c9347f7b2b
Author: askwang <[email protected]>
AuthorDate: Mon Oct 14 20:47:35 2024 +0800

    [spark] Add show tags sql syntax (#4316)
---
 docs/content/spark/sql-ddl.md                      |  6 +++
 .../org/apache/paimon/spark/sql/ShowTagsTest.scala | 21 +++++++++
 .../org/apache/paimon/spark/sql/ShowTagsTest.scala | 21 +++++++++
 .../org/apache/paimon/spark/sql/ShowTagsTest.scala | 21 +++++++++
 .../org/apache/paimon/spark/sql/ShowTagsTest.scala | 21 +++++++++
 .../PaimonSqlExtensions.g4                         |  3 ++
 .../catalyst/plans/logical/ShowTagsCommand.scala   | 34 ++++++++++++++
 .../paimon/spark/execution/PaimonStrategy.scala    | 28 +++++++++++-
 .../paimon/spark/execution/ShowTagsExec.scala      | 52 ++++++++++++++++++++++
 .../PaimonSparkSqlExtensionsParser.scala           |  7 +--
 .../extensions/PaimonSqlExtensionsAstBuilder.scala |  6 ++-
 .../paimon/spark/sql/PaimonShowTagsTestBase.scala  | 43 ++++++++++++++++++
 12 files changed, 257 insertions(+), 6 deletions(-)

diff --git a/docs/content/spark/sql-ddl.md b/docs/content/spark/sql-ddl.md
index fa82b467d..35b2e5351 100644
--- a/docs/content/spark/sql-ddl.md
+++ b/docs/content/spark/sql-ddl.md
@@ -209,3 +209,9 @@ CREATE TABLE my_table_all (
 );
 CREATE TABLE my_table_all_as PARTITIONED BY (dt) TBLPROPERTIES ('primary-key' 
= 'dt,hh') AS SELECT * FROM my_table_all;
 ```
+
+## Show Tags
+The SHOW TAGS statement is used to list all tags of a table.
+```
+SHOW TAGS my_table;
+```
diff --git 
a/paimon-spark/paimon-spark-3.2/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
 
b/paimon-spark/paimon-spark-3.2/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
new file mode 100644
index 000000000..36b42e6b6
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-3.2/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.sql
+
+class ShowTagsTest extends PaimonShowTagsTestBase {}
diff --git 
a/paimon-spark/paimon-spark-3.3/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
 
b/paimon-spark/paimon-spark-3.3/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
new file mode 100644
index 000000000..36b42e6b6
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-3.3/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.sql
+
+class ShowTagsTest extends PaimonShowTagsTestBase {}
diff --git 
a/paimon-spark/paimon-spark-3.4/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
 
b/paimon-spark/paimon-spark-3.4/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
new file mode 100644
index 000000000..36b42e6b6
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-3.4/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.sql
+
+class ShowTagsTest extends PaimonShowTagsTestBase {}
diff --git 
a/paimon-spark/paimon-spark-3.5/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
 
b/paimon-spark/paimon-spark-3.5/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
new file mode 100644
index 000000000..36b42e6b6
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-3.5/src/test/scala/org/apache/paimon/spark/sql/ShowTagsTest.scala
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.sql
+
+class ShowTagsTest extends PaimonShowTagsTestBase {}
diff --git 
a/paimon-spark/paimon-spark-common/src/main/antlr4/org.apache.spark.sql.catalyst.parser.extensions/PaimonSqlExtensions.g4
 
b/paimon-spark/paimon-spark-common/src/main/antlr4/org.apache.spark.sql.catalyst.parser.extensions/PaimonSqlExtensions.g4
index 54e71b362..d29aaa423 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/antlr4/org.apache.spark.sql.catalyst.parser.extensions/PaimonSqlExtensions.g4
+++ 
b/paimon-spark/paimon-spark-common/src/main/antlr4/org.apache.spark.sql.catalyst.parser.extensions/PaimonSqlExtensions.g4
@@ -70,6 +70,7 @@ singleStatement
 
 statement
     : CALL multipartIdentifier '(' (callArgument (',' callArgument)*)? ')'     
             #call
+    | SHOW TAGS multipartIdentifier                                            
             #showTags
     ;
 
 callArgument
@@ -130,6 +131,8 @@ nonReserved
     ;
 
 CALL: 'CALL';
+SHOW: 'SHOW';
+TAGS: 'TAGS';
 
 TRUE: 'TRUE';
 FALSE: 'FALSE';
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/ShowTagsCommand.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/ShowTagsCommand.scala
new file mode 100644
index 000000000..f5b62d333
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/catalyst/plans/logical/ShowTagsCommand.scala
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.catalyst.plans.logical
+
+import org.apache.paimon.spark.leafnode.PaimonLeafCommand
+
+import org.apache.spark.sql.catalyst.expressions.{Attribute, 
AttributeReference}
+import org.apache.spark.sql.types.StringType
+
+case class ShowTagsCommand(table: Seq[String]) extends PaimonLeafCommand {
+
+  override def output: Seq[Attribute] =
+    Seq(AttributeReference("tag", StringType, nullable = false)())
+
+  override def simpleString(maxFields: Int): String = {
+    s"Show Tags for table: $table"
+  }
+}
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/PaimonStrategy.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/PaimonStrategy.scala
index c6c6fc875..21b809d1e 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/PaimonStrategy.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/PaimonStrategy.scala
@@ -18,16 +18,25 @@
 
 package org.apache.paimon.spark.execution
 
-import org.apache.paimon.spark.catalyst.plans.logical.PaimonCallCommand
+import org.apache.paimon.spark.{SparkCatalog, SparkUtils}
+import org.apache.paimon.spark.catalyst.plans.logical.{PaimonCallCommand, 
ShowTagsCommand}
 
 import org.apache.spark.sql.{SparkSession, Strategy}
 import org.apache.spark.sql.catalyst.InternalRow
 import org.apache.spark.sql.catalyst.expressions.{Expression, 
GenericInternalRow, PredicateHelper}
 import org.apache.spark.sql.catalyst.plans.logical.{CreateTableAsSelect, 
LogicalPlan}
+import org.apache.spark.sql.connector.catalog.{Identifier, 
PaimonLookupCatalog, TableCatalog}
 import org.apache.spark.sql.execution.SparkPlan
 import org.apache.spark.sql.execution.shim.PaimonCreateTableAsSelectStrategy
 
-case class PaimonStrategy(spark: SparkSession) extends Strategy with 
PredicateHelper {
+import scala.collection.JavaConverters._
+
+case class PaimonStrategy(spark: SparkSession)
+  extends Strategy
+  with PredicateHelper
+  with PaimonLookupCatalog {
+
+  protected lazy val catalogManager = spark.sessionState.catalogManager
 
   override def apply(plan: LogicalPlan): Seq[SparkPlan] = plan match {
 
@@ -37,6 +46,9 @@ case class PaimonStrategy(spark: SparkSession) extends 
Strategy with PredicateHe
     case c @ PaimonCallCommand(procedure, args) =>
       val input = buildInternalRow(args)
       PaimonCallExec(c.output, procedure, input) :: Nil
+
+    case t @ ShowTagsCommand(PaimonCatalogAndIdentifier(catalog, ident)) =>
+      ShowTagsExec(catalog, ident, t.output) :: Nil
     case _ => Nil
   }
 
@@ -48,4 +60,16 @@ case class PaimonStrategy(spark: SparkSession) extends 
Strategy with PredicateHe
     new GenericInternalRow(values)
   }
 
+  private object PaimonCatalogAndIdentifier {
+    def unapply(identifier: Seq[String]): Option[(TableCatalog, Identifier)] = 
{
+      val catalogAndIdentifier =
+        SparkUtils.catalogAndIdentifier(spark, identifier.asJava, 
catalogManager.currentCatalog)
+      catalogAndIdentifier.catalog match {
+        case paimonCatalog: SparkCatalog =>
+          Some((paimonCatalog, catalogAndIdentifier.identifier()))
+        case _ =>
+          None
+      }
+    }
+  }
 }
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/ShowTagsExec.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/ShowTagsExec.scala
new file mode 100644
index 000000000..8f8d2b466
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/execution/ShowTagsExec.scala
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.execution
+
+import org.apache.paimon.spark.SparkTable
+import org.apache.paimon.spark.leafnode.PaimonLeafV2CommandExec
+import org.apache.paimon.table.FileStoreTable
+
+import org.apache.spark.sql.catalyst.InternalRow
+import org.apache.spark.sql.catalyst.expressions.Attribute
+import org.apache.spark.sql.connector.catalog.{Identifier, TableCatalog}
+import org.apache.spark.unsafe.types.UTF8String
+
+import scala.collection.JavaConverters._
+
+case class ShowTagsExec(catalog: TableCatalog, ident: Identifier, out: 
Seq[Attribute])
+  extends PaimonLeafV2CommandExec {
+
+  override protected def run(): Seq[InternalRow] = {
+    val table = catalog.loadTable(ident)
+    assert(table.isInstanceOf[SparkTable])
+
+    var tags: Seq[InternalRow] = Nil
+    table.asInstanceOf[SparkTable].getTable match {
+      case paimonTable: FileStoreTable =>
+        val tagNames = paimonTable.tagManager().allTagNames()
+        tags = tagNames.asScala.toList.sorted.map(t => 
InternalRow(UTF8String.fromString(t)))
+      case t =>
+        throw new UnsupportedOperationException(
+          s"Can not show tags for non-paimon FileStoreTable: $t")
+    }
+    tags
+  }
+
+  override def output: Seq[Attribute] = out
+}
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSparkSqlExtensionsParser.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSparkSqlExtensionsParser.scala
index 26a351bc6..47991228a 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSparkSqlExtensionsParser.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSparkSqlExtensionsParser.scala
@@ -57,7 +57,7 @@ class PaimonSparkSqlExtensionsParser(delegate: 
ParserInterface)
   /** Parses a string to a LogicalPlan. */
   override def parsePlan(sqlText: String): LogicalPlan = {
     val sqlTextAfterSubstitution = substitutor.substitute(sqlText)
-    if (isCommand(sqlTextAfterSubstitution)) {
+    if (isPaimonCommand(sqlTextAfterSubstitution)) {
       parse(sqlTextAfterSubstitution)(parser => 
astBuilder.visit(parser.singleStatement()))
         .asInstanceOf[LogicalPlan]
     } else {
@@ -93,7 +93,7 @@ class PaimonSparkSqlExtensionsParser(delegate: 
ParserInterface)
     delegate.parseMultipartIdentifier(sqlText)
 
   /** Returns whether SQL text is command. */
-  private def isCommand(sqlText: String): Boolean = {
+  private def isPaimonCommand(sqlText: String): Boolean = {
     val normalized = sqlText
       .toLowerCase(Locale.ROOT)
       .trim()
@@ -101,7 +101,8 @@ class PaimonSparkSqlExtensionsParser(delegate: 
ParserInterface)
       .replaceAll("\\s+", " ")
       .replaceAll("/\\*.*?\\*/", " ")
       .trim()
-    normalized.startsWith("call")
+    normalized.startsWith("call") ||
+    normalized.contains("show tags")
   }
 
   protected def parse[T](command: String)(toResult: PaimonSqlExtensionsParser 
=> T): T = {
diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
index 3424129e9..1fe92a1b3 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/catalyst/parser/extensions/PaimonSqlExtensionsAstBuilder.scala
@@ -19,7 +19,7 @@
 package org.apache.spark.sql.catalyst.parser.extensions
 
 import org.apache.paimon.spark.catalyst.plans.logical
-import org.apache.paimon.spark.catalyst.plans.logical.{PaimonCallArgument, 
PaimonCallStatement, PaimonNamedArgument, PaimonPositionalArgument}
+import org.apache.paimon.spark.catalyst.plans.logical.{PaimonCallArgument, 
PaimonCallStatement, PaimonNamedArgument, PaimonPositionalArgument, 
ShowTagsCommand}
 
 import org.antlr.v4.runtime._
 import org.antlr.v4.runtime.misc.Interval
@@ -92,6 +92,10 @@ class PaimonSqlExtensionsAstBuilder(delegate: 
ParserInterface)
       ctx.parts.asScala.map(_.getText).toSeq
     }
 
+  override def visitShowTags(ctx: ShowTagsContext): AnyRef = withOrigin(ctx) {
+    ShowTagsCommand(typedVisit[Seq[String]](ctx.multipartIdentifier))
+  }
+
   private def toBuffer[T](list: java.util.List[T]) = list.asScala
 
   private def toSeq[T](list: java.util.List[T]) = toBuffer(list)
diff --git 
a/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/PaimonShowTagsTestBase.scala
 
b/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/PaimonShowTagsTestBase.scala
new file mode 100644
index 000000000..4d8f0b9b4
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/PaimonShowTagsTestBase.scala
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.spark.sql
+
+import org.apache.paimon.spark.PaimonSparkTestBase
+
+import org.apache.spark.sql.Row
+
+abstract class PaimonShowTagsTestBase extends PaimonSparkTestBase {
+
+  test("Paimon DDL: show tags for table") {
+    spark.sql("""CREATE TABLE T (id INT, name STRING)
+                |USING PAIMON
+                |TBLPROPERTIES ('primary-key'='id')""".stripMargin)
+
+    spark.sql("insert into T values(1, 'a')")
+    spark.sql("insert into T values(2, 'b')")
+
+    spark.sql("CALL paimon.sys.create_tag(table => 'test.T', tag => 
'2024-10-12')")
+    spark.sql("CALL paimon.sys.create_tag(table => 'test.T', tag => 
'2024-10-11')")
+    spark.sql("CALL paimon.sys.create_tag(table => 'test.T', tag => 
'2024-10-13')")
+
+    checkAnswer(
+      spark.sql("show tags T"),
+      Row("2024-10-11") :: Row("2024-10-12") :: Row("2024-10-13") :: Nil)
+  }
+}

Reply via email to