Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SPARK-14349] [SQL] Issue Error Messages for Unsupported Operators/DML/DDL in SQL Context. #12134

Closed
wants to merge 64 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
01e4cdf
Merge remote-tracking branch 'upstream/master'
gatorsmile Nov 13, 2015
6835704
Merge remote-tracking branch 'upstream/master'
gatorsmile Nov 14, 2015
9180687
Merge remote-tracking branch 'upstream/master'
gatorsmile Nov 14, 2015
b38a21e
SPARK-11633
gatorsmile Nov 17, 2015
d2b84af
Merge remote-tracking branch 'upstream/master' into joinMakeCopy
gatorsmile Nov 17, 2015
fda8025
Merge remote-tracking branch 'upstream/master'
gatorspark Nov 17, 2015
ac0dccd
Merge branch 'master' of https://github.com/gatorsmile/spark
gatorspark Nov 17, 2015
6e0018b
Merge remote-tracking branch 'upstream/master'
Nov 20, 2015
0546772
converge
gatorsmile Nov 20, 2015
b37a64f
converge
gatorsmile Nov 20, 2015
c2a872c
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 6, 2016
ab6dbd7
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 6, 2016
4276356
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 6, 2016
2dab708
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 7, 2016
0458770
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 8, 2016
1debdfa
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 9, 2016
763706d
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 14, 2016
4de6ec1
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 18, 2016
9422a4f
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 19, 2016
52bdf48
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 20, 2016
1e95df3
Merge remote-tracking branch 'upstream/master'
gatorsmile Jan 23, 2016
fab24cf
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 1, 2016
8b2e33b
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 5, 2016
2ee1876
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 11, 2016
b9f0090
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 12, 2016
ade6f7e
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 15, 2016
9fd63d2
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 19, 2016
5199d49
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 22, 2016
404214c
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 23, 2016
c001dd9
Merge remote-tracking branch 'upstream/master'
gatorsmile Feb 25, 2016
59daa48
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 5, 2016
41d5f64
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 7, 2016
472a6e3
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 10, 2016
0fba10a
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 12, 2016
cbf73b3
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 21, 2016
c08f561
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 22, 2016
474df88
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 22, 2016
3d9828d
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 24, 2016
72d2361
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 26, 2016
07afea5
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 29, 2016
8bf2007
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 30, 2016
87a165b
Merge remote-tracking branch 'upstream/master'
gatorsmile Mar 31, 2016
b9359cd
Merge remote-tracking branch 'upstream/master'
gatorsmile Apr 1, 2016
e09ac7c
unsupported operations in SQL Context.
gatorsmile Apr 2, 2016
62c814d
style fix.
gatorsmile Apr 3, 2016
4178291
alter view + create view
gatorsmile Apr 3, 2016
5807347
create table
gatorsmile Apr 3, 2016
3a2f06e
style fix.
gatorsmile Apr 3, 2016
f3d886f
Issue Error Messages for Unsupported Operators
hvanhovell Apr 3, 2016
51a9b69
merge Herman's fix and revert the changes back
gatorsmile Apr 3, 2016
8c5f1e3
Merge remote-tracking branch 'origin/pr/1' into hiveParserCommand
gatorsmile Apr 3, 2016
4f88e22
Merge remote-tracking branch 'upstream/master' into hiveParserCommand
gatorsmile Apr 3, 2016
6b1c9fb
storage file format
gatorsmile Apr 3, 2016
237b73b
syntax fix.
gatorsmile Apr 3, 2016
0b786c0
address comments
gatorsmile Apr 3, 2016
c7c9461
address comments.
gatorsmile Apr 4, 2016
e69a7e8
address comments.
gatorsmile Apr 4, 2016
e4f06f9
revert it back.
gatorsmile Apr 4, 2016
07264c0
revert it back.
gatorsmile Apr 4, 2016
c618a78
revert it back.
gatorsmile Apr 4, 2016
4486c75
move test cases.
gatorsmile Apr 4, 2016
249febf
address comments.
gatorsmile Apr 5, 2016
65bd090
Merge remote-tracking branch 'upstream/master'
gatorsmile Apr 5, 2016
8a7fcf6
Merge branch 'hiveParserCommand' into hiveParserCommandNew
gatorsmile Apr 5, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,15 @@ booleanExpression
// https://github.com/antlr/antlr4/issues/780
// https://github.com/antlr/antlr4/issues/781
predicated
: valueExpression predicate[$valueExpression.ctx]?
: valueExpression predicate?
;

predicate[ParserRuleContext value]
: NOT? BETWEEN lower=valueExpression AND upper=valueExpression #between
| NOT? IN '(' expression (',' expression)* ')' #inList
| NOT? IN '(' query ')' #inSubquery
| NOT? like=(RLIKE | LIKE) pattern=valueExpression #like
| IS NOT? NULL #nullPredicate
predicate
: NOT? kind=BETWEEN lower=valueExpression AND upper=valueExpression
| NOT? kind=IN '(' expression (',' expression)* ')'
| NOT? kind=IN '(' query ')'
| NOT? kind=(RLIKE | LIKE) pattern=valueExpression
| IS NOT? kind=NULL
;

valueExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import scala.collection.JavaConverters._
import scala.collection.mutable.ArrayBuffer

import org.antlr.v4.runtime.{ParserRuleContext, Token}
import org.antlr.v4.runtime.tree.{ParseTree, TerminalNode}
import org.antlr.v4.runtime.tree.{ParseTree, RuleNode, TerminalNode}

import org.apache.spark.internal.Logging
import org.apache.spark.sql.catalyst.{InternalRow, TableIdentifier}
Expand All @@ -46,6 +46,19 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with Logging {
ctx.accept(this).asInstanceOf[T]
}

/**
* Override the default behavior for all visit methods. This will only return a non-null result
* when the context has only one child. This is done because there is no generic method to
* combine the results of the context children. In all other cases null is returned.
*/
override def visitChildren(node: RuleNode): AnyRef = {
if (node.getChildCount == 1) {
node.getChild(0).accept(this)
} else {
null
}
}

override def visitSingleStatement(ctx: SingleStatementContext): LogicalPlan = withOrigin(ctx) {
visit(ctx.statement).asInstanceOf[LogicalPlan]
}
Expand Down Expand Up @@ -351,7 +364,8 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with Logging {
string(script),
attributes,
withFilter,
withScriptIOSchema(inRowFormat, recordWriter, outRowFormat, recordReader, schemaLess))
withScriptIOSchema(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: one line (i.e. revert this).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! After we adding ctx, it has 102 characters. Thus, have to split it into two lines.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, my bad :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

: )

ctx, inRowFormat, recordWriter, outRowFormat, recordReader, schemaLess))

case SqlBaseParser.SELECT =>
// Regular select
Expand Down Expand Up @@ -398,11 +412,14 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with Logging {
* Create a (Hive based) [[ScriptInputOutputSchema]].
*/
protected def withScriptIOSchema(
ctx: QuerySpecificationContext,
inRowFormat: RowFormatContext,
recordWriter: Token,
outRowFormat: RowFormatContext,
recordReader: Token,
schemaLess: Boolean): ScriptInputOutputSchema = null
schemaLess: Boolean): ScriptInputOutputSchema = {
throw new ParseException("Script Transform is not supported", ctx)
}

/**
* Create a logical plan for a given 'FROM' clause. Note that we support multiple (comma
Expand Down Expand Up @@ -778,17 +795,6 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with Logging {
trees.asScala.map(expression)
}

/**
* Invert a boolean expression if it has a valid NOT clause.
*/
private def invertIfNotDefined(expression: Expression, not: TerminalNode): Expression = {
if (not != null) {
Not(expression)
} else {
expression
}
}

/**
* Create a star (i.e. all) expression; this selects all elements (in the specified object).
* Both un-targeted (global) and targeted aliases are supported.
Expand Down Expand Up @@ -909,57 +915,55 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with Logging {
}

/**
* Create a BETWEEN expression. This tests if an expression lies with in the bounds set by two
* other expressions. The inverse can also be created.
*/
override def visitBetween(ctx: BetweenContext): Expression = withOrigin(ctx) {
val value = expression(ctx.value)
val between = And(
GreaterThanOrEqual(value, expression(ctx.lower)),
LessThanOrEqual(value, expression(ctx.upper)))
invertIfNotDefined(between, ctx.NOT)
}

/**
* Create an IN expression. This tests if the value of the left hand side expression is
* contained by the sequence of expressions on the right hand side.
* Create a predicated expression. A predicated expression is a normal expression with a
* predicate attached to it, for example:
* {{{
* a + 1 IS NULL
* }}}
*/
override def visitInList(ctx: InListContext): Expression = withOrigin(ctx) {
val in = In(expression(ctx.value), ctx.expression().asScala.map(expression))
invertIfNotDefined(in, ctx.NOT)
override def visitPredicated(ctx: PredicatedContext): Expression = withOrigin(ctx) {
val e = expression(ctx.valueExpression)
if (ctx.predicate != null) {
withPredicate(e, ctx.predicate)
} else {
e
}
}

/**
* Create an IN expression, where the the right hand side is a query. This is unsupported.
* Add a predicate to the given expression. Supported expressions are:
* - (NOT) BETWEEN
* - (NOT) IN
* - (NOT) LIKE
* - (NOT) RLIKE
* - IS (NOT) NULL.
*/
override def visitInSubquery(ctx: InSubqueryContext): Expression = {
throw new ParseException("IN with a Sub-query is currently not supported.", ctx)
}
private def withPredicate(e: Expression, ctx: PredicateContext): Expression = withOrigin(ctx) {
// Invert a predicate if it has a valid NOT clause.
def invertIfNotDefined(e: Expression): Expression = ctx.NOT match {
case null => e
case not => Not(e)
}

/**
* Create a (R)LIKE/REGEXP expression.
*/
override def visitLike(ctx: LikeContext): Expression = {
val left = expression(ctx.value)
val right = expression(ctx.pattern)
val like = ctx.like.getType match {
// Create the predicate.
ctx.kind.getType match {
case SqlBaseParser.BETWEEN =>
// BETWEEN is translated to lower <= e && e <= upper
invertIfNotDefined(And(
GreaterThanOrEqual(e, expression(ctx.lower)),
LessThanOrEqual(e, expression(ctx.upper))))
case SqlBaseParser.IN if ctx.query != null =>
throw new ParseException("IN with a Sub-query is currently not supported.", ctx)
case SqlBaseParser.IN =>
invertIfNotDefined(In(e, ctx.expression.asScala.map(expression)))
case SqlBaseParser.LIKE =>
Like(left, right)
invertIfNotDefined(Like(e, expression(ctx.pattern)))
case SqlBaseParser.RLIKE =>
RLike(left, right)
}
invertIfNotDefined(like, ctx.NOT)
}

/**
* Create an IS (NOT) NULL expression.
*/
override def visitNullPredicate(ctx: NullPredicateContext): Expression = withOrigin(ctx) {
val value = expression(ctx.value)
if (ctx.NOT != null) {
IsNotNull(value)
} else {
IsNull(value)
invertIfNotDefined(RLike(e, expression(ctx.pattern)))
case SqlBaseParser.NULL if ctx.NOT != null =>
IsNotNull(e)
case SqlBaseParser.NULL =>
IsNull(e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,6 @@ class PlanParserSuite extends PlanTest {
table("a").union(table("b")).as("c").select(star()))
}

test("transform query spec") {
val p = ScriptTransformation(Seq('a, 'b), "func", Seq.empty, table("e"), null)
assertEqual("select transform(a, b) using 'func' from e where f < 10",
p.copy(child = p.child.where('f < 10), output = Seq('key.string, 'value.string)))
assertEqual("map a, b using 'func' as c, d from e",
p.copy(output = Seq('c.string, 'd.string)))
assertEqual("reduce a, b using 'func' as (c: int, d decimal(10, 0)) from e",
p.copy(output = Seq('c.int, 'd.decimal(10, 0))))
}

test("multi select query") {
assertEqual(
"from a select * select * where s < 10",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.spark.sql.execution.command

import org.apache.spark.sql.catalyst.TableIdentifier
import org.apache.spark.sql.catalyst.parser.ParseException
import org.apache.spark.sql.catalyst.plans.PlanTest
import org.apache.spark.sql.execution.SparkSqlParser
import org.apache.spark.sql.execution.datasources.BucketSpec
Expand Down Expand Up @@ -781,4 +782,26 @@ class DDLCommandSuite extends PlanTest {
comparePlans(parsed1, expected1)
comparePlans(parsed2, expected2)
}

test("commands only available in HiveContext") {
intercept[ParseException] {
parser.parsePlan("DROP TABLE D1.T1")
}
intercept[ParseException] {
parser.parsePlan("CREATE VIEW testView AS SELECT id FROM tab")
}
intercept[ParseException] {
parser.parsePlan("ALTER VIEW testView AS SELECT id FROM tab")
}
intercept[ParseException] {
parser.parsePlan(
"""
|CREATE EXTERNAL TABLE parquet_tab2(c1 INT, c2 STRING)
|TBLPROPERTIES('prop1Key '= "prop1Val", ' `prop2Key` '= "prop2Val")
""".stripMargin)
}
intercept[ParseException] {
parser.parsePlan("SELECT TRANSFORM (key, value) USING 'cat' AS (tKey, tValue) FROM testData")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ class HiveSqlAstBuilder extends SparkSqlAstBuilder {
}
}

/**
* Create a [[CatalogStorageFormat]]. This is part of the [[CreateTableAsSelect]] command.
*/
override def visitCreateFileFormat(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some doc to this.

Do you know which Hive test fails on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm I found the test which fail.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Multiple test cases failed. For example,
test("SPARK-8811: compatibility with array of struct in Hive") in parquetSuites.scala

ctx: CreateFileFormatContext): CatalogStorageFormat = withOrigin(ctx) {
if (ctx.storageHandler == null) {
typedVisit[CatalogStorageFormat](ctx.fileFormat)
} else {
visitStorageHandler(ctx.storageHandler)
}
}

/**
* Create a [[CreateTableAsSelect]] command.
*/
Expand Down Expand Up @@ -282,6 +294,7 @@ class HiveSqlAstBuilder extends SparkSqlAstBuilder {
* Create a [[HiveScriptIOSchema]].
*/
override protected def withScriptIOSchema(
ctx: QuerySpecificationContext,
inRowFormat: RowFormatContext,
recordWriter: Token,
outRowFormat: RowFormatContext,
Expand Down Expand Up @@ -391,7 +404,8 @@ class HiveSqlAstBuilder extends SparkSqlAstBuilder {
/**
* Storage Handlers are currently not supported in the statements we support (CTAS).
*/
override def visitStorageHandler(ctx: StorageHandlerContext): AnyRef = withOrigin(ctx) {
override def visitStorageHandler(
ctx: StorageHandlerContext): CatalogStorageFormat = withOrigin(ctx) {
throw new ParseException("Storage Handlers are currently unsupported.", ctx)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@
package org.apache.spark.sql.hive

import org.apache.hadoop.hive.serde.serdeConstants
import org.scalatest.BeforeAndAfterAll

import org.apache.spark.SparkFunSuite
import org.apache.spark.sql.AnalysisException
import org.apache.spark.sql.catalyst.analysis.UnresolvedAttribute
import org.apache.spark.sql.catalyst.catalog.{CatalogColumn, CatalogTable, CatalogTableType}
import org.apache.spark.sql.catalyst.dsl.expressions._
import org.apache.spark.sql.catalyst.dsl.plans
import org.apache.spark.sql.catalyst.dsl.plans.DslLogicalPlan
import org.apache.spark.sql.catalyst.expressions.JsonTuple
import org.apache.spark.sql.catalyst.plans.logical.Generate
import org.apache.spark.sql.catalyst.plans.PlanTest
import org.apache.spark.sql.catalyst.plans.logical.{Generate, ScriptTransformation}
import org.apache.spark.sql.hive.execution.HiveSqlParser

class HiveQlSuite extends SparkFunSuite with BeforeAndAfterAll {
class HiveQlSuite extends PlanTest {
val parser = HiveSqlParser

private def extractTableDesc(sql: String): (CatalogTable, Boolean) = {
Expand Down Expand Up @@ -201,6 +204,26 @@ class HiveQlSuite extends SparkFunSuite with BeforeAndAfterAll {
assert(plan.children.head.asInstanceOf[Generate].generator.isInstanceOf[JsonTuple])
}

test("transform query spec") {
val plan1 = parser.parsePlan("select transform(a, b) using 'func' from e where f < 10")
.asInstanceOf[ScriptTransformation].copy(ioschema = null)
val plan2 = parser.parsePlan("map a, b using 'func' as c, d from e")
.asInstanceOf[ScriptTransformation].copy(ioschema = null)
val plan3 = parser.parsePlan("reduce a, b using 'func' as (c: int, d decimal(10, 0)) from e")
.asInstanceOf[ScriptTransformation].copy(ioschema = null)

val p = ScriptTransformation(
Seq(UnresolvedAttribute("a"), UnresolvedAttribute("b")),
"func", Seq.empty, plans.table("e"), null)

comparePlans(plan1,
p.copy(child = p.child.where('f < 10), output = Seq('key.string, 'value.string)))
comparePlans(plan2,
p.copy(output = Seq('c.string, 'd.string)))
comparePlans(plan3,
p.copy(output = Seq('c.int, 'd.decimal(10, 0))))
}

test("use backticks in output of Script Transform") {
val plan = parser.parsePlan(
"""SELECT `t`.`thing1`
Expand Down