-
Notifications
You must be signed in to change notification settings - Fork 28.1k
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-12576][SQL] Enable expression parsing in CatalystQl #10649
Changes from 4 commits
c15ae29
cd7f8ec
682df13
7f37d81
c2b35b7
b070bf9
bc0e298
3111ffb
beb5ca0
81588d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,43 +41,45 @@ private[sql] class CatalystQl(val conf: ParserConf = SimpleParserConf()) { | |
} | ||
} | ||
|
||
|
||
/** | ||
* Returns the AST for the given SQL string. | ||
*/ | ||
protected def getAst(sql: String): ASTNode = ParseDriver.parse(sql, conf) | ||
|
||
/** Creates LogicalPlan for a given HiveQL string. */ | ||
def createPlan(sql: String): LogicalPlan = { | ||
protected def safeParse[T](sql: String, ast: ASTNode, toResult: ASTNode => T): T = { | ||
try { | ||
createPlan(sql, ParseDriver.parse(sql, conf)) | ||
toResult(ast) | ||
} catch { | ||
case e: MatchError => throw e | ||
case e: AnalysisException => throw e | ||
case e: Exception => | ||
throw new AnalysisException(e.getMessage) | ||
case e: NotImplementedError => | ||
throw new AnalysisException( | ||
s""" | ||
|Unsupported language features in query: $sql | ||
|${getAst(sql).treeString} | ||
s"""== Unsupported language features in query == | ||
|== SQL == | ||
|$sql | ||
|== AST == | ||
|${ast.treeString} | ||
|== Error == | ||
|$e | ||
|== Stacktrace == | ||
|${e.getStackTrace.head} | ||
""".stripMargin) | ||
} | ||
} | ||
|
||
protected def createPlan(sql: String, tree: ASTNode): LogicalPlan = nodeToPlan(tree) | ||
|
||
def parseDdl(ddl: String): Seq[Attribute] = { | ||
val tree = getAst(ddl) | ||
assert(tree.text == "TOK_CREATETABLE", "Only CREATE TABLE supported.") | ||
val tableOps = tree.children | ||
val colList = tableOps | ||
.find(_.text == "TOK_TABCOLLIST") | ||
.getOrElse(sys.error("No columnList!")) | ||
|
||
colList.children.map(nodeToAttribute) | ||
/** Creates LogicalPlan for a given SQL string. */ | ||
def createPlan(sql: String): LogicalPlan = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, I like the old name "parseXXX" better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but no big deal. |
||
safeParse(sql, ParseDriver.parsePlan(sql, conf), nodeToPlan) | ||
|
||
/** Creates Expression for a given SQL string. */ | ||
def createExpression(sql: String): Expression = | ||
safeParse(sql, ParseDriver.parseExpression(sql, conf), nodeToExpr) | ||
|
||
def createDdl(sql: String): Seq[Attribute] = { | ||
safeParse(sql, ParseDriver.parseExpression(sql, conf), ast => { | ||
val Token("TOK_CREATETABLE", children) = ast | ||
children | ||
.find(_.text == "TOK_TABCOLLIST") | ||
.getOrElse(sys.error("No columnList!")) | ||
.flatMap(_.children.map(nodeToAttribute)) | ||
}) | ||
} | ||
|
||
protected def getClauses( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,7 +28,15 @@ import org.apache.spark.sql.AnalysisException | |
* This is based on Hive's org.apache.hadoop.hive.ql.parse.ParseDriver | ||
*/ | ||
object ParseDriver extends Logging { | ||
def parse(command: String, conf: ParserConf): ASTNode = { | ||
def parsePlan(command: String, conf: ParserConf): ASTNode = parse(command, conf) { parser => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add some function doc for these 3 functions, and also cover what the differences are? |
||
parser.statement().getTree | ||
} | ||
|
||
def parseExpression(command: String, conf: ParserConf): ASTNode = parse(command, conf) { parser => | ||
parser.expression().getTree | ||
} | ||
|
||
def parse(command: String, conf: ParserConf)(toTree: SparkSqlParser => CommonTree): ASTNode = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be private? |
||
logInfo(s"Parsing command: $command") | ||
|
||
// Setup error collection. | ||
|
@@ -44,7 +52,7 @@ object ParseDriver extends Logging { | |
parser.configure(conf, reporter) | ||
|
||
try { | ||
val result = parser.statement() | ||
val result = toTree(parser) | ||
|
||
// Check errors. | ||
reporter.checkForErrors() | ||
|
@@ -57,7 +65,7 @@ object ParseDriver extends Logging { | |
if (tree.token != null || tree.getChildCount == 0) tree | ||
else nonNullToken(tree.getChild(0).asInstanceOf[CommonTree]) | ||
} | ||
val tree = nonNullToken(result.getTree) | ||
val tree = nonNullToken(result) | ||
|
||
// Make sure all boundaries are set. | ||
tree.setUnknownTokenBoundaries() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use multi parameter list?
then you can call it in a slightly nicer way