diff options
author | Herman van Hovell <hvanhovell@questtec.nl> | 2016-03-31 09:25:09 -0700 |
---|---|---|
committer | Reynold Xin <rxin@databricks.com> | 2016-03-31 09:25:09 -0700 |
commit | a9b93e07391faede77dde4c0b3c21c9b3f97f8eb (patch) | |
tree | ebcdf8cef08c6c14efadd5186097c7ceb8fc1738 /sql/core/src/main | |
parent | 26445c2e472bad137fd350e4089dd0ff43a42039 (diff) | |
download | spark-a9b93e07391faede77dde4c0b3c21c9b3f97f8eb.tar.gz spark-a9b93e07391faede77dde4c0b3c21c9b3f97f8eb.tar.bz2 spark-a9b93e07391faede77dde4c0b3c21c9b3f97f8eb.zip |
[SPARK-14211][SQL] Remove ANTLR3 based parser
### What changes were proposed in this pull request?
This PR removes the ANTLR3 based parser, and moves the new ANTLR4 based parser into the `org.apache.spark.sql.catalyst.parser package`.
### How was this patch tested?
Existing unit tests.
cc rxin andrewor14 yhuai
Author: Herman van Hovell <hvanhovell@questtec.nl>
Closes #12071 from hvanhovell/SPARK-14211.
Diffstat (limited to 'sql/core/src/main')
4 files changed, 4 insertions, 840 deletions
diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala deleted file mode 100644 index 6fe04757ba..0000000000 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/SparkQl.scala +++ /dev/null @@ -1,387 +0,0 @@ -/* - * 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 - -import org.apache.spark.sql.{AnalysisException, SaveMode} -import org.apache.spark.sql.catalyst.TableIdentifier -import org.apache.spark.sql.catalyst.parser._ -import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, OneRowRelation} -import org.apache.spark.sql.execution.command._ -import org.apache.spark.sql.execution.datasources._ -import org.apache.spark.sql.types.StructType - -private[sql] class SparkQl(conf: ParserConf = SimpleParserConf()) extends CatalystQl(conf) { - import ParserUtils._ - - /** Check if a command should not be explained. */ - protected def isNoExplainCommand(command: String): Boolean = { - "TOK_DESCTABLE" == command || "TOK_ALTERTABLE" == command - } - - /** - * For each node, extract properties in the form of a list - * ['key_part1', 'key_part2', 'key_part3', 'value'] - * into a pair (key_part1.key_part2.key_part3, value). - * - * Example format: - * - * TOK_TABLEPROPERTY - * :- 'k1' - * +- 'v1' - * TOK_TABLEPROPERTY - * :- 'k2' - * +- 'v2' - * TOK_TABLEPROPERTY - * :- 'k3' - * +- 'v3' - */ - private def extractProps( - props: Seq[ASTNode], - expectedNodeText: String): Seq[(String, String)] = { - props.map { - case Token(x, keysAndValue) if x == expectedNodeText => - val key = keysAndValue.init.map { x => unquoteString(x.text) }.mkString(".") - val value = unquoteString(keysAndValue.last.text) - (key, value) - case p => - parseFailed(s"Expected property '$expectedNodeText' in command", p) - } - } - - protected override def nodeToPlan(node: ASTNode): LogicalPlan = { - node match { - case Token("TOK_SETCONFIG", Nil) => - val keyValueSeparatorIndex = node.remainder.indexOf('=') - if (keyValueSeparatorIndex >= 0) { - val key = node.remainder.substring(0, keyValueSeparatorIndex).trim - val value = node.remainder.substring(keyValueSeparatorIndex + 1).trim - SetCommand(Some(key -> Option(value))) - } else if (node.remainder.nonEmpty) { - SetCommand(Some(node.remainder -> None)) - } else { - SetCommand(None) - } - - // Just fake explain for any of the native commands. - case Token("TOK_EXPLAIN", explainArgs) if isNoExplainCommand(explainArgs.head.text) => - ExplainCommand(OneRowRelation) - - case Token("TOK_EXPLAIN", explainArgs) if "TOK_CREATETABLE" == explainArgs.head.text => - val Some(crtTbl) :: _ :: extended :: Nil = - getClauses(Seq("TOK_CREATETABLE", "FORMATTED", "EXTENDED"), explainArgs) - ExplainCommand(nodeToPlan(crtTbl), extended = extended.isDefined) - - case Token("TOK_EXPLAIN", explainArgs) => - // Ignore FORMATTED if present. - val Some(query) :: _ :: extended :: Nil = - getClauses(Seq("TOK_QUERY", "FORMATTED", "EXTENDED"), explainArgs) - ExplainCommand(nodeToPlan(query), extended = extended.isDefined) - - case Token("TOK_REFRESHTABLE", nameParts :: Nil) => - val tableIdent = extractTableIdent(nameParts) - RefreshTable(tableIdent) - - // CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] - // [LOCATION path] [WITH DBPROPERTIES (key1=val1, key2=val2, ...)]; - case Token("TOK_CREATEDATABASE", Token(dbName, Nil) :: args) => - val databaseName = cleanIdentifier(dbName) - val Seq(ifNotExists, dbLocation, databaseComment, dbprops) = getClauses(Seq( - "TOK_IFNOTEXISTS", - "TOK_DATABASELOCATION", - "TOK_DATABASECOMMENT", - "TOK_DATABASEPROPERTIES"), args) - val location = dbLocation.map { - case Token("TOK_DATABASELOCATION", Token(loc, Nil) :: Nil) => unquoteString(loc) - case _ => parseFailed("Invalid CREATE DATABASE command", node) - } - val comment = databaseComment.map { - case Token("TOK_DATABASECOMMENT", Token(com, Nil) :: Nil) => unquoteString(com) - case _ => parseFailed("Invalid CREATE DATABASE command", node) - } - val props = dbprops.toSeq.flatMap { - case Token("TOK_DATABASEPROPERTIES", Token("TOK_DBPROPLIST", propList) :: Nil) => - // Example format: - // - // TOK_DATABASEPROPERTIES - // +- TOK_DBPROPLIST - // :- TOK_TABLEPROPERTY - // : :- 'k1' - // : +- 'v1' - // :- TOK_TABLEPROPERTY - // :- 'k2' - // +- 'v2' - extractProps(propList, "TOK_TABLEPROPERTY") - case _ => parseFailed("Invalid CREATE DATABASE command", node) - }.toMap - CreateDatabase(databaseName, ifNotExists.isDefined, location, comment, props) - - // DROP DATABASE [IF EXISTS] database_name [RESTRICT|CASCADE]; - case Token("TOK_DROPDATABASE", Token(dbName, Nil) :: otherArgs) => - // Example format: - // - // TOK_DROPDATABASE - // :- database_name - // :- TOK_IFEXISTS - // +- TOK_RESTRICT/TOK_CASCADE - val databaseName = cleanIdentifier(dbName) - // The default is RESTRICT - val Seq(ifExists, _, cascade) = getClauses(Seq( - "TOK_IFEXISTS", "TOK_RESTRICT", "TOK_CASCADE"), otherArgs) - DropDatabase(databaseName, ifExists.isDefined, cascade.isDefined) - - // ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...) - case Token("TOK_ALTERDATABASE_PROPERTIES", Token(dbName, Nil) :: args) => - val databaseName = cleanIdentifier(dbName) - val dbprops = getClause("TOK_DATABASEPROPERTIES", args) - val props = dbprops match { - case Token("TOK_DATABASEPROPERTIES", Token("TOK_DBPROPLIST", propList) :: Nil) => - // Example format: - // - // TOK_DATABASEPROPERTIES - // +- TOK_DBPROPLIST - // :- TOK_TABLEPROPERTY - // : :- 'k1' - // : +- 'v1' - // :- TOK_TABLEPROPERTY - // :- 'k2' - // +- 'v2' - extractProps(propList, "TOK_TABLEPROPERTY") - case _ => parseFailed("Invalid ALTER DATABASE command", node) - } - AlterDatabaseProperties(databaseName, props.toMap) - - // DESCRIBE DATABASE [EXTENDED] db_name - case Token("TOK_DESCDATABASE", Token(dbName, Nil) :: describeArgs) => - val databaseName = cleanIdentifier(dbName) - val extended = getClauseOption("EXTENDED", describeArgs) - DescribeDatabase(databaseName, extended.isDefined) - - // CREATE [TEMPORARY] FUNCTION [db_name.]function_name AS class_name - // [USING JAR|FILE|ARCHIVE 'file_uri' [, JAR|FILE|ARCHIVE 'file_uri'] ]; - case Token("TOK_CREATEFUNCTION", args) => - // Example format: - // - // TOK_CREATEFUNCTION - // :- db_name - // :- func_name - // :- alias - // +- TOK_RESOURCE_LIST - // :- TOK_RESOURCE_URI - // : :- TOK_JAR - // : +- '/path/to/jar' - // +- TOK_RESOURCE_URI - // :- TOK_FILE - // +- 'path/to/file' - val (funcNameArgs, otherArgs) = args.partition { - case Token("TOK_RESOURCE_LIST", _) => false - case Token("TOK_TEMPORARY", _) => false - case Token(_, Nil) => true - case _ => parseFailed("Invalid CREATE FUNCTION command", node) - } - // If database name is specified, there are 3 tokens, otherwise 2. - val (dbName, funcName, alias) = funcNameArgs match { - case Token(dbName, Nil) :: Token(fname, Nil) :: Token(aname, Nil) :: Nil => - (Some(unquoteString(dbName)), unquoteString(fname), unquoteString(aname)) - case Token(fname, Nil) :: Token(aname, Nil) :: Nil => - (None, unquoteString(fname), unquoteString(aname)) - case _ => - parseFailed("Invalid CREATE FUNCTION command", node) - } - // Extract other keywords, if they exist - val Seq(rList, temp) = getClauses(Seq("TOK_RESOURCE_LIST", "TOK_TEMPORARY"), otherArgs) - val resources: Seq[(String, String)] = rList.toSeq.flatMap { - case Token("TOK_RESOURCE_LIST", resList) => - resList.map { - case Token("TOK_RESOURCE_URI", rType :: Token(rPath, Nil) :: Nil) => - val resourceType = rType match { - case Token("TOK_JAR", Nil) => "jar" - case Token("TOK_FILE", Nil) => "file" - case Token("TOK_ARCHIVE", Nil) => "archive" - case Token(f, _) => parseFailed(s"Unexpected resource format '$f'", node) - } - (resourceType, unquoteString(rPath)) - case _ => parseFailed("Invalid CREATE FUNCTION command", node) - } - case _ => parseFailed("Invalid CREATE FUNCTION command", node) - } - CreateFunction(dbName, funcName, alias, resources, temp.isDefined)(node.source) - - // DROP [TEMPORARY] FUNCTION [IF EXISTS] function_name; - case Token("TOK_DROPFUNCTION", args) => - // Example format: - // - // TOK_DROPFUNCTION - // :- db_name - // :- func_name - // :- TOK_IFEXISTS - // +- TOK_TEMPORARY - val (funcNameArgs, otherArgs) = args.partition { - case Token("TOK_IFEXISTS", _) => false - case Token("TOK_TEMPORARY", _) => false - case Token(_, Nil) => true - case _ => parseFailed("Invalid DROP FUNCTION command", node) - } - // If database name is specified, there are 2 tokens, otherwise 1. - val (dbName, funcName) = funcNameArgs match { - case Token(dbName, Nil) :: Token(fname, Nil) :: Nil => - (Some(unquoteString(dbName)), unquoteString(fname)) - case Token(fname, Nil) :: Nil => - (None, unquoteString(fname)) - case _ => - parseFailed("Invalid DROP FUNCTION command", node) - } - - val Seq(ifExists, temp) = getClauses(Seq( - "TOK_IFEXISTS", "TOK_TEMPORARY"), otherArgs) - - DropFunction(dbName, funcName, ifExists.isDefined, temp.isDefined)(node.source) - - case Token("TOK_ALTERTABLE", alterTableArgs) => - AlterTableCommandParser.parse(node) - - case Token("TOK_CREATETABLEUSING", createTableArgs) => - val Seq( - temp, - ifNotExists, - Some(tabName), - tableCols, - Some(Token("TOK_TABLEPROVIDER", providerNameParts)), - tableOpts, - tableAs) = getClauses(Seq( - "TEMPORARY", - "TOK_IFNOTEXISTS", - "TOK_TABNAME", "TOK_TABCOLLIST", - "TOK_TABLEPROVIDER", - "TOK_TABLEOPTIONS", - "TOK_QUERY"), createTableArgs) - val tableIdent: TableIdentifier = extractTableIdent(tabName) - val columns = tableCols.map { - case Token("TOK_TABCOLLIST", fields) => StructType(fields.map(nodeToStructField)) - case _ => parseFailed("Invalid CREATE TABLE command", node) - } - val provider = providerNameParts.map { - case Token(name, Nil) => name - case _ => parseFailed("Invalid CREATE TABLE command", node) - }.mkString(".") - val options = tableOpts.toSeq.flatMap { - case Token("TOK_TABLEOPTIONS", opts) => extractProps(opts, "TOK_TABLEOPTION") - case _ => parseFailed("Invalid CREATE TABLE command", node) - }.toMap - val asClause = tableAs.map(nodeToPlan) - - if (temp.isDefined && ifNotExists.isDefined) { - throw new AnalysisException( - "a CREATE TEMPORARY TABLE statement does not allow IF NOT EXISTS clause.") - } - - if (asClause.isDefined) { - if (columns.isDefined) { - throw new AnalysisException( - "a CREATE TABLE AS SELECT statement does not allow column definitions.") - } - - val mode = if (ifNotExists.isDefined) { - SaveMode.Ignore - } else if (temp.isDefined) { - SaveMode.Overwrite - } else { - SaveMode.ErrorIfExists - } - - CreateTableUsingAsSelect(tableIdent, - provider, - temp.isDefined, - Array.empty[String], - bucketSpec = None, - mode, - options, - asClause.get) - } else { - CreateTableUsing( - tableIdent, - columns, - provider, - temp.isDefined, - options, - ifNotExists.isDefined, - managedIfNoPath = false) - } - - case Token("TOK_SWITCHDATABASE", Token(database, Nil) :: Nil) => - SetDatabaseCommand(cleanIdentifier(database)) - - case Token("TOK_DESCTABLE", describeArgs) => - // Reference: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL - val Some(tableType) :: formatted :: extended :: pretty :: Nil = - getClauses(Seq("TOK_TABTYPE", "FORMATTED", "EXTENDED", "PRETTY"), describeArgs) - if (formatted.isDefined || pretty.isDefined) { - // FORMATTED and PRETTY are not supported and this statement will be treated as - // a Hive native command. - nodeToDescribeFallback(node) - } else { - tableType match { - case Token("TOK_TABTYPE", Token("TOK_TABNAME", nameParts) :: Nil) => - nameParts match { - case Token(dbName, Nil) :: Token(tableName, Nil) :: Nil => - // It is describing a table with the format like "describe db.table". - // TODO: Actually, a user may mean tableName.columnName. Need to resolve this - // issue. - val tableIdent = TableIdentifier( - cleanIdentifier(tableName), Some(cleanIdentifier(dbName))) - datasources.DescribeCommand(tableIdent, isExtended = extended.isDefined) - case Token(dbName, Nil) :: Token(tableName, Nil) :: Token(colName, Nil) :: Nil => - // It is describing a column with the format like "describe db.table column". - nodeToDescribeFallback(node) - case tableName :: Nil => - // It is describing a table with the format like "describe table". - datasources.DescribeCommand( - TableIdentifier(cleanIdentifier(tableName.text)), - isExtended = extended.isDefined) - case _ => - nodeToDescribeFallback(node) - } - // All other cases. - case _ => - nodeToDescribeFallback(node) - } - } - - case Token("TOK_CACHETABLE", Token(tableName, Nil) :: args) => - val Seq(lzy, selectAst) = getClauses(Seq("LAZY", "TOK_QUERY"), args) - CacheTableCommand(tableName, selectAst.map(nodeToPlan), lzy.isDefined) - - case Token("TOK_UNCACHETABLE", Token(tableName, Nil) :: Nil) => - UncacheTableCommand(tableName) - - case Token("TOK_CLEARCACHE", Nil) => - ClearCacheCommand - - case Token("TOK_SHOWTABLES", args) => - val databaseName = args match { - case Nil => None - case Token("TOK_FROM", Token(dbName, Nil) :: Nil) :: Nil => Option(dbName) - case _ => noParseRule("SHOW TABLES", node) - } - ShowTablesCommand(databaseName) - - case _ => - super.nodeToPlan(node) - } - } - - protected def nodeToDescribeFallback(node: ASTNode): LogicalPlan = noParseRule("Describe", node) -} 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 8333074eca..b4687c985d 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 @@ -20,8 +20,8 @@ import scala.collection.JavaConverters._ import org.apache.spark.sql.SaveMode import org.apache.spark.sql.catalyst.TableIdentifier -import org.apache.spark.sql.catalyst.parser.ng.{AbstractSqlParser, AstBuilder, ParseException} -import org.apache.spark.sql.catalyst.parser.ng.SqlBaseParser._ +import org.apache.spark.sql.catalyst.parser.{AbstractSqlParser, AstBuilder, ParseException} +import org.apache.spark.sql.catalyst.parser.SqlBaseParser._ import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, OneRowRelation} import org.apache.spark.sql.execution.command.{DescribeCommand => _, _} import org.apache.spark.sql.execution.datasources._ @@ -37,7 +37,7 @@ object SparkSqlParser extends AbstractSqlParser{ * Builder that converts an ANTLR ParseTree into a LogicalPlan/Expression/TableIdentifier. */ class SparkSqlAstBuilder extends AstBuilder { - import org.apache.spark.sql.catalyst.parser.ng.ParserUtils._ + import org.apache.spark.sql.catalyst.parser.ParserUtils._ /** * Create a [[SetCommand]] logical plan. diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/AlterTableCommandParser.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/AlterTableCommandParser.scala deleted file mode 100644 index 9fbe6db467..0000000000 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/AlterTableCommandParser.scala +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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 scala.collection.mutable.ArrayBuffer - -import org.apache.spark.sql.catalyst.TableIdentifier -import org.apache.spark.sql.catalyst.catalog.ExternalCatalog.TablePartitionSpec -import org.apache.spark.sql.catalyst.expressions.{Ascending, Descending, SortDirection} -import org.apache.spark.sql.catalyst.parser._ -import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan -import org.apache.spark.sql.execution.datasources._ -import org.apache.spark.sql.types.StructType - - -/** - * Helper object to parse alter table commands. - */ -object AlterTableCommandParser { - import ParserUtils._ - - /** - * Parse the given node assuming it is an alter table command. - */ - def parse(node: ASTNode): LogicalPlan = { - node.children match { - case (tabName @ Token("TOK_TABNAME", _)) :: otherNodes => - val tableIdent = extractTableIdent(tabName) - val partSpec = getClauseOption("TOK_PARTSPEC", node.children).map(parsePartitionSpec) - matchAlterTableCommands(node, otherNodes, tableIdent, partSpec) - case _ => - parseFailed("Could not parse ALTER TABLE command", node) - } - } - - private def cleanAndUnquoteString(s: String): String = { - cleanIdentifier(unquoteString(s)) - } - - /** - * Extract partition spec from the given [[ASTNode]] as a map, assuming it exists. - * - * Example format: - * - * TOK_PARTSPEC - * :- TOK_PARTVAL - * : :- dt - * : +- '2008-08-08' - * +- TOK_PARTVAL - * :- country - * +- 'us' - */ - private def parsePartitionSpec(node: ASTNode): Map[String, String] = { - node match { - case Token("TOK_PARTSPEC", partitions) => - partitions.map { - // Note: sometimes there's a "=", "<" or ">" between the key and the value - // (e.g. when dropping all partitions with value > than a certain constant) - case Token("TOK_PARTVAL", ident :: conj :: constant :: Nil) => - (cleanAndUnquoteString(ident.text), cleanAndUnquoteString(constant.text)) - case Token("TOK_PARTVAL", ident :: constant :: Nil) => - (cleanAndUnquoteString(ident.text), cleanAndUnquoteString(constant.text)) - case Token("TOK_PARTVAL", ident :: Nil) => - (cleanAndUnquoteString(ident.text), null) - case _ => - parseFailed("Invalid ALTER TABLE command", node) - }.toMap - case _ => - parseFailed("Expected partition spec in ALTER TABLE command", node) - } - } - - /** - * Extract table properties from the given [[ASTNode]] as a map, assuming it exists. - * - * Example format: - * - * TOK_TABLEPROPERTIES - * +- TOK_TABLEPROPLIST - * :- TOK_TABLEPROPERTY - * : :- 'test' - * : +- 'value' - * +- TOK_TABLEPROPERTY - * :- 'comment' - * +- 'new_comment' - */ - private def extractTableProps(node: ASTNode): Map[String, String] = { - node match { - case Token("TOK_TABLEPROPERTIES", propsList) => - propsList.flatMap { - case Token("TOK_TABLEPROPLIST", props) => - props.map { case Token("TOK_TABLEPROPERTY", key :: value :: Nil) => - val k = cleanAndUnquoteString(key.text) - val v = value match { - case Token("TOK_NULL", Nil) => null - case _ => cleanAndUnquoteString(value.text) - } - (k, v) - } - case _ => - parseFailed("Invalid ALTER TABLE command", node) - }.toMap - case _ => - parseFailed("Expected table properties in ALTER TABLE command", node) - } - } - - /** - * Parse an alter table command from a [[ASTNode]] into a [[LogicalPlan]]. - * This follows https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL. - * - * @param node the original [[ASTNode]] to parse. - * @param otherNodes the other [[ASTNode]]s after the first one containing the table name. - * @param tableIdent identifier of the table, parsed from the first [[ASTNode]]. - * @param partition spec identifying the partition this command is concerned with, if any. - */ - // TODO: This method is massive. Break it down. - private def matchAlterTableCommands( - node: ASTNode, - otherNodes: Seq[ASTNode], - tableIdent: TableIdentifier, - partition: Option[TablePartitionSpec]): LogicalPlan = { - otherNodes match { - // ALTER TABLE table_name RENAME TO new_table_name; - case Token("TOK_ALTERTABLE_RENAME", renameArgs) :: _ => - val tableNameClause = getClause("TOK_TABNAME", renameArgs) - val newTableIdent = extractTableIdent(tableNameClause) - AlterTableRename(tableIdent, newTableIdent)(node.source) - - // ALTER TABLE table_name SET TBLPROPERTIES ('comment' = new_comment); - case Token("TOK_ALTERTABLE_PROPERTIES", args) :: _ => - val properties = extractTableProps(args.head) - AlterTableSetProperties(tableIdent, properties)(node.source) - - // ALTER TABLE table_name UNSET TBLPROPERTIES IF EXISTS ('comment', 'key'); - case Token("TOK_ALTERTABLE_DROPPROPERTIES", args) :: _ => - val properties = extractTableProps(args.head) - val ifExists = getClauseOption("TOK_IFEXISTS", args).isDefined - AlterTableUnsetProperties(tableIdent, properties, ifExists)(node.source) - - // ALTER TABLE table_name [PARTITION spec] SET SERDE serde_name [WITH SERDEPROPERTIES props]; - case Token("TOK_ALTERTABLE_SERIALIZER", Token(serdeClassName, Nil) :: serdeArgs) :: _ => - AlterTableSerDeProperties( - tableIdent, - Some(cleanAndUnquoteString(serdeClassName)), - serdeArgs.headOption.map(extractTableProps), - partition)(node.source) - - // ALTER TABLE table_name [PARTITION spec] SET SERDEPROPERTIES serde_properties; - case Token("TOK_ALTERTABLE_SERDEPROPERTIES", args) :: _ => - AlterTableSerDeProperties( - tableIdent, - None, - Some(extractTableProps(args.head)), - partition)(node.source) - - // ALTER TABLE table_name CLUSTERED BY (col, ...) [SORTED BY (col, ...)] INTO n BUCKETS; - case Token("TOK_ALTERTABLE_CLUSTER_SORT", Token("TOK_ALTERTABLE_BUCKETS", b) :: Nil) :: _ => - val clusterCols: Seq[String] = b.head match { - case Token("TOK_TABCOLNAME", children) => children.map(_.text) - case _ => parseFailed("Invalid ALTER TABLE command", node) - } - // If sort columns are specified, num buckets should be the third arg. - // If sort columns are not specified, num buckets should be the second arg. - // TODO: actually use `sortDirections` once we actually store that in the metastore - val (sortCols: Seq[String], sortDirections: Seq[SortDirection], numBuckets: Int) = { - b.tail match { - case Token("TOK_TABCOLNAME", children) :: numBucketsNode :: Nil => - val (cols, directions) = children.map { - case Token("TOK_TABSORTCOLNAMEASC", Token(col, Nil) :: Nil) => (col, Ascending) - case Token("TOK_TABSORTCOLNAMEDESC", Token(col, Nil) :: Nil) => (col, Descending) - }.unzip - (cols, directions, numBucketsNode.text.toInt) - case numBucketsNode :: Nil => - (Nil, Nil, numBucketsNode.text.toInt) - case _ => - parseFailed("Invalid ALTER TABLE command", node) - } - } - AlterTableStorageProperties( - tableIdent, - BucketSpec(numBuckets, clusterCols, sortCols))(node.source) - - // ALTER TABLE table_name NOT CLUSTERED - case Token("TOK_ALTERTABLE_CLUSTER_SORT", Token("TOK_NOT_CLUSTERED", Nil) :: Nil) :: _ => - AlterTableNotClustered(tableIdent)(node.source) - - // ALTER TABLE table_name NOT SORTED - case Token("TOK_ALTERTABLE_CLUSTER_SORT", Token("TOK_NOT_SORTED", Nil) :: Nil) :: _ => - AlterTableNotSorted(tableIdent)(node.source) - - // ALTER TABLE table_name SKEWED BY (col1, col2) - // ON ((col1_value, col2_value) [, (col1_value, col2_value), ...]) - // [STORED AS DIRECTORIES]; - case Token("TOK_ALTERTABLE_SKEWED", - Token("TOK_TABLESKEWED", - Token("TOK_TABCOLNAME", colNames) :: colValues :: rest) :: Nil) :: _ => - // Example format: - // - // TOK_ALTERTABLE_SKEWED - // :- TOK_TABLESKEWED - // : :- TOK_TABCOLNAME - // : : :- dt - // : : +- country - // :- TOK_TABCOLVALUE_PAIR - // : :- TOK_TABCOLVALUES - // : : :- TOK_TABCOLVALUE - // : : : :- '2008-08-08' - // : : : +- 'us' - // : :- TOK_TABCOLVALUES - // : : :- TOK_TABCOLVALUE - // : : : :- '2009-09-09' - // : : : +- 'uk' - // +- TOK_STOREASDIR - val names = colNames.map { n => cleanAndUnquoteString(n.text) } - val values = colValues match { - case Token("TOK_TABCOLVALUE", vals) => - Seq(vals.map { n => cleanAndUnquoteString(n.text) }) - case Token("TOK_TABCOLVALUE_PAIR", pairs) => - pairs.map { - case Token("TOK_TABCOLVALUES", Token("TOK_TABCOLVALUE", vals) :: Nil) => - vals.map { n => cleanAndUnquoteString(n.text) } - case _ => - parseFailed("Invalid ALTER TABLE command", node) - } - case _ => - parseFailed("Invalid ALTER TABLE command", node) - } - val storedAsDirs = rest match { - case Token("TOK_STOREDASDIRS", Nil) :: Nil => true - case _ => false - } - AlterTableSkewed( - tableIdent, - names, - values, - storedAsDirs)(node.source) - - // ALTER TABLE table_name NOT SKEWED - case Token("TOK_ALTERTABLE_SKEWED", Nil) :: _ => - AlterTableNotSkewed(tableIdent)(node.source) - - // ALTER TABLE table_name NOT STORED AS DIRECTORIES - case Token("TOK_ALTERTABLE_SKEWED", Token("TOK_STOREDASDIRS", Nil) :: Nil) :: _ => - AlterTableNotStoredAsDirs(tableIdent)(node.source) - - // ALTER TABLE table_name SET SKEWED LOCATION (col1="loc1" [, (col2, col3)="loc2", ...] ); - case Token("TOK_ALTERTABLE_SKEWED_LOCATION", - Token("TOK_SKEWED_LOCATIONS", - Token("TOK_SKEWED_LOCATION_LIST", locationMaps) :: Nil) :: Nil) :: _ => - // Example format: - // - // TOK_ALTERTABLE_SKEWED_LOCATION - // +- TOK_SKEWED_LOCATIONS - // +- TOK_SKEWED_LOCATION_LIST - // :- TOK_SKEWED_LOCATION_MAP - // : :- 'col1' - // : +- 'loc1' - // +- TOK_SKEWED_LOCATION_MAP - // :- TOK_TABCOLVALUES - // : +- TOK_TABCOLVALUE - // : :- 'col2' - // : +- 'col3' - // +- 'loc2' - val skewedMaps = locationMaps.flatMap { - case Token("TOK_SKEWED_LOCATION_MAP", col :: loc :: Nil) => - col match { - case Token(const, Nil) => - Seq((cleanAndUnquoteString(const), cleanAndUnquoteString(loc.text))) - case Token("TOK_TABCOLVALUES", Token("TOK_TABCOLVALUE", keys) :: Nil) => - keys.map { k => (cleanAndUnquoteString(k.text), cleanAndUnquoteString(loc.text)) } - } - case _ => - parseFailed("Invalid ALTER TABLE command", node) - }.toMap - AlterTableSkewedLocation(tableIdent, skewedMaps)(node.source) - - // ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION spec [LOCATION 'loc1'] - // spec [LOCATION 'loc2'] ...; - case Token("TOK_ALTERTABLE_ADDPARTS", args) :: _ => - val (ifNotExists, parts) = args.head match { - case Token("TOK_IFNOTEXISTS", Nil) => (true, args.tail) - case _ => (false, args) - } - // List of (spec, location) to describe partitions to add - // Each partition spec may or may not be followed by a location - val parsedParts = new ArrayBuffer[(TablePartitionSpec, Option[String])] - parts.foreach { - case t @ Token("TOK_PARTSPEC", _) => - parsedParts += ((parsePartitionSpec(t), None)) - case Token("TOK_PARTITIONLOCATION", loc :: Nil) => - // Update the location of the last partition we just added - if (parsedParts.nonEmpty) { - val (spec, _) = parsedParts.remove(parsedParts.length - 1) - parsedParts += ((spec, Some(unquoteString(loc.text)))) - } - case _ => - parseFailed("Invalid ALTER TABLE command", node) - } - AlterTableAddPartition(tableIdent, parsedParts, ifNotExists)(node.source) - - // ALTER TABLE table_name PARTITION spec1 RENAME TO PARTITION spec2; - case Token("TOK_ALTERTABLE_RENAMEPART", spec :: Nil) :: _ => - val newPartition = parsePartitionSpec(spec) - val oldPartition = partition.getOrElse { - parseFailed("Expected old partition spec in ALTER TABLE rename partition command", node) - } - AlterTableRenamePartition(tableIdent, oldPartition, newPartition)(node.source) - - // ALTER TABLE table_name_1 EXCHANGE PARTITION spec WITH TABLE table_name_2; - case Token("TOK_ALTERTABLE_EXCHANGEPARTITION", spec :: newTable :: Nil) :: _ => - val parsedSpec = parsePartitionSpec(spec) - val newTableIdent = extractTableIdent(newTable) - AlterTableExchangePartition(tableIdent, newTableIdent, parsedSpec)(node.source) - - // ALTER TABLE table_name DROP [IF EXISTS] PARTITION spec1[, PARTITION spec2, ...] [PURGE]; - case Token("TOK_ALTERTABLE_DROPPARTS", args) :: _ => - val parts = args.collect { case p @ Token("TOK_PARTSPEC", _) => parsePartitionSpec(p) } - val ifExists = getClauseOption("TOK_IFEXISTS", args).isDefined - val purge = getClauseOption("PURGE", args).isDefined - AlterTableDropPartition(tableIdent, parts, ifExists, purge)(node.source) - - // ALTER TABLE table_name ARCHIVE PARTITION spec; - case Token("TOK_ALTERTABLE_ARCHIVE", spec :: Nil) :: _ => - AlterTableArchivePartition(tableIdent, parsePartitionSpec(spec))(node.source) - - // ALTER TABLE table_name UNARCHIVE PARTITION spec; - case Token("TOK_ALTERTABLE_UNARCHIVE", spec :: Nil) :: _ => - AlterTableUnarchivePartition(tableIdent, parsePartitionSpec(spec))(node.source) - - // ALTER TABLE table_name [PARTITION spec] SET FILEFORMAT file_format; - case Token("TOK_ALTERTABLE_FILEFORMAT", args) :: _ => - val Seq(fileFormat, genericFormat) = - getClauses(Seq("TOK_TABLEFILEFORMAT", "TOK_FILEFORMAT_GENERIC"), args) - // Note: the AST doesn't contain information about which file format is being set here. - // E.g. we can't differentiate between INPUTFORMAT and OUTPUTFORMAT if either is set. - // Right now this just stores the values, but we should figure out how to get the keys. - val fFormat = fileFormat - .map { _.children.map { n => cleanAndUnquoteString(n.text) }} - .getOrElse(Seq()) - val gFormat = genericFormat.map { f => cleanAndUnquoteString(f.children(0).text) } - AlterTableSetFileFormat(tableIdent, partition, fFormat, gFormat)(node.source) - - // ALTER TABLE table_name [PARTITION spec] SET LOCATION "loc"; - case Token("TOK_ALTERTABLE_LOCATION", Token(loc, Nil) :: Nil) :: _ => - AlterTableSetLocation(tableIdent, partition, cleanAndUnquoteString(loc))(node.source) - - // ALTER TABLE table_name TOUCH [PARTITION spec]; - case Token("TOK_ALTERTABLE_TOUCH", args) :: _ => - // Note: the partition spec, if it exists, comes after TOUCH, so `partition` should - // always be None here. Instead, we need to parse it from the TOUCH node's children. - val part = getClauseOption("TOK_PARTSPEC", args).map(parsePartitionSpec) - AlterTableTouch(tableIdent, part)(node.source) - - // ALTER TABLE table_name [PARTITION spec] COMPACT 'compaction_type'; - case Token("TOK_ALTERTABLE_COMPACT", Token(compactType, Nil) :: Nil) :: _ => - AlterTableCompact(tableIdent, partition, cleanAndUnquoteString(compactType))(node.source) - - // ALTER TABLE table_name [PARTITION spec] CONCATENATE; - case Token("TOK_ALTERTABLE_MERGEFILES", _) :: _ => - AlterTableMerge(tableIdent, partition)(node.source) - - // ALTER TABLE table_name [PARTITION spec] CHANGE [COLUMN] col_old_name col_new_name - // column_type [COMMENT col_comment] [FIRST|AFTER column_name] [CASCADE|RESTRICT]; - case Token("TOK_ALTERTABLE_RENAMECOL", oldName :: newName :: dataType :: args) :: _ => - val afterColName: Option[String] = - getClauseOption("TOK_ALTERTABLE_CHANGECOL_AFTER_POSITION", args).map { ap => - ap.children match { - case Token(col, Nil) :: Nil => col - case _ => parseFailed("Invalid ALTER TABLE command", node) - } - } - val restrict = getClauseOption("TOK_RESTRICT", args).isDefined - val cascade = getClauseOption("TOK_CASCADE", args).isDefined - val comment = args.headOption.map { - case Token("TOK_ALTERTABLE_CHANGECOL_AFTER_POSITION", _) => null - case Token("TOK_RESTRICT", _) => null - case Token("TOK_CASCADE", _) => null - case Token(commentStr, Nil) => cleanAndUnquoteString(commentStr) - case _ => parseFailed("Invalid ALTER TABLE command", node) - } - AlterTableChangeCol( - tableIdent, - partition, - oldName.text, - newName.text, - nodeToDataType(dataType), - comment, - afterColName, - restrict, - cascade)(node.source) - - // ALTER TABLE table_name [PARTITION spec] ADD COLUMNS (name type [COMMENT comment], ...) - // [CASCADE|RESTRICT] - case Token("TOK_ALTERTABLE_ADDCOLS", args) :: _ => - val columnNodes = getClause("TOK_TABCOLLIST", args).children - val columns = StructType(columnNodes.map(nodeToStructField)) - val restrict = getClauseOption("TOK_RESTRICT", args).isDefined - val cascade = getClauseOption("TOK_CASCADE", args).isDefined - AlterTableAddCol(tableIdent, partition, columns, restrict, cascade)(node.source) - - // ALTER TABLE table_name [PARTITION spec] REPLACE COLUMNS (name type [COMMENT comment], ...) - // [CASCADE|RESTRICT] - case Token("TOK_ALTERTABLE_REPLACECOLS", args) :: _ => - val columnNodes = getClause("TOK_TABCOLLIST", args).children - val columns = StructType(columnNodes.map(nodeToStructField)) - val restrict = getClauseOption("TOK_RESTRICT", args).isDefined - val cascade = getClauseOption("TOK_CASCADE", args).isDefined - AlterTableReplaceCol(tableIdent, partition, columns, restrict, cascade)(node.source) - - case _ => - parseFailed("Unsupported ALTER TABLE command", node) - } - } - -} diff --git a/sql/core/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala b/sql/core/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala index d06e9086a3..6cc72fba48 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala @@ -26,7 +26,6 @@ import org.apache.parquet.hadoop.ParquetOutputCommitter import org.apache.spark.internal.Logging import org.apache.spark.sql.catalyst.CatalystConf -import org.apache.spark.sql.catalyst.parser.ParserConf import org.apache.spark.util.Utils //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -500,19 +499,6 @@ object SQLConf { doc = "When true, we could use `datasource`.`path` as table in SQL query." ) - val PARSER_SUPPORT_QUOTEDID = booleanConf("spark.sql.parser.supportQuotedIdentifiers", - defaultValue = Some(true), - isPublic = false, - doc = "Whether to use quoted identifier.\n false: default(past) behavior. Implies only" + - "alphaNumeric and underscore are valid characters in identifiers.\n" + - " true: implies column names can contain any character.") - - val PARSER_SUPPORT_SQL11_RESERVED_KEYWORDS = booleanConf( - "spark.sql.parser.supportSQL11ReservedKeywords", - defaultValue = Some(false), - isPublic = false, - doc = "This flag should be set to true to enable support for SQL2011 reserved keywords.") - val WHOLESTAGE_CODEGEN_ENABLED = booleanConf("spark.sql.codegen.wholeStage", defaultValue = Some(true), doc = "When true, the whole stage (of multiple operators) will be compiled into single java" + @@ -573,7 +559,7 @@ object SQLConf { * * SQLConf is thread-safe (internally synchronized, so safe to be used in multiple threads). */ -class SQLConf extends Serializable with CatalystConf with ParserConf with Logging { +class SQLConf extends Serializable with CatalystConf with Logging { import SQLConf._ /** Only low degree of contention is expected for conf, thus NOT using ConcurrentHashMap. */ @@ -674,10 +660,6 @@ class SQLConf extends Serializable with CatalystConf with ParserConf with Loggin def runSQLOnFile: Boolean = getConf(RUN_SQL_ON_FILES) - def supportQuotedId: Boolean = getConf(PARSER_SUPPORT_QUOTEDID) - - def supportSQL11ReservedKeywords: Boolean = getConf(PARSER_SUPPORT_SQL11_RESERVED_KEYWORDS) - override def orderByOrdinal: Boolean = getConf(ORDER_BY_ORDINAL) override def groupByOrdinal: Boolean = getConf(GROUP_BY_ORDINAL) |