Skip to content

Commit 48bc989

Browse files
Support EXTENDED for EXPLAIN
1 parent fa5a08e commit 48bc989

File tree

6 files changed

+77
-10
lines changed

6 files changed

+77
-10
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/commands.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ case class SetCommand(key: Option[String], value: Option[String]) extends Comman
5050
* Returned by a parser when the users only wants to see what query plan would be executed, without
5151
* actually performing the execution.
5252
*/
53-
case class ExplainCommand(plan: LogicalPlan) extends Command {
53+
case class ExplainCommand(plan: LogicalPlan, extended: Boolean = false) extends Command {
5454
override def output =
5555
Seq(AttributeReference("plan", StringType, nullable = false)())
5656
}

sql/core/src/main/scala/org/apache/spark/sql/SQLContext.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,9 @@ class SQLContext(@transient val sparkContext: SparkContext)
411411
def simpleString: String = stringOrError(executedPlan)
412412

413413
override def toString: String =
414-
s"""== Logical Plan ==
414+
s"""== Parsed Logical Plan ==
415+
|${stringOrError(logical)}
416+
|== Analyzed Logical Plan ==
415417
|${stringOrError(analyzed)}
416418
|== Optimized Logical Plan ==
417419
|${stringOrError(optimizedPlan)}
@@ -421,6 +423,14 @@ class SQLContext(@transient val sparkContext: SparkContext)
421423
|== RDD ==
422424
|${stringOrError(toRdd.toDebugString)}
423425
""".stripMargin.trim
426+
427+
def toSimpleString: String =
428+
s"""== Physical Plan ==
429+
|${stringOrError(executedPlan)}
430+
|Code Generation: ${executedPlan.codegenEnabled}
431+
|== RDD ==
432+
|${stringOrError(toRdd.toDebugString)}
433+
""".stripMargin.trim
424434
}
425435

426436
/**

sql/core/src/main/scala/org/apache/spark/sql/execution/SparkStrategies.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ private[sql] abstract class SparkStrategies extends QueryPlanner[SparkPlan] {
297297
def apply(plan: LogicalPlan): Seq[SparkPlan] = plan match {
298298
case logical.SetCommand(key, value) =>
299299
Seq(execution.SetCommand(key, value, plan.output)(context))
300-
case logical.ExplainCommand(logicalPlan) =>
301-
Seq(execution.ExplainCommand(logicalPlan, plan.output)(context))
300+
case logical.ExplainCommand(logicalPlan, extended) =>
301+
Seq(execution.ExplainCommand(logicalPlan, plan.output, extended)(context))
302302
case logical.CacheCommand(tableName, cache) =>
303303
Seq(execution.CacheCommand(tableName, cache)(context))
304304
case _ => Nil

sql/core/src/main/scala/org/apache/spark/sql/execution/commands.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,19 @@ case class SetCommand(
108108
*/
109109
@DeveloperApi
110110
case class ExplainCommand(
111-
logicalPlan: LogicalPlan, output: Seq[Attribute])(
111+
logicalPlan: LogicalPlan, output: Seq[Attribute], extended: Boolean)(
112112
@transient context: SQLContext)
113113
extends LeafNode with Command {
114114

115115
// Run through the optimizer to generate the physical plan.
116116
override protected[sql] lazy val sideEffectResult: Seq[String] = try {
117-
"Physical execution plan:" +: context.executePlan(logicalPlan).executedPlan.toString.split("\n")
117+
// TODO in Hive, the "extended" ExplainCommand prints the AST as well, and detailed properties.
118+
val queryExecution = context.executePlan(logicalPlan)
119+
val outputString = if (extended) queryExecution.toString else queryExecution.toSimpleString
120+
121+
outputString.split("\n")
118122
} catch { case cause: TreeNodeException[_] =>
119-
"Error occurred during query planning: " +: cause.getMessage.split("\n")
123+
("Error occurred during query planning: \n" + cause.getMessage).split("\n")
120124
}
121125

122126
def execute(): RDD[Row] = {

sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,9 @@ private[hive] object HiveQl {
409409
ExplainCommand(NoRelation)
410410
case Token("TOK_EXPLAIN", explainArgs) =>
411411
// Ignore FORMATTED if present.
412-
val Some(query) :: _ :: _ :: Nil =
412+
val Some(query) :: _ :: extended :: Nil =
413413
getClauses(Seq("TOK_QUERY", "FORMATTED", "EXTENDED"), explainArgs)
414-
// TODO: support EXTENDED?
415-
ExplainCommand(nodeToPlan(query))
414+
ExplainCommand(nodeToPlan(query), extended != None)
416415

417416
case Token("TOK_DESCTABLE", describeArgs) =>
418417
// Reference: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.spark.sql.hive.execution
19+
20+
import org.apache.spark.sql.QueryTest
21+
import org.apache.spark.sql.hive.test.TestHive
22+
import org.apache.spark.sql.hive.test.TestHive._
23+
import org.apache.spark.sql.Row
24+
25+
/**
26+
* A set of tests that validates support for Hive Explain command.
27+
*/
28+
class HiveExplainSuite extends QueryTest {
29+
private def check(sqlCmd: String, exists: Boolean, keywords: String*) {
30+
val outputs = sql(sqlCmd).collect().map(_.getString(0)).mkString
31+
for (key <- keywords) {
32+
if (exists) {
33+
assert(outputs.contains(key), s"Failed for $sqlCmd ($key doens't exist in result)")
34+
} else {
35+
assert(!outputs.contains(key), s"Failed for $sqlCmd ($key existed in the result)")
36+
}
37+
}
38+
}
39+
40+
test("explain extended command") {
41+
check(" explain select * from src where key=123 ", true,
42+
"== Physical Plan ==", "== RDD ==")
43+
check(" explain select * from src where key=123 ", false,
44+
"== Parsed Logical Plan ==",
45+
"== Analyzed Logical Plan ==",
46+
"== Optimized Logical Plan ==")
47+
check(" explain extended select * from src where key=123 ", true,
48+
"== Parsed Logical Plan ==",
49+
"== Analyzed Logical Plan ==",
50+
"== Optimized Logical Plan ==",
51+
"== Physical Plan ==",
52+
"Code Generation", "== RDD ==")
53+
}
54+
}

0 commit comments

Comments
 (0)