This is an automated email from the ASF dual-hosted git repository.
cloud-fan 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 90d1fbecbdbd [SPARK-54710][SQL] Show Partitions As Json
90d1fbecbdbd is described below
commit 90d1fbecbdbdfe671eee6de6a96c67a65c064d51
Author: ashutosh-jindal <[email protected]>
AuthorDate: Fri Jun 19 17:14:48 2026 -0700
[SPARK-54710][SQL] Show Partitions As Json
### What changes were proposed in this pull request?
Support SHOW PARTITIONS ... [AS JSON] to display table metadata in JSON
format.
SQL Ref Spec:
```
SHOW PARTITIONS table_name [ PARTITION clause ] [ AS JSON ]
```
Output:
json_metadata: String
### Why are the changes needed?
The Spark SQL command `SHOW PARTITIONS` displays partitions list meant more
for human consumption. With the introduction of the `AS JSON` option, the
command now returns table metadata as a JSON string suitable for machine
consumption.
### Does this PR introduce _any_ user-facing change?
Yes, this provides a new option to display `SHOW PARTITIONS` metadata in
JSON format. See below for the JSON output schema:
```json
{
"partitions": [{"col": "val", ...}, ...]
}
```
### How was this patch tested?
Added tests in `v1/ShowPartitionsSuite.scala`,
`v2/ShowPartitionsSuite.scala` and `ShowPartitionsParserSuite.scala`.
### Was this patch authored or co-authored using generative AI tooling?
No
Closes #55441 from ashutosh-jindal/partitions-as-json.
Lead-authored-by: ashutosh-jindal
<[email protected]>
Co-authored-by: Ashutosh Jindal <[email protected]>
Co-authored-by: Wenchen Fan <[email protected]>
Signed-off-by: Wenchen Fan <[email protected]>
---
docs/sql-ref-syntax-aux-show-partitions.md | 59 ++++++++++-
.../spark/sql/catalyst/parser/SqlBaseParser.g4 | 2 +-
.../spark/sql/catalyst/parser/AstBuilder.scala | 2 +-
.../spark/sql/errors/QueryCompilationErrors.scala | 4 +
.../spark/sql/execution/SparkSqlParser.scala | 23 ++++
.../command/ShowPartitionsJsonCommand.scala | 93 ++++++++++++++++
.../spark/sql/execution/command/tables.scala | 49 ++++-----
.../execution/command/v1/ShowPartitionsSuite.scala | 117 +++++++++++++++++++++
.../execution/command/v2/ShowPartitionsSuite.scala | 12 +++
9 files changed, 332 insertions(+), 29 deletions(-)
diff --git a/docs/sql-ref-syntax-aux-show-partitions.md
b/docs/sql-ref-syntax-aux-show-partitions.md
index 0b2ed3507e29..35dccf1f3608 100644
--- a/docs/sql-ref-syntax-aux-show-partitions.md
+++ b/docs/sql-ref-syntax-aux-show-partitions.md
@@ -28,7 +28,7 @@ partition spec.
### Syntax
```sql
-SHOW PARTITIONS table_identifier [ partition_spec ]
+SHOW PARTITIONS table_identifier [ partition_spec ] [ AS JSON ]
```
### Parameters
@@ -46,6 +46,31 @@ SHOW PARTITIONS table_identifier [ partition_spec ]
**Syntax:** `PARTITION ( partition_col_name = partition_col_val [ , ... ]
)`
+* **AS JSON**
+
+ An optional parameter to return the partition list as a single-row JSON
document
+ instead of the default tabular format. Only supported for V1 (session
catalog / Hive
+ metastore) tables.
+
+ **Syntax:** `[ AS JSON ]`
+
+ **Output schema:** A single column named `json_metadata` of type `STRING
NOT NULL`.
+
+ **Schema:**
+
+ Below is the full JSON schema.
+ In actual output, the JSON is not pretty-printed (see Examples).
+
+ ```json
+ {
+ "partitions": [{"col": "val", ...}, ...]
+ }
+ ```
+
+ | Field | Type | Description |
+ |---|---|---|
+ | `partitions` | array of objects | Each element is a JSON object mapping
partition column names to their string values. The array is empty when no
partitions match the optional `partition_spec`. Elements appear in the order
returned by the underlying catalog (lexicographic for in-memory and Hive
catalogs); no order is guaranteed across catalogs.|
+
### Examples
```sql
@@ -100,6 +125,38 @@ SHOW PARTITIONS customer PARTITION (city = 'San Jose');
+----------------------+
|state=CA/city=San Jose|
+----------------------+
+
+-- List all partitions as a JSON
+SHOW PARTITIONS customer AS JSON;
++--------------------------------------------------------------------------------------------------------------+
+|json_metadata
|
++--------------------------------------------------------------------------------------------------------------+
+|{"partitions":[{"state":"AZ","city":"Peoria"},{"state":"CA","city":"Fremont"},{"state":"CA","city":"San
Jose"}]}|
++--------------------------------------------------------------------------------------------------------------+
+
+-- Filter with a partial partition spec and return results as JSON
+SHOW PARTITIONS customer PARTITION (state = 'CA') AS JSON;
++-----------------------------------------------------------------------------------+
+|json_metadata
|
++-----------------------------------------------------------------------------------+
+|{"partitions":[{"state":"CA","city":"Fremont"},{"state":"CA","city":"San
Jose"}]} |
++-----------------------------------------------------------------------------------+
+
+-- Filter with a full partition spec as JSON
+SHOW PARTITIONS customer PARTITION (state = 'CA', city = 'Fremont') AS JSON;
++--------------------------------------------------+
+|json_metadata |
++--------------------------------------------------+
+|{"partitions":[{"state":"CA","city":"Fremont"}]} |
++--------------------------------------------------+
+
+-- When no partitions match the spec, AS JSON returns an empty array
+SHOW PARTITIONS customer PARTITION (state = 'TX') AS JSON;
++------------------+
+|json_metadata |
++------------------+
+|{"partitions":[]} |
++------------------+
```
### Related Statements
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 bb44041f67dd..cce03c169aac 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
@@ -373,7 +373,7 @@ statement
((FROM | IN) ns=multipartIdentifier)?
#showColumns
| SHOW VIEWS ((FROM | IN) identifierReference)?
(LIKE? pattern=stringLit)?
#showViews
- | SHOW PARTITIONS identifierReference partitionSpec?
#showPartitions
+ | SHOW PARTITIONS identifierReference partitionSpec? (AS JSON)?
#showPartitions
| SHOW functionScope=simpleIdentifier? FUNCTIONS ((FROM | IN)
ns=identifierReference)?
(LIKE? (legacy=multipartIdentifier | pattern=stringLit))?
#showFunctions
| SHOW PROCEDURES ((FROM | IN) identifierReference)?
#showProcedures
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
index 23bdeaa16584..4dc63760e6a2 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
@@ -4430,7 +4430,7 @@ class AstBuilder extends DataTypeAstBuilder
/**
* Create an [[UnresolvedTable]] from an identifier reference.
*/
- private def createUnresolvedTable(
+ protected def createUnresolvedTable(
ctx: IdentifierReferenceContext,
commandName: String,
suggestAlternative: Boolean = false): LogicalPlan = withOrigin(ctx) {
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
index 7f76f48cc7ef..239aaf3e29e8 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryCompilationErrors.scala
@@ -1746,6 +1746,10 @@ private[sql] object QueryCompilationErrors extends
QueryErrorsBase with Compilat
notSupportedInJDBCCatalog("CREATE TABLE ... USING ...")
}
+ def showPartitionsAsJsonNotSupportedForV2TablesError(): Throwable = {
+ notSupportedForV2TablesError("SHOW PARTITIONS AS JSON")
+ }
+
def cannotCreateJDBCTableUsingLocationError(): Throwable = {
notSupportedInJDBCCatalog("CREATE TABLE ... LOCATION ...")
}
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 bce51f7c23fa..8ff2161a2965 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
@@ -1480,6 +1480,29 @@ class SparkSqlAstBuilder extends AstBuilder {
}
}
+ /**
+ * Overrides `SHOW PARTITIONS` parsing to intercept the `AS JSON` variant.
+ *
+ * When `AS JSON` is absent, parsing is delegated to the superclass
+ * ([[AstBuilder#visitShowPartitions]]), which produces a [[ShowPartitions]]
logical plan.
+ *
+ * When `AS JSON` is present, this method produces a
[[ShowPartitionsJsonCommand]] directly -
+ * a runnable command that returns partition metadata as a single-row JSON
document.
+ *
+ * The syntax of using this command in SQL is:
+ * {{{
+ * SHOW PARTITIONS multi_part_name [partition_spec] [AS JSON];
+ * }}}
+ */
+ override def visitShowPartitions(ctx: ShowPartitionsContext): LogicalPlan =
withOrigin(ctx) {
+ if (ctx.JSON == null) return super.visitShowPartitions(ctx)
+ val relation = createUnresolvedTable(ctx.identifierReference, "SHOW
PARTITIONS AS JSON")
+ val partitionKeys = Option(ctx.partitionSpec).map { specCtx =>
+ UnresolvedPartitionSpec(visitNonOptionalPartitionSpec(specCtx), None)
+ }
+ ShowPartitionsJsonCommand(relation, partitionKeys.map(_.spec))
+ }
+
override def visitShowProcedures(ctx: ShowProceduresContext): LogicalPlan =
withOrigin(ctx) {
val ns = if (ctx.identifierReference != null) {
withIdentClause(ctx.identifierReference, UnresolvedNamespace(_))
diff --git
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowPartitionsJsonCommand.scala
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowPartitionsJsonCommand.scala
new file mode 100644
index 000000000000..c74a7d8af034
--- /dev/null
+++
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/ShowPartitionsJsonCommand.scala
@@ -0,0 +1,93 @@
+/*
+ * 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.json4s._
+import org.json4s.JsonAST.JObject
+import org.json4s.jackson.JsonMethods.{compact, render}
+
+import org.apache.spark.sql.{Row, SparkSession}
+import org.apache.spark.sql.catalyst.analysis.ResolvedTable
+import org.apache.spark.sql.catalyst.catalog.CatalogTypes.TablePartitionSpec
+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.V1Table
+import org.apache.spark.sql.errors.QueryCompilationErrors
+import org.apache.spark.sql.types.{MetadataBuilder, StringType}
+
+/**
+ * A command for users to list the partition names of a table as a JSON
document. If a partition
+ * spec is specified, only partitions matching the spec are returned.
Otherwise all partitions are
+ * returned.
+ *
+ * The output is a single row with a `json_metadata` column containing a JSON
object of the form:
+ * `{"partitions": [{"col": "val", ...}, ...]}`, where each element of the
array is a JSON object
+ * mapping partition column names to their string values.
+ *
+ * This command is the AS JSON variant of [[ShowPartitions]] and is produced
by the parser
+ * when `SHOW PARTITIONS ... AS JSON` is issued. Only V1 (session catalog /
Hive metastore) tables
+ * are supported.
+ *
+ * The syntax of using this command in SQL is:
+ * {{{
+ * SHOW PARTITIONS multi_part_name [partition_spec] AS JSON;
+ * }}}
+ */
+case class ShowPartitionsJsonCommand(
+ child: LogicalPlan,
+ spec: Option[TablePartitionSpec],
+ override val output: Seq[Attribute] = Seq(
+ AttributeReference(
+ "json_metadata",
+ StringType,
+ nullable = false,
+ new MetadataBuilder().putString("comment", "Partition list of the
table").build())()))
+ extends UnaryRunnableCommand {
+
+ /**
+ * Converts a partition name string (e.g. `"year=2015/month=1"`) into a
[[JObject]] where each
+ * path segment becomes a key-value pair (e.g.
`{"year":"2015","month":"1"}`).
+ */
+ private def partitionNameToJson(partName: String): JObject = {
+ JObject(partName.split("/").map { segment =>
+ val eqIdx = segment.indexOf('=')
+ if (eqIdx >= 0) {
+ segment.substring(0, eqIdx) -> JString(segment.substring(eqIdx + 1))
+ } else {
+ segment -> JString("")
+ }
+ }.toList)
+ }
+
+ override def run(sparkSession: SparkSession): Seq[Row] = {
+ child match {
+ case ResolvedTable(_, _, t: V1Table, _) =>
+ val partNames = ShowPartitionsHelper.listV1PartitionNames(
+ sparkSession, t.catalogTable, spec, "SHOW PARTITIONS AS JSON")
+ Seq(Row(compact(render(JObject("partitions" ->
+ JArray(partNames.map(partitionNameToJson).toList))))))
+
+ // Non-V1 tables are currently not supported.
+ case _ =>
+ throw
QueryCompilationErrors.showPartitionsAsJsonNotSupportedForV2TablesError()
+ }
+ }
+
+ override protected def withNewChildInternal(newChild: LogicalPlan):
LogicalPlan = {
+ copy(child = newChild)
+ }
+}
diff --git
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala
index ca534706635a..e0a4922efe9e 100644
---
a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala
+++
b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/tables.scala
@@ -1062,37 +1062,34 @@ case class ShowPartitionsCommand(
spec: Option[TablePartitionSpec]) extends LeafRunnableCommand {
override def run(sparkSession: SparkSession): Seq[Row] = {
- val catalog = sparkSession.sessionState.catalog
- val table = catalog.getTableMetadata(tableName)
- val tableIdentWithDB = table.identifier.quotedString
-
- /**
- * Validate and throws an [[AnalysisException]] exception under the
following conditions:
- * 1. If the table is not partitioned.
- * 2. If it is a datasource table.
- */
+ val table = sparkSession.sessionState.catalog.getTableMetadata(tableName)
+ ShowPartitionsHelper.listV1PartitionNames(sparkSession, table,
spec).map(Row(_))
+ }
+}
+object ShowPartitionsHelper {
+ /**
+ * Used by [[ShowPartitionsCommand]] and [[ShowPartitionsJsonCommand]] to
+ * extract partition names of V1 tables.
+ */
+ def listV1PartitionNames(
+ sparkSession: SparkSession,
+ table: CatalogTable,
+ spec: Option[TablePartitionSpec],
+ commandName: String = "SHOW PARTITIONS"): Seq[String] = {
+ val tableIdentWithDB = table.identifier.quotedString
if (table.partitionColumnNames.isEmpty) {
throw
QueryCompilationErrors.showPartitionNotAllowedOnTableNotPartitionedError(
tableIdentWithDB)
}
-
- DDLUtils.verifyPartitionProviderIsHive(sparkSession, table, "SHOW
PARTITIONS")
-
- /**
- * Normalizes the partition spec w.r.t the partition columns and case
sensitivity settings,
- * and validates the spec by making sure all the referenced columns are
- * defined as partitioning columns in table definition. An
AnalysisException exception is
- * thrown if the partitioning spec is invalid.
- */
- val normalizedSpec = spec.map(partitionSpec =>
PartitioningUtils.normalizePartitionSpec(
- partitionSpec,
- table.partitionSchema,
- table.identifier.quotedString,
- sparkSession.sessionState.conf.resolver))
-
- val partNames = catalog.listPartitionNames(tableName, normalizedSpec)
- partNames.map(Row(_))
+ DDLUtils.verifyPartitionProviderIsHive(sparkSession, table, commandName)
+ val normalizedSpec = spec.map(partitionSpec =>
+ PartitioningUtils.normalizePartitionSpec(
+ partitionSpec,
+ table.partitionSchema,
+ tableIdentWithDB,
+ sparkSession.sessionState.conf.resolver))
+ sparkSession.sessionState.catalog.listPartitionNames(table.identifier,
normalizedSpec)
}
}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/ShowPartitionsSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/ShowPartitionsSuite.scala
index 0f64fa49f486..8789fb20fc06 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/ShowPartitionsSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v1/ShowPartitionsSuite.scala
@@ -20,6 +20,7 @@ package org.apache.spark.sql.execution.command.v1
import org.apache.spark.sql.{AnalysisException, Row, SaveMode}
import org.apache.spark.sql.catalyst.analysis.UnresolvedAttribute
import org.apache.spark.sql.catalyst.util.quoteIdentifier
+import
org.apache.spark.sql.connector.catalog.CatalogManager.SESSION_CATALOG_NAME
import org.apache.spark.sql.execution.command
/**
@@ -105,6 +106,73 @@ trait ShowPartitionsSuiteBase extends
command.ShowPartitionsSuiteBase {
Row("p1=__HIVE_DEFAULT_PARTITION__"))
}
}
+
+ test("show partitions as JSON") {
+ withNamespaceAndTable("ns", "dateTable") { t =>
+ createDateTable(t)
+ val df = spark.sql(s"SHOW PARTITIONS $t AS JSON")
+ assert(df.schema.length == 1)
+ assert(df.schema.head.name == "json_metadata")
+ checkAnswer(
+ df,
+ Row(
+
"""{"partitions":[{"year":"2015","month":"1"},{"year":"2015","month":"2"},""" +
+ """{"year":"2016","month":"2"},{"year":"2016","month":"3"}]}"""))
+ }
+ }
+
+ test("show partitions with spec as JSON") {
+ withNamespaceAndTable("ns", "dateTable") { t =>
+ createDateTable(t)
+ checkAnswer(
+ spark.sql(s"SHOW PARTITIONS $t PARTITION(year=2015) AS JSON"),
+
Row("""{"partitions":[{"year":"2015","month":"1"},{"year":"2015","month":"2"}]}"""))
+ checkAnswer(
+ spark.sql(s"SHOW PARTITIONS $t PARTITION(year=2015, month=1) AS JSON"),
+ Row("""{"partitions":[{"year":"2015","month":"1"}]}"""))
+ checkAnswer(
+ spark.sql(s"SHOW PARTITIONS $t PARTITION(month=2) AS JSON"),
+
Row("""{"partitions":[{"year":"2015","month":"2"},{"year":"2016","month":"2"}]}"""))
+ }
+ }
+
+ test("show partitions as JSON with no partitions matching the spec") {
+ withNamespaceAndTable("ns", "dateTable") { t =>
+ createDateTable(t)
+ checkAnswer(
+ spark.sql(s"SHOW PARTITIONS $t PARTITION(year=9999) AS JSON"),
+ Row("""{"partitions":[]}"""))
+ }
+ }
+
+ test("null as a partition value AS JSON") {
+ val t = "part_table"
+ withTable(t) {
+ sql(s"CREATE TABLE $t (col1 INT, p1 STRING) $defaultUsing PARTITIONED BY
(p1)")
+ sql(s"INSERT INTO TABLE $t PARTITION (p1 = null) SELECT 0")
+ checkAnswer(
+ sql(s"SHOW PARTITIONS $t AS JSON"),
+ Row("""{"partitions":[{"p1":"__HIVE_DEFAULT_PARTITION__"}]}"""))
+ checkAnswer(
+ sql(s"SHOW PARTITIONS $t PARTITION (p1 = null) AS JSON"),
+ Row("""{"partitions":[{"p1":"__HIVE_DEFAULT_PARTITION__"}]}"""))
+ }
+ }
+
+ test("non-partitioning columns AS JSON") {
+ withNamespaceAndTable("ns", "dateTable") { t =>
+ createDateTable(t)
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql(s"SHOW PARTITIONS $t PARTITION(abcd=2015, xyz=1) AS JSON")
+ },
+ condition = "PARTITIONS_NOT_FOUND",
+ parameters = Map(
+ "partitionList" -> "`abcd`",
+ "tableName" -> s"`$SESSION_CATALOG_NAME`.`ns`.`datetable`")
+ )
+ }
+ }
}
/**
@@ -168,6 +236,20 @@ class ShowPartitionsSuite extends ShowPartitionsSuiteBase
with CommandSuiteBase
}
}
+ test("show partitions of non-partitioned table AS JSON") {
+ withNamespaceAndTable("ns", "not_partitioned_table") { t =>
+ sql(s"CREATE TABLE $t (col1 int) $defaultUsing")
+ val tableName =
+
UnresolvedAttribute.parseAttributeName(t).map(quoteIdentifier).mkString(".")
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql(s"SHOW PARTITIONS $t AS JSON")
+ },
+ condition = "INVALID_PARTITION_OPERATION.PARTITION_SCHEMA_IS_EMPTY",
+ parameters = Map("name" -> tableName))
+ }
+ }
+
test("SPARK-33904: null and empty string as partition values") {
withNamespaceAndTable("ns", "tbl") { t =>
createNullPartTable(t, "parquet")
@@ -177,4 +259,39 @@ class ShowPartitionsSuite extends ShowPartitionsSuiteBase
with CommandSuiteBase
checkAnswer(spark.table(t), Row(0, null) :: Row(1, null) :: Nil)
}
}
+
+ test("null and empty string as partition values AS JSON") {
+ withNamespaceAndTable("ns", "tbl") { t =>
+ createNullPartTable(t, "parquet")
+ checkAnswer(
+ sql(s"SHOW PARTITIONS $t AS JSON"),
+ Row("""{"partitions":[{"part":"__HIVE_DEFAULT_PARTITION__"}]}"""))
+ }
+ }
+
+ test("partition value containing '/' AS JSON") {
+ withTable("slash_part") {
+ sql(s"CREATE TABLE slash_part (col1 INT, p STRING) $defaultUsing
PARTITIONED BY (p)")
+ sql("INSERT INTO TABLE slash_part PARTITION (p = 'a/b') SELECT 0")
+ checkAnswer(
+ sql("SHOW PARTITIONS slash_part AS JSON"),
+ Row("""{"partitions":[{"p":"a%2Fb"}]}"""))
+ // Filtering by the escaped spec also works and returns the same encoded
value.
+ checkAnswer(
+ sql("SHOW PARTITIONS slash_part PARTITION (p = 'a/b') AS JSON"),
+ Row("""{"partitions":[{"p":"a%2Fb"}]}"""))
+ }
+ }
+
+ test("partition value containing '=' AS JSON") {
+ // '=' is encoded as '%3D'; splitting on the first '=' in each segment is
still
+ // correct because a column name never contains an unencoded '='.
+ withTable("eq_part") {
+ sql(s"CREATE TABLE eq_part (col1 INT, p STRING) $defaultUsing
PARTITIONED BY (p)")
+ sql("INSERT INTO TABLE eq_part PARTITION (p = 'a=b') SELECT 0")
+ checkAnswer(
+ sql("SHOW PARTITIONS eq_part AS JSON"),
+ Row("""{"partitions":[{"p":"a%3Db"}]}"""))
+ }
+ }
}
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ShowPartitionsSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ShowPartitionsSuite.scala
index 1fb1c4889060..403ca9fa8edc 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ShowPartitionsSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ShowPartitionsSuite.scala
@@ -77,4 +77,16 @@ class ShowPartitionsSuite extends
command.ShowPartitionsSuiteBase with CommandSu
checkAnswer(spark.table(t), Row(0, "") :: Row(1, null) :: Nil)
}
}
+
+ test("SHOW PARTITIONS AS JSON is not supported for V2 tables") {
+ withNamespaceAndTable("ns", "dateTable") { t =>
+ createDateTable(t)
+ checkError(
+ exception = intercept[AnalysisException] {
+ sql(s"SHOW PARTITIONS $t AS JSON")
+ },
+ condition = "NOT_SUPPORTED_COMMAND_FOR_V2_TABLE",
+ parameters = Map("cmd" -> "SHOW PARTITIONS AS JSON"))
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]