You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by we...@apache.org on 2025/03/26 07:00:38 UTC
(spark) branch master updated: [SPARK-51350][SQL] Implement Show Procedures
This is an automated email from the ASF dual-hosted git repository.
wenchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 100d4a0ce5e3 [SPARK-51350][SQL] Implement Show Procedures
100d4a0ce5e3 is described below
commit 100d4a0ce5e37ddfea6ea64197c77906850b8d62
Author: Szehon Ho <sz...@gmail.com>
AuthorDate: Wed Mar 26 15:00:22 2025 +0800
[SPARK-51350][SQL] Implement Show Procedures
### What changes were proposed in this pull request?
Implement Show Procedures
### Why are the changes needed?
Following SPARK-44167, we want to be able to list stored procedures of a given catalog.
### Does this PR introduce _any_ user-facing change?
Adds a new SQL statement
### How was this patch tested?
Unit tests in ProcedureSuite
### Was this patch authored or co-authored using generative AI tooling?
No
Closes #50109 from szehon-ho/SPARK-51350.
Authored-by: Szehon Ho <sz...@gmail.com>
Signed-off-by: Wenchen Fan <we...@databricks.com>
---
docs/sql-ref-ansi-compliance.md | 1 +
.../spark/sql/catalyst/parser/SqlBaseLexer.g4 | 1 +
.../spark/sql/catalyst/parser/SqlBaseParser.g4 | 3 +
.../sql/connector/catalog/ProcedureCatalog.java | 6 ++
.../sql/connector/catalog/InMemoryCatalog.scala | 1 -
.../connector/catalog/InMemoryTableCatalog.scala | 11 +++
.../spark/sql/execution/SparkSqlParser.scala | 11 ++-
.../execution/command/ShowProceduresCommand.scala | 64 +++++++++++++
.../sql-tests/results/keywords-enforced.sql.out | 1 +
.../resources/sql-tests/results/keywords.sql.out | 1 +
.../sql-tests/results/nonansi/keywords.sql.out | 1 +
.../spark/sql/connector/ProcedureSuite.scala | 106 ++++++++++++++++++++-
.../ThriftServerWithSparkContextSuite.scala | 2 +-
13 files changed, 204 insertions(+), 5 deletions(-)
diff --git a/docs/sql-ref-ansi-compliance.md b/docs/sql-ref-ansi-compliance.md
index 73a53b6deba5..53e9183dbafc 100644
--- a/docs/sql-ref-ansi-compliance.md
+++ b/docs/sql-ref-ansi-compliance.md
@@ -649,6 +649,7 @@ Below is a list of all the keywords in Spark SQL.
|PRECEDING|non-reserved|non-reserved|non-reserved|
|PRIMARY|reserved|non-reserved|reserved|
|PRINCIPALS|non-reserved|non-reserved|non-reserved|
+|PROCEDURES|non-reserved|non-reserved|non-reserved|
|PROPERTIES|non-reserved|non-reserved|non-reserved|
|PURGE|non-reserved|non-reserved|non-reserved|
|QUARTER|non-reserved|non-reserved|non-reserved|
diff --git a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseLexer.g4 b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseLexer.g4
index b868eea41b69..dad27b8524b3 100644
--- a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseLexer.g4
+++ b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseLexer.g4
@@ -362,6 +362,7 @@ POSITION: 'POSITION';
PRECEDING: 'PRECEDING';
PRIMARY: 'PRIMARY';
PRINCIPALS: 'PRINCIPALS';
+PROCEDURES: 'PROCEDURES';
PROPERTIES: 'PROPERTIES';
PURGE: 'PURGE';
QUARTER: 'QUARTER';
diff --git a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4 b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
index eda084ce2a4e..03111b5bf19e 100644
--- a/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
+++ b/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4
@@ -304,6 +304,7 @@ statement
| SHOW PARTITIONS identifierReference partitionSpec? #showPartitions
| SHOW identifier? FUNCTIONS ((FROM | IN) ns=identifierReference)?
(LIKE? (legacy=multipartIdentifier | pattern=stringLit))? #showFunctions
+ | SHOW PROCEDURES ((FROM | IN) identifierReference)? #showProcedures
| SHOW CREATE TABLE identifierReference (AS SERDE)? #showCreateTable
| SHOW CURRENT namespace #showCurrentNamespace
| SHOW CATALOGS (LIKE? pattern=stringLit)? #showCatalogs
@@ -1782,6 +1783,7 @@ ansiNonReserved
| POSITION
| PRECEDING
| PRINCIPALS
+ | PROCEDURES
| PROPERTIES
| PURGE
| QUARTER
@@ -2162,6 +2164,7 @@ nonReserved
| PRECEDING
| PRIMARY
| PRINCIPALS
+ | PROCEDURES
| PROPERTIES
| PURGE
| QUARTER
diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ProcedureCatalog.java b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ProcedureCatalog.java
index 6eaacf340cb8..ef799a6c30df 100644
--- a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ProcedureCatalog.java
+++ b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ProcedureCatalog.java
@@ -34,4 +34,10 @@ public interface ProcedureCatalog extends CatalogPlugin {
* @return the loaded unbound procedure
*/
UnboundProcedure loadProcedure(Identifier ident);
+
+ /**
+ * List all procedures in the specified namespace.
+ *
+ */
+ Identifier[] listProcedures(String[] namespace);
}
diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryCatalog.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryCatalog.scala
index 14e857e1dae3..4f0588498ec4 100644
--- a/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryCatalog.scala
+++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryCatalog.scala
@@ -33,7 +33,6 @@ class InMemoryCatalog extends InMemoryTableCatalog with FunctionCatalog with Pro
override protected def allNamespaces: Seq[Seq[String]] =
(super.allNamespaces ++ functions.keySet.asScala.map(_.namespace.toSeq)).distinct
-
override def listFunctions(namespace: Array[String]): Array[Identifier] = {
if (namespace.isEmpty || namespaceExists(namespace)) {
functions.keySet.asScala.filter(_.namespace.sameElements(namespace)).toArray
diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryTableCatalog.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryTableCatalog.scala
index 3bf3c6582b45..1b223eae9839 100644
--- a/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryTableCatalog.scala
+++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/InMemoryTableCatalog.scala
@@ -277,6 +277,17 @@ class InMemoryTableCatalog extends BasicInMemoryTableCatalog with SupportsNamesp
procedure
}
+ override def listProcedures(namespace: Array[String]): Array[Identifier] = {
+ val result =
+ if (namespaceExists(namespace)) {
+ procedures.keySet.asScala
+ .filter(_.namespace.sameElements(namespace))
+ } else {
+ throw new NoSuchNamespaceException(namespace)
+ }
+ result.filter(!_.namespace.sameElements(Array("dummy"))).toArray
+ }
+
object UnboundIncrement extends UnboundProcedure {
override def name: String = "dummy_increment"
override def description: String = "test method to increment an in-memory counter"
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
index 8859b7b421b3..eab76f4c7d88 100644
--- a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
+++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala
@@ -27,7 +27,7 @@ import org.antlr.v4.runtime.tree.TerminalNode
import org.apache.spark.SparkException
import org.apache.spark.sql.catalyst.{FunctionIdentifier, TableIdentifier}
-import org.apache.spark.sql.catalyst.analysis.{GlobalTempView, LocalTempView, PersistedView, PlanWithUnresolvedIdentifier, SchemaEvolution, SchemaTypeEvolution, UnresolvedAttribute, UnresolvedFunctionName, UnresolvedIdentifier, UnresolvedNamespace}
+import org.apache.spark.sql.catalyst.analysis.{CurrentNamespace, GlobalTempView, LocalTempView, PersistedView, PlanWithUnresolvedIdentifier, SchemaEvolution, SchemaTypeEvolution, UnresolvedAttribute, UnresolvedFunctionName, UnresolvedIdentifier, UnresolvedNamespace}
import org.apache.spark.sql.catalyst.catalog._
import org.apache.spark.sql.catalyst.expressions.{Expression, Literal}
import org.apache.spark.sql.catalyst.parser._
@@ -1179,4 +1179,13 @@ class SparkSqlAstBuilder extends AstBuilder {
}
}
}
+
+ override def visitShowProcedures(ctx: ShowProceduresContext): LogicalPlan = withOrigin(ctx) {
+ val ns = if (ctx.identifierReference != null) {
+ withIdentClause(ctx.identifierReference, UnresolvedNamespace(_))
+ } else {
+ CurrentNamespace
+ }
+ ShowProceduresCommand(ns)
+ }
}
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowProceduresCommand.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowProceduresCommand.scala
new file mode 100644
index 000000000000..f08d0924d7cd
--- /dev/null
+++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowProceduresCommand.scala
@@ -0,0 +1,64 @@
+/*
+ * 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.spark.sql.execution.command
+
+import org.apache.spark.sql.{Row, SparkSession}
+import org.apache.spark.sql.catalyst.analysis.ResolvedNamespace
+import org.apache.spark.sql.catalyst.expressions.{Attribute, AttributeReference}
+import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._
+import org.apache.spark.sql.types.{ArrayType, StringType}
+
+/**
+ * A command for users to get procedures.
+ * If a namespace is not given, the current namespace will be used.
+ * The syntax of using this command in SQL is:
+ * {{{
+ * SHOW PROCEDURES [(IN|FROM) namespace]]
+ * }}}
+ */
+case class ShowProceduresCommand(
+ child: LogicalPlan,
+ override val output: Seq[Attribute] = Seq(
+ AttributeReference("catalog", StringType, nullable = false)(),
+ AttributeReference("namespace", ArrayType(StringType, containsNull = false))(),
+ AttributeReference("schema", StringType)(),
+ AttributeReference("procedure_name", StringType, nullable = false)()
+ )) extends UnaryRunnableCommand {
+
+ override def run(sparkSession: SparkSession): Seq[Row] = {
+ child match {
+ case ResolvedNamespace(catalog, ns, _) =>
+ val procedureCatalog = catalog.asProcedureCatalog
+ val procedures = procedureCatalog.listProcedures(ns.toArray)
+
+ procedures.toSeq.map{ p =>
+ val schema = if (p.namespace() != null && p.namespace().nonEmpty) {
+ p.namespace().last
+ } else {
+ null
+ }
+ Row(catalog.name, p.namespace(), schema, p.name)
+ }
+ }
+ }
+
+ override protected def withNewChildInternal(newChild: LogicalPlan): LogicalPlan = {
+ copy(child = newChild)
+ }
+}
diff --git a/sql/core/src/test/resources/sql-tests/results/keywords-enforced.sql.out b/sql/core/src/test/resources/sql-tests/results/keywords-enforced.sql.out
index 6ee2b12be068..4e4e1eff3a7b 100644
--- a/sql/core/src/test/resources/sql-tests/results/keywords-enforced.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/keywords-enforced.sql.out
@@ -249,6 +249,7 @@ POSITION false
PRECEDING false
PRIMARY true
PRINCIPALS false
+PROCEDURES false
PROPERTIES false
PURGE false
QUARTER false
diff --git a/sql/core/src/test/resources/sql-tests/results/keywords.sql.out b/sql/core/src/test/resources/sql-tests/results/keywords.sql.out
index 16c2835bd695..e0f72b5814e3 100644
--- a/sql/core/src/test/resources/sql-tests/results/keywords.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/keywords.sql.out
@@ -249,6 +249,7 @@ POSITION false
PRECEDING false
PRIMARY false
PRINCIPALS false
+PROCEDURES false
PROPERTIES false
PURGE false
QUARTER false
diff --git a/sql/core/src/test/resources/sql-tests/results/nonansi/keywords.sql.out b/sql/core/src/test/resources/sql-tests/results/nonansi/keywords.sql.out
index 16c2835bd695..e0f72b5814e3 100644
--- a/sql/core/src/test/resources/sql-tests/results/nonansi/keywords.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/nonansi/keywords.sql.out
@@ -249,6 +249,7 @@ POSITION false
PRECEDING false
PRIMARY false
PRINCIPALS false
+PROCEDURES false
PROPERTIES false
PURGE false
QUARTER false
diff --git a/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
index f5a750a26a74..b11116039a91 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
@@ -19,6 +19,8 @@ package org.apache.spark.sql.connector
import java.util.Collections
+import scala.collection.immutable.ArraySeq
+
import org.scalatest.BeforeAndAfter
import org.apache.spark.{SPARK_DOC_ROOT, SparkException, SparkNumberFormatException}
@@ -40,15 +42,19 @@ class ProcedureSuite extends QueryTest with SharedSparkSession with BeforeAndAft
before {
spark.conf.set(s"spark.sql.catalog.cat", classOf[InMemoryCatalog].getName)
+ spark.conf.set(s"spark.sql.catalog.cat2", classOf[InMemoryCatalog].getName)
}
after {
spark.sessionState.catalogManager.reset()
spark.sessionState.conf.unsetConf(s"spark.sql.catalog.cat")
+ spark.sessionState.conf.unsetConf(s"spark.sql.catalog.cat2")
}
- private def catalog: InMemoryCatalog = {
- val catalog = spark.sessionState.catalogManager.catalog("cat")
+ private def catalog: InMemoryCatalog = catalog("cat")
+
+ private def catalog(name: String): InMemoryCatalog = {
+ val catalog = spark.sessionState.catalogManager.catalog(name)
catalog.asInstanceOf[InMemoryCatalog]
}
@@ -143,6 +149,14 @@ class ProcedureSuite extends QueryTest with SharedSparkSession with BeforeAndAft
condition = "_LEGACY_ERROR_TEMP_1184",
parameters = Map("plugin" -> "testcat", "ability" -> "procedures")
)
+
+ checkError(
+ exception = intercept[AnalysisException](
+ sql("SHOW PROCEDURES IN testcat")
+ ),
+ condition = "_LEGACY_ERROR_TEMP_1184",
+ parameters = Map("plugin" -> "testcat", "ability" -> "procedures")
+ )
}
}
@@ -348,6 +362,94 @@ class ProcedureSuite extends QueryTest with SharedSparkSession with BeforeAndAft
}
}
+ test("SPARK-51350: Implement SHOW procedures") {
+ catalog.createProcedure(Identifier.of(Array("ns"), "foo"), UnboundSum)
+ catalog.createProcedure(Identifier.of(Array("ns"), "abc"), UnboundLongSum)
+ catalog.createProcedure(Identifier.of(Array(""), "xyz"), UnboundComplexProcedure)
+ catalog.createProcedure(Identifier.of(Array(), "xxx"), UnboundStructProcedure)
+
+ sql("USE cat")
+ withNamespace("cat2.db_1") {
+ sql("CREATE NAMESPACE cat2.db_1")
+
+ catalog("cat2").createProcedure(Identifier.of(Array("ns_1", "db_1"), "foo"),
+ UnboundVoidProcedure)
+ catalog("cat2").createProcedure(Identifier.of(Array("ns_1", "db_1"), "bar"),
+ UnboundMultiResultProcedure)
+ catalog("cat2").createProcedure(Identifier.of(Array(""), "foo"),
+ UnboundVoidProcedure)
+ catalog("cat2").createProcedure(Identifier.of(Array(), "bar"),
+ UnboundMultiResultProcedure)
+
+ checkAnswer(
+ // uses default catalog and ns
+ sql("SHOW PROCEDURES"),
+ Row("cat", ArraySeq(), null, "xxx") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES IN ns"),
+ Row("cat", Array("ns"), "ns", "abc") ::
+ Row("cat", Array("ns"), "ns", "foo") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES IN cat.ns"),
+ Row("cat", Array("ns"), "ns", "abc") ::
+ Row("cat", Array("ns"), "ns", "foo") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM cat.ns"),
+ Row("cat", Array("ns"), "ns", "abc") ::
+ Row("cat", Array("ns"), "ns", "foo") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM ``"),
+ Row("cat", Array(""), "", "xyz") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM cat.``"),
+ Row("cat", Array(""), "", "xyz") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM cat2.ns_1.db_1"),
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "foo") ::
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "bar") :: Nil)
+
+ // Switch catalog.
+ sql("USE cat2")
+
+ checkAnswer(
+ sql("SHOW PROCEDURES IN cat.ns"),
+ Row("cat", Array("ns"), "ns", "abc") ::
+ Row("cat", Array("ns"), "ns", "foo") :: Nil)
+
+ checkAnswer(
+ // uses default catalog and ns
+ sql("SHOW PROCEDURES"),
+ Row("cat2", ArraySeq(), null, "bar") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM ns_1.db_1"),
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "foo") ::
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "bar") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM cat2.ns_1.db_1"),
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "foo") ::
+ Row("cat2", ArraySeq("ns_1", "db_1"), "db_1", "bar") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM ``"),
+ Row("cat2", Array(""), "", "foo") :: Nil)
+
+ checkAnswer(
+ sql("SHOW PROCEDURES FROM cat2.``"),
+ Row("cat2", Array(""), "", "foo") :: Nil)
+
+ // Switch catalog back to 'cat' before clean up.
+ sql("USE cat")
+ }
+ }
+
object UnboundVoidProcedure extends UnboundProcedure {
override def name: String = "void"
override def description: String = "void procedure"
diff --git a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerWithSparkContextSuite.scala b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerWithSparkContextSuite.scala
index 5cf7cfc58ef2..f05f5c788fa0 100644
--- a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerWithSparkContextSuite.scala
+++ b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerWithSparkContextSuite.scala
@@ -214,7 +214,7 @@ trait ThriftServerWithSparkContextSuite extends SharedThriftServer {
val sessionHandle = client.openSession(user, "")
val infoValue = client.getInfo(sessionHandle, GetInfoType.CLI_ODBC_KEYWORDS)
// scalastyle:off line.size.limit
- assert(infoValue.getStringValue == "ADD,AFTER,AGGREGATE,ALL,ALTER,ALWAYS,ANALYZE,AND,ANTI,ANY,ANY_VALUE,ARCHIVE,ARRAY,AS,ASC,AT,AUTHORIZATION,BEGIN,BETWEEN,BIGINT,BINARY,BINDING,BOOLEAN,BOTH,BUCKET,BUCKETS,BY,BYTE,CACHE,CALL,CALLED,CASCADE,CASE,CAST,CATALOG,CATALOGS,CHANGE,CHAR,CHARACTER,CHECK,CLEAR,CLUSTER,CLUSTERED,CODEGEN,COLLATE,COLLATION,COLLECTION,COLUMN,COLUMNS,COMMENT,COMMIT,COMPACT,COMPACTIONS,COMPENSATION,COMPUTE,CONCATENATE,CONDITION,CONSTRAINT,CONTAINS,CONTINUE,COST,CRE [...]
+ assert(infoValue.getStringValue == "ADD,AFTER,AGGREGATE,ALL,ALTER,ALWAYS,ANALYZE,AND,ANTI,ANY,ANY_VALUE,ARCHIVE,ARRAY,AS,ASC,AT,AUTHORIZATION,BEGIN,BETWEEN,BIGINT,BINARY,BINDING,BOOLEAN,BOTH,BUCKET,BUCKETS,BY,BYTE,CACHE,CALL,CALLED,CASCADE,CASE,CAST,CATALOG,CATALOGS,CHANGE,CHAR,CHARACTER,CHECK,CLEAR,CLUSTER,CLUSTERED,CODEGEN,COLLATE,COLLATION,COLLECTION,COLUMN,COLUMNS,COMMENT,COMMIT,COMPACT,COMPACTIONS,COMPENSATION,COMPUTE,CONCATENATE,CONDITION,CONSTRAINT,CONTAINS,CONTINUE,COST,CRE [...]
// scalastyle:on line.size.limit
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org