| <#-- |
| // 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. |
| --> |
| |
| /** |
| * Parses a "IF EXISTS" option, default is false. |
| */ |
| boolean IfExistsOpt() : |
| { |
| } |
| { |
| ( |
| LOOKAHEAD(2) |
| <IF> <EXISTS> { return true; } |
| | |
| { return false; } |
| ) |
| } |
| |
| /** |
| * Parses a "IF NOT EXISTS" option, default is false. |
| */ |
| boolean IfNotExistsOpt() : |
| { |
| } |
| { |
| ( |
| LOOKAHEAD(3) |
| <IF> <NOT> <EXISTS> { return true; } |
| | |
| { return false; } |
| ) |
| } |
| |
| /** |
| * Parse a "Show Catalogs" metadata query command. |
| */ |
| SqlShowCatalogs SqlShowCatalogs() : |
| { |
| } |
| { |
| <SHOW> <CATALOGS> |
| { |
| return new SqlShowCatalogs(getPos()); |
| } |
| } |
| |
| SqlCall SqlShowCurrentCatalogOrDatabase() : |
| { |
| } |
| { |
| <SHOW> <CURRENT> ( <CATALOG> |
| { |
| return new SqlShowCurrentCatalog(getPos()); |
| } |
| | <DATABASE> |
| { |
| return new SqlShowCurrentDatabase(getPos()); |
| } |
| ) |
| } |
| |
| /** |
| * Parse a "DESCRIBE CATALOG" metadata query command. |
| * { DESCRIBE | DESC } CATALOG [EXTENDED] catalog_name; |
| */ |
| SqlDescribeCatalog SqlDescribeCatalog() : |
| { |
| SqlIdentifier catalogName; |
| SqlParserPos pos; |
| boolean isExtended = false; |
| } |
| { |
| ( <DESCRIBE> | <DESC> ) <CATALOG> { pos = getPos();} |
| [ <EXTENDED> { isExtended = true;} ] |
| catalogName = SimpleIdentifier() |
| { |
| return new SqlDescribeCatalog(pos, catalogName, isExtended); |
| } |
| |
| } |
| |
| SqlUseCatalog SqlUseCatalog() : |
| { |
| SqlIdentifier catalogName; |
| SqlParserPos pos; |
| } |
| { |
| <USE> <CATALOG> { pos = getPos();} |
| catalogName = SimpleIdentifier() |
| { |
| return new SqlUseCatalog(pos, catalogName); |
| } |
| } |
| |
| /** |
| * Parses a create catalog statement. |
| * CREATE CATALOG catalog_name [WITH (property_name=property_value, ...)]; |
| */ |
| SqlCreate SqlCreateCatalog(Span s, boolean replace) : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier catalogName; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| } |
| { |
| <CATALOG> { startPos = getPos(); } |
| catalogName = SimpleIdentifier() |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| { |
| return new SqlCreateCatalog(startPos.plus(getPos()), |
| catalogName, |
| propertyList); |
| } |
| } |
| |
| SqlDrop SqlDropCatalog(Span s, boolean replace) : |
| { |
| SqlIdentifier catalogName = null; |
| boolean ifExists = false; |
| } |
| { |
| <CATALOG> |
| |
| ifExists = IfExistsOpt() |
| |
| catalogName = CompoundIdentifier() |
| |
| { |
| return new SqlDropCatalog(s.pos(), catalogName, ifExists); |
| } |
| } |
| |
| /** |
| * Parses an alter catalog statement. |
| * ALTER CATALOG catalog_name SET (key1=val1, key2=val2, ...); |
| */ |
| SqlAlterCatalog SqlAlterCatalog() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier catalogName; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| } |
| { |
| <ALTER> <CATALOG> { startPos = getPos(); } |
| catalogName = SimpleIdentifier() |
| ( |
| <SET> |
| propertyList = Properties() |
| { |
| return new SqlAlterCatalogOptions(startPos.plus(getPos()), |
| catalogName, |
| propertyList); |
| } |
| | |
| <RESET> |
| propertyList = PropertyKeys() |
| { |
| return new SqlAlterCatalogReset(startPos.plus(getPos()), |
| catalogName, |
| propertyList); |
| } |
| ) |
| } |
| |
| /** |
| * Parse a "Show DATABASES" metadata query command. |
| */ |
| SqlShowDatabases SqlShowDatabases() : |
| { |
| SqlParserPos pos; |
| String prep = null; |
| SqlIdentifier catalogName = null; |
| String likeType = null; |
| SqlCharStringLiteral likeLiteral = null; |
| boolean notLike = false; |
| } |
| { |
| <SHOW> |
| { |
| pos = getPos(); |
| } |
| <DATABASES> |
| [ |
| ( <FROM> { prep = "FROM"; } | <IN> { prep = "IN"; } ) |
| { pos = getPos(); } |
| catalogName = CompoundIdentifier() |
| ] |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| ( |
| <LIKE> |
| { |
| likeType = "LIKE"; |
| } |
| | |
| <ILIKE> |
| { |
| likeType = "ILIKE"; |
| } |
| ) |
| <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowDatabases(pos, prep, catalogName, likeType, likeLiteral, notLike); |
| } |
| } |
| |
| SqlUseDatabase SqlUseDatabase() : |
| { |
| SqlIdentifier databaseName; |
| SqlParserPos pos; |
| } |
| { |
| <USE> { pos = getPos();} |
| databaseName = CompoundIdentifier() |
| { |
| return new SqlUseDatabase(pos, databaseName); |
| } |
| } |
| |
| /** |
| * Parses a create database statement. |
| * <pre>CREATE DATABASE database_name |
| * [COMMENT database_comment] |
| * [WITH (property_name=property_value, ...)].</pre> |
| */ |
| SqlCreate SqlCreateDatabase(Span s, boolean replace) : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier databaseName; |
| SqlCharStringLiteral comment = null; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| boolean ifNotExists = false; |
| } |
| { |
| <DATABASE> { startPos = getPos(); } |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| databaseName = CompoundIdentifier() |
| [ <COMMENT> <QUOTED_STRING> |
| { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| } |
| ] |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| |
| { return new SqlCreateDatabase(startPos.plus(getPos()), |
| databaseName, |
| propertyList, |
| comment, |
| ifNotExists); } |
| |
| } |
| |
| SqlAlterDatabase SqlAlterDatabase() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier databaseName; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| } |
| { |
| <ALTER> <DATABASE> { startPos = getPos(); } |
| databaseName = CompoundIdentifier() |
| <SET> |
| propertyList = Properties() |
| { |
| return new SqlAlterDatabase(startPos.plus(getPos()), |
| databaseName, |
| propertyList); |
| } |
| } |
| |
| SqlDrop SqlDropDatabase(Span s, boolean replace) : |
| { |
| SqlIdentifier databaseName = null; |
| boolean ifExists = false; |
| boolean cascade = false; |
| } |
| { |
| <DATABASE> |
| |
| ifExists = IfExistsOpt() |
| |
| databaseName = CompoundIdentifier() |
| [ |
| <RESTRICT> { cascade = false; } |
| | |
| <CASCADE> { cascade = true; } |
| ] |
| |
| { |
| return new SqlDropDatabase(s.pos(), databaseName, ifExists, cascade); |
| } |
| } |
| |
| SqlDescribeDatabase SqlDescribeDatabase() : |
| { |
| SqlIdentifier databaseName; |
| SqlParserPos pos; |
| boolean isExtended = false; |
| } |
| { |
| ( <DESCRIBE> | <DESC> ) <DATABASE> { pos = getPos();} |
| [ <EXTENDED> { isExtended = true;} ] |
| databaseName = CompoundIdentifier() |
| { |
| return new SqlDescribeDatabase(pos, databaseName, isExtended); |
| } |
| |
| } |
| |
| SqlCreate SqlCreateFunction(Span s, boolean replace, boolean isTemporary) : |
| { |
| SqlIdentifier functionIdentifier = null; |
| SqlCharStringLiteral functionClassName = null; |
| String functionLanguage = null; |
| boolean ifNotExists = false; |
| boolean isSystemFunction = false; |
| SqlNodeList resourceInfos = SqlNodeList.EMPTY; |
| SqlParserPos functionLanguagePos = null; |
| } |
| { |
| ( |
| <SYSTEM> |
| { |
| if (!isTemporary){ |
| throw SqlUtil.newContextException(getPos(), |
| ParserResource.RESOURCE.createSystemFunctionOnlySupportTemporary()); |
| } |
| } |
| <FUNCTION> |
| ifNotExists = IfNotExistsOpt() |
| functionIdentifier = SimpleIdentifier() |
| { isSystemFunction = true; } |
| | |
| <FUNCTION> |
| ifNotExists = IfNotExistsOpt() |
| functionIdentifier = CompoundIdentifier() |
| ) |
| |
| <AS> <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| functionClassName = SqlLiteral.createCharString(p, getPos()); |
| } |
| [ |
| <LANGUAGE> |
| ( |
| <JAVA> { |
| functionLanguage = "JAVA"; |
| functionLanguagePos = getPos(); |
| } |
| | |
| <SCALA> { |
| functionLanguage = "SCALA"; |
| functionLanguagePos = getPos(); |
| } |
| | |
| <SQL> { |
| functionLanguage = "SQL"; |
| functionLanguagePos = getPos(); |
| } |
| | |
| <PYTHON> { |
| functionLanguage = "PYTHON"; |
| functionLanguagePos = getPos(); |
| } |
| ) |
| ] |
| [ |
| <USING> { |
| if ("SQL".equals(functionLanguage) || "PYTHON".equals(functionLanguage)) { |
| throw SqlUtil.newContextException( |
| functionLanguagePos, |
| ParserResource.RESOURCE.createFunctionUsingJar(functionLanguage)); |
| } |
| List<SqlNode> resourceList = new ArrayList<SqlNode>(); |
| SqlResource sqlResource = null; |
| } |
| sqlResource = SqlResourceInfo() { |
| resourceList.add(sqlResource); |
| } |
| ( |
| <COMMA> |
| sqlResource = SqlResourceInfo() { |
| resourceList.add(sqlResource); |
| } |
| )* |
| { resourceInfos = new SqlNodeList(resourceList, s.pos()); } |
| ] |
| { |
| return new SqlCreateFunction( |
| s.pos(), |
| functionIdentifier, |
| functionClassName, |
| functionLanguage, |
| ifNotExists, |
| isTemporary, |
| isSystemFunction, |
| resourceInfos); |
| } |
| } |
| |
| /** |
| * Parse resource type and path. |
| */ |
| SqlResource SqlResourceInfo() : |
| { |
| String resourcePath; |
| } |
| { |
| <JAR> <QUOTED_STRING> { |
| resourcePath = SqlParserUtil.parseString(token.image); |
| return new SqlResource( |
| getPos(), |
| SqlResourceType.JAR.symbol(getPos()), |
| SqlLiteral.createCharString(resourcePath, getPos())); |
| } |
| } |
| |
| SqlDrop SqlDropFunction(Span s, boolean replace, boolean isTemporary) : |
| { |
| SqlIdentifier functionIdentifier = null; |
| boolean ifExists = false; |
| boolean isSystemFunction = false; |
| } |
| { |
| [ <SYSTEM> { isSystemFunction = true; } ] |
| |
| <FUNCTION> |
| |
| ifExists = IfExistsOpt() |
| |
| functionIdentifier = CompoundIdentifier() |
| |
| { |
| return new SqlDropFunction(s.pos(), functionIdentifier, ifExists, isTemporary, isSystemFunction); |
| } |
| } |
| |
| SqlAlterFunction SqlAlterFunction() : |
| { |
| SqlIdentifier functionIdentifier = null; |
| SqlCharStringLiteral functionClassName = null; |
| String functionLanguage = null; |
| SqlParserPos startPos; |
| boolean ifExists = false; |
| boolean isTemporary = false; |
| boolean isSystemFunction = false; |
| } |
| { |
| <ALTER> |
| |
| [ <TEMPORARY> { isTemporary = true; } |
| [ <SYSTEM> { isSystemFunction = true; } ] |
| ] |
| |
| <FUNCTION> { startPos = getPos(); } |
| |
| ifExists = IfExistsOpt() |
| |
| functionIdentifier = CompoundIdentifier() |
| |
| <AS> <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| functionClassName = SqlLiteral.createCharString(p, getPos()); |
| } |
| |
| [<LANGUAGE> |
| ( <JAVA> { functionLanguage = "JAVA"; } |
| | |
| <SCALA> { functionLanguage = "SCALA"; } |
| | |
| <SQL> { functionLanguage = "SQL"; } |
| | |
| <PYTHON> { functionLanguage = "PYTHON"; } |
| ) |
| ] |
| { |
| return new SqlAlterFunction(startPos.plus(getPos()), functionIdentifier, functionClassName, |
| functionLanguage, ifExists, isTemporary, isSystemFunction); |
| } |
| } |
| |
| /** |
| * Parses a show functions statement. |
| * SHOW [USER] FUNCTIONS [ ( FROM | IN ) [catalog_name.]database_name ] [ [NOT] (LIKE | ILIKE) pattern; |
| */ |
| SqlShowFunctions SqlShowFunctions() : |
| { |
| SqlParserPos pos; |
| boolean requireUser = false; |
| String prep = null; |
| SqlIdentifier databaseName = null; |
| String likeType = null; |
| SqlCharStringLiteral likeLiteral = null; |
| boolean notLike = false; |
| } |
| { |
| <SHOW> { pos = getPos();} |
| [ |
| <USER> { requireUser = true; } |
| ] |
| <FUNCTIONS> |
| [ |
| ( <FROM> { prep = "FROM"; } | <IN> { prep = "IN"; } ) |
| { pos = getPos(); } |
| databaseName = CompoundIdentifier() |
| ] |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| ( |
| <LIKE> |
| { |
| likeType = "LIKE"; |
| } |
| | |
| <ILIKE> |
| { |
| likeType = "ILIKE"; |
| } |
| ) |
| <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowFunctions(pos, requireUser, prep, databaseName, likeType, likeLiteral, notLike); |
| } |
| } |
| |
| /** |
| * Parses a show functions statement. |
| * SHOW PROCEDURES [ ( FROM | IN ) [catalog_name.]database_name ] [ [NOT] (LIKE | ILIKE) pattern; |
| */ |
| SqlShowProcedures SqlShowProcedures() : |
| { |
| String prep = null; |
| SqlIdentifier databaseName = null; |
| boolean notLike = false; |
| String likeType = null; |
| SqlCharStringLiteral likeLiteral = null; |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <PROCEDURES> |
| { pos = getPos(); } |
| [ |
| ( <FROM> { prep = "FROM"; } | <IN> { prep = "IN"; } ) |
| { pos = getPos(); } |
| databaseName = CompoundIdentifier() |
| ] |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| ( <LIKE> { likeType = "LIKE"; } | <ILIKE> { likeType = "ILIKE"; } ) |
| <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowProcedures(pos, prep, databaseName, notLike, likeType, likeLiteral); |
| } |
| } |
| |
| /** |
| * Parse a "Show Views" metadata query command. |
| */ |
| SqlShowViews SqlShowViews() : |
| { |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <VIEWS> { pos = getPos(); } |
| { |
| return new SqlShowViews(pos); |
| } |
| } |
| |
| /** |
| * Parses a show tables statement. |
| * SHOW TABLES [ ( FROM | IN ) [catalog_name.]database_name ] [ [NOT] LIKE pattern ]; |
| */ |
| SqlShowTables SqlShowTables() : |
| { |
| SqlIdentifier databaseName = null; |
| SqlCharStringLiteral likeLiteral = null; |
| String prep = null; |
| boolean notLike = false; |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <TABLES> |
| { pos = getPos(); } |
| [ |
| ( <FROM> { prep = "FROM"; } | <IN> { prep = "IN"; } ) |
| { pos = getPos(); } |
| databaseName = CompoundIdentifier() |
| ] |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| <LIKE> <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowTables(pos, prep, databaseName, notLike, likeLiteral); |
| } |
| } |
| |
| /** |
| * SHOW COLUMNS FROM [[catalog.] database.]sqlIdentifier sql call. |
| */ |
| SqlShowColumns SqlShowColumns() : |
| { |
| SqlIdentifier tableName; |
| SqlCharStringLiteral likeLiteral = null; |
| String prep = "FROM"; |
| boolean notLike = false; |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <COLUMNS> ( <FROM> | <IN> { prep = "IN"; } ) |
| { pos = getPos();} |
| tableName = CompoundIdentifier() |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| <LIKE> <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowColumns(pos, prep, tableName, notLike, likeLiteral); |
| } |
| } |
| |
| /** |
| * Parse a "Show Create Table" query and "Show Create View" and "Show Create Catalog" query commands. |
| */ |
| SqlShowCreate SqlShowCreate() : |
| { |
| SqlIdentifier sqlIdentifier; |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <CREATE> |
| ( |
| <TABLE> |
| { pos = getPos(); } |
| sqlIdentifier = CompoundIdentifier() |
| { |
| return new SqlShowCreateTable(pos, sqlIdentifier); |
| } |
| | |
| <VIEW> |
| { pos = getPos(); } |
| sqlIdentifier = CompoundIdentifier() |
| { |
| return new SqlShowCreateView(pos, sqlIdentifier); |
| } |
| | |
| <CATALOG> |
| { pos = getPos(); } |
| sqlIdentifier = SimpleIdentifier() |
| { |
| return new SqlShowCreateCatalog(pos, sqlIdentifier); |
| } |
| | |
| <MODEL> |
| { pos = getPos(); } |
| sqlIdentifier = CompoundIdentifier() |
| { |
| return new SqlShowCreateModel(pos, sqlIdentifier); |
| } |
| ) |
| } |
| |
| /** |
| * DESCRIBE | DESC MODEL [ EXTENDED] [[catalogName.] dataBasesName].modelName sql call. |
| * Here we add Rich in className to match the naming of SqlRichDescribeTable. |
| */ |
| SqlRichDescribeModel SqlRichDescribeModel() : |
| { |
| SqlIdentifier modelName; |
| SqlParserPos pos; |
| boolean isExtended = false; |
| } |
| { |
| ( <DESCRIBE> | <DESC> ) <MODEL> { pos = getPos();} |
| [ <EXTENDED> { isExtended = true;} ] |
| modelName = CompoundIdentifier() |
| { |
| return new SqlRichDescribeModel(pos, modelName, isExtended); |
| } |
| } |
| |
| /** |
| * DESCRIBE | DESC [ EXTENDED] [[catalogName.] dataBasesName].tableName sql call. |
| * Here we add Rich in className to distinguish from calcite's original SqlDescribeTable. |
| */ |
| SqlRichDescribeTable SqlRichDescribeTable() : |
| { |
| SqlIdentifier tableName; |
| SqlParserPos pos; |
| boolean isExtended = false; |
| } |
| { |
| ( <DESCRIBE> | <DESC> ) { pos = getPos();} |
| [ <EXTENDED> { isExtended = true;} ] |
| tableName = CompoundIdentifier() |
| { |
| return new SqlRichDescribeTable(pos, tableName, isExtended); |
| } |
| } |
| |
| SqlAlterTable SqlAlterTable() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier tableIdentifier; |
| SqlIdentifier newTableIdentifier = null; |
| boolean ifExists = false; |
| boolean ifNotExists = false; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlNodeList propertyKeyList = SqlNodeList.EMPTY; |
| SqlNodeList partitionSpec = null; |
| SqlDistribution distribution = null; |
| SqlIdentifier constraintName; |
| SqlTableConstraint constraint; |
| SqlIdentifier originColumnIdentifier; |
| SqlIdentifier newColumnIdentifier; |
| AlterTableContext ctx = new AlterTableContext(); |
| AlterTableAddPartitionContext addPartitionCtx = new AlterTableAddPartitionContext(); |
| AlterTableDropPartitionsContext dropPartitionsCtx = new AlterTableDropPartitionsContext(); |
| } |
| { |
| <ALTER> <TABLE> { startPos = getPos(); } |
| ifExists = IfExistsOpt() |
| tableIdentifier = CompoundIdentifier() |
| ( |
| LOOKAHEAD(2) |
| <RENAME> <TO> |
| newTableIdentifier = CompoundIdentifier() |
| { |
| return new SqlAlterTableRename( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| newTableIdentifier, |
| ifExists); |
| } |
| | |
| <RENAME> |
| originColumnIdentifier = CompoundIdentifier() |
| <TO> |
| newColumnIdentifier = CompoundIdentifier() |
| { |
| return new SqlAlterTableRenameColumn( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| originColumnIdentifier, |
| newColumnIdentifier, |
| ifExists); |
| } |
| | |
| <RESET> |
| propertyKeyList = PropertyKeys() |
| { |
| return new SqlAlterTableReset( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| propertyKeyList, |
| ifExists); |
| } |
| | |
| <SET> |
| propertyList = Properties() |
| { |
| return new SqlAlterTableOptions( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| propertyList, |
| ifExists); |
| } |
| | |
| <ADD> |
| ( |
| LOOKAHEAD(2) |
| AlterTableAddPartition(addPartitionCtx) |
| { |
| return new SqlAddPartitions(startPos.plus(getPos()), |
| tableIdentifier, |
| addPartitionCtx.ifNotExists, |
| addPartitionCtx.partSpecs, |
| addPartitionCtx.partProps); |
| } |
| | |
| ( |
| AlterTableAddOrModify(ctx) |
| | |
| <LPAREN> |
| AlterTableAddOrModify(ctx) |
| ( |
| <COMMA> AlterTableAddOrModify(ctx) |
| )* |
| <RPAREN> |
| ) |
| { |
| return new SqlAlterTableAdd( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| new SqlNodeList(ctx.columnPositions, startPos.plus(getPos())), |
| ctx.constraints, |
| ctx.watermark, |
| ctx.distribution, |
| ifExists); |
| } |
| ) |
| | |
| <MODIFY> |
| ( |
| AlterTableAddOrModify(ctx) |
| | |
| <LPAREN> |
| AlterTableAddOrModify(ctx) |
| ( |
| <COMMA> AlterTableAddOrModify(ctx) |
| )* |
| <RPAREN> |
| ) |
| { |
| return new SqlAlterTableModify( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| new SqlNodeList(ctx.columnPositions, startPos.plus(getPos())), |
| ctx.constraints, |
| ctx.watermark, |
| ctx.distribution, |
| ifExists); |
| } |
| |
| | |
| <DROP> |
| ( |
| LOOKAHEAD(2) |
| AlterTableDropPartitions(dropPartitionsCtx) { |
| return new SqlDropPartitions( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| dropPartitionsCtx.ifExists, |
| dropPartitionsCtx.partSpecs); |
| } |
| | |
| ( |
| { SqlIdentifier columnName = null; } |
| columnName = CompoundIdentifier() { |
| return new SqlAlterTableDropColumn( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| new SqlNodeList( |
| Collections.singletonList(columnName), |
| getPos()), |
| ifExists); |
| } |
| | |
| { Pair<SqlNodeList, SqlNodeList> columnWithTypePair = null; } |
| columnWithTypePair = ParenthesizedCompoundIdentifierList() { |
| return new SqlAlterTableDropColumn( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| columnWithTypePair.getKey(), |
| ifExists); |
| } |
| | |
| <PRIMARY> <KEY> { |
| return new SqlAlterTableDropPrimaryKey( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| ifExists); |
| } |
| | |
| <CONSTRAINT> constraintName = SimpleIdentifier() { |
| return new SqlAlterTableDropConstraint( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| constraintName, |
| ifExists); |
| } |
| | |
| <DISTRIBUTION> { |
| return new SqlAlterTableDropDistribution( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| ifExists); |
| } |
| | |
| <WATERMARK> { |
| return new SqlAlterTableDropWatermark( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| ifExists); |
| } |
| ) |
| ) |
| | |
| [ |
| <PARTITION> |
| { partitionSpec = new SqlNodeList(getPos()); |
| PartitionSpecCommaList(partitionSpec); |
| } |
| ] |
| <COMPACT> |
| { |
| return new SqlAlterTableCompact(startPos.plus(getPos()), tableIdentifier, partitionSpec, ifExists); |
| } |
| ) |
| } |
| |
| /** Parse a table option key list. */ |
| SqlNodeList PropertyKeys(): |
| { |
| SqlNode key; |
| final List<SqlNode> proKeyList = new ArrayList<SqlNode>(); |
| final Span span; |
| } |
| { |
| <LPAREN> { span = span(); } |
| [ |
| key = StringLiteral() |
| { |
| proKeyList.add(key); |
| } |
| ( |
| <COMMA> key = StringLiteral() |
| { |
| proKeyList.add(key); |
| } |
| )* |
| ] |
| <RPAREN> |
| { return new SqlNodeList(proKeyList, span.end(this)); } |
| } |
| |
| void TableColumn(TableCreationContext context) : |
| { |
| SqlTableConstraint constraint; |
| } |
| { |
| ( |
| LOOKAHEAD(2) |
| TypedColumn(context) |
| | |
| constraint = TableConstraint() { |
| context.constraints.add(constraint); |
| } |
| | |
| ComputedColumn(context) |
| | |
| Watermark(context) |
| ) |
| } |
| |
| void Watermark(TableCreationContext context) : |
| { |
| SqlIdentifier eventTimeColumnName; |
| SqlParserPos pos; |
| SqlNode watermarkStrategy; |
| } |
| { |
| <WATERMARK> {pos = getPos();} <FOR> |
| eventTimeColumnName = CompoundIdentifier() |
| <AS> |
| watermarkStrategy = Expression(ExprContext.ACCEPT_NON_QUERY) { |
| if (context.watermark != null) { |
| throw SqlUtil.newContextException(pos, |
| ParserResource.RESOURCE.multipleWatermarksUnsupported()); |
| } else { |
| context.watermark = new SqlWatermark(pos, eventTimeColumnName, watermarkStrategy); |
| } |
| } |
| } |
| |
| /** Parses {@code column_name column_data_type [...]}. */ |
| SqlTableColumn TypedColumn(TableCreationContext context) : |
| { |
| SqlTableColumn tableColumn; |
| SqlIdentifier name; |
| SqlParserPos pos; |
| SqlDataTypeSpec type; |
| } |
| { |
| name = CompoundIdentifier() {pos = getPos();} |
| type = ExtendedDataType() |
| ( |
| tableColumn = MetadataColumn(context, name, type) |
| | |
| tableColumn = RegularColumn(context, name, type) |
| ) |
| { |
| return tableColumn; |
| } |
| } |
| |
| /** Parses {@code column_name AS expr [COMMENT 'comment']}. */ |
| SqlTableColumn ComputedColumn(TableCreationContext context) : |
| { |
| SqlIdentifier name; |
| SqlParserPos pos; |
| SqlNode expr; |
| SqlNode comment = null; |
| } |
| { |
| name = SimpleIdentifier() {pos = getPos();} |
| <AS> |
| expr = Expression(ExprContext.ACCEPT_NON_QUERY) |
| [ |
| <COMMENT> |
| comment = StringLiteral() |
| ] |
| { |
| SqlTableColumn computedColumn = new SqlTableColumn.SqlComputedColumn( |
| getPos(), |
| name, |
| comment, |
| expr); |
| context.columnList.add(computedColumn); |
| return computedColumn; |
| } |
| } |
| |
| /** Parses {@code column_name column_data_type METADATA [FROM 'alias_name'] [VIRTUAL] [COMMENT 'comment']}. */ |
| SqlTableColumn MetadataColumn(TableCreationContext context, SqlIdentifier name, SqlDataTypeSpec type) : |
| { |
| SqlNode metadataAlias = null; |
| boolean isVirtual = false; |
| SqlNode comment = null; |
| } |
| { |
| <METADATA> |
| [ |
| <FROM> |
| metadataAlias = StringLiteral() |
| ] |
| [ |
| <VIRTUAL> { |
| isVirtual = true; |
| } |
| ] |
| [ |
| <COMMENT> |
| comment = StringLiteral() |
| ] |
| { |
| SqlTableColumn metadataColumn = new SqlTableColumn.SqlMetadataColumn( |
| getPos(), |
| name, |
| comment, |
| type, |
| metadataAlias, |
| isVirtual); |
| context.columnList.add(metadataColumn); |
| return metadataColumn; |
| } |
| } |
| |
| /** Parses {@code column_name column_data_type [constraint] [COMMENT 'comment']}. */ |
| SqlTableColumn RegularColumn(TableCreationContext context, SqlIdentifier name, SqlDataTypeSpec type) : |
| { |
| SqlTableConstraint constraint = null; |
| SqlNode comment = null; |
| } |
| { |
| [ |
| constraint = ColumnConstraint(name) |
| ] |
| [ |
| <COMMENT> |
| comment = StringLiteral() |
| ] |
| { |
| SqlTableColumn regularColumn = new SqlTableColumn.SqlRegularColumn( |
| getPos(), |
| name, |
| comment, |
| type, |
| constraint); |
| context.columnList.add(regularColumn); |
| return regularColumn; |
| } |
| } |
| |
| /** Parses {@code ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [PARTITION partition_spec][...]}. */ |
| void AlterTableAddPartition(AlterTableAddPartitionContext context) : |
| { |
| List<SqlNodeList> partSpecs = new ArrayList(); |
| List<SqlNodeList> partProps = new ArrayList(); |
| SqlNodeList partSpec; |
| SqlNodeList partProp; |
| } |
| { |
| context.ifNotExists = IfNotExistsOpt() |
| ( |
| <PARTITION> |
| { |
| partSpec = new SqlNodeList(getPos()); |
| partProp = null; |
| PartitionSpecCommaList(partSpec); |
| } |
| [ <WITH> { partProp = Properties(); } ] |
| { |
| partSpecs.add(partSpec); |
| partProps.add(partProp); |
| } |
| )+ |
| { |
| context.partSpecs = partSpecs; |
| context.partProps = partProps; |
| } |
| } |
| |
| /** Parses {@code ALTER TABLE table_name ADD/MODIFY [...]}. */ |
| void AlterTableAddOrModify(AlterTableContext context) : |
| { |
| SqlTableConstraint constraint; |
| } |
| { |
| ( |
| AddOrModifyColumn(context) |
| | |
| constraint = TableConstraint() { |
| context.constraints.add(constraint); |
| } |
| | |
| Watermark(context) |
| | |
| <DISTRIBUTION> |
| context.distribution = SqlDistribution(getPos()) |
| ) |
| } |
| |
| /** Parses {@code ADD/MODIFY column_name column_data_type [...]}. */ |
| void AddOrModifyColumn(AlterTableContext context) : |
| { |
| SqlTableColumn column; |
| SqlIdentifier referencedColumn = null; |
| SqlTableColumnPosition columnPos = null; |
| } |
| { |
| ( |
| LOOKAHEAD(2) |
| column = TypedColumn(context) |
| | |
| column = ComputedColumn(context) |
| ) |
| [ |
| ( |
| <AFTER> |
| referencedColumn = CompoundIdentifier() |
| { |
| columnPos = new SqlTableColumnPosition( |
| getPos(), |
| column, |
| SqlColumnPosSpec.AFTER.symbol(getPos()), |
| referencedColumn); |
| } |
| | |
| <FIRST> |
| { |
| columnPos = new SqlTableColumnPosition( |
| getPos(), |
| column, |
| SqlColumnPosSpec.FIRST.symbol(getPos()), |
| referencedColumn); |
| } |
| ) |
| ] |
| { |
| if (columnPos == null) { |
| columnPos = new SqlTableColumnPosition( |
| getPos(), |
| column, |
| null, |
| referencedColumn); |
| } |
| context.columnPositions.add(columnPos); |
| } |
| } |
| |
| /** Parses {@code ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec[, PARTITION partition_spec, ...]}. */ |
| void AlterTableDropPartitions(AlterTableDropPartitionsContext context) : |
| { |
| List<SqlNodeList> partSpecs = new ArrayList(); |
| SqlNodeList partSpec; |
| } |
| { |
| context.ifExists = IfExistsOpt() |
| <PARTITION> |
| { |
| partSpec = new SqlNodeList(getPos()); |
| PartitionSpecCommaList(partSpec); |
| partSpecs.add(partSpec); |
| } |
| ( |
| <COMMA> |
| <PARTITION> |
| { |
| partSpec = new SqlNodeList(getPos()); |
| PartitionSpecCommaList(partSpec); |
| partSpecs.add(partSpec); |
| } |
| )* |
| { |
| context.partSpecs = partSpecs; |
| } |
| } |
| |
| /** |
| * Different with {@link #DataType()}, we support a [ NULL | NOT NULL ] suffix syntax for both the |
| * collection element data type and the data type itself. |
| * |
| * <p>See {@link #SqlDataTypeSpec} for the syntax details of {@link #DataType()}. |
| */ |
| SqlDataTypeSpec ExtendedDataType() : |
| { |
| SqlTypeNameSpec typeName; |
| final Span s; |
| boolean elementNullable = true; |
| boolean nullable = true; |
| } |
| { |
| <#-- #DataType does not take care of the nullable attribute. --> |
| typeName = TypeName() { |
| s = span(); |
| } |
| ( |
| LOOKAHEAD(3) |
| elementNullable = NullableOptDefaultTrue() |
| typeName = ExtendedCollectionsTypeName(typeName, elementNullable) |
| )* |
| nullable = NullableOptDefaultTrue() |
| { |
| return new SqlDataTypeSpec(typeName, s.end(this)).withNullable(nullable); |
| } |
| } |
| |
| /** Parses a column constraint for CREATE TABLE. */ |
| SqlTableConstraint ColumnConstraint(SqlIdentifier column) : |
| { |
| SqlIdentifier constraintName = null; |
| final SqlLiteral uniqueSpec; |
| SqlLiteral enforcement = null; |
| } |
| { |
| |
| [ constraintName = ConstraintName() ] |
| uniqueSpec = UniqueSpec() |
| [ enforcement = ConstraintEnforcement() ] |
| { |
| return new SqlTableConstraint( |
| constraintName, |
| uniqueSpec, |
| SqlNodeList.of(column), |
| enforcement, |
| false, |
| getPos()); |
| } |
| } |
| |
| /** Parses a table constraint for CREATE TABLE. */ |
| SqlTableConstraint TableConstraint() : |
| { |
| SqlIdentifier constraintName = null; |
| final SqlLiteral uniqueSpec; |
| final SqlNodeList columns; |
| SqlLiteral enforcement = null; |
| } |
| { |
| |
| [ constraintName = ConstraintName() ] |
| uniqueSpec = UniqueSpec() |
| columns = ParenthesizedSimpleIdentifierList() |
| [ enforcement = ConstraintEnforcement() ] |
| { |
| return new SqlTableConstraint( |
| constraintName, |
| uniqueSpec, |
| columns, |
| enforcement, |
| true, |
| getPos()); |
| } |
| } |
| |
| SqlIdentifier ConstraintName() : |
| { |
| SqlIdentifier constraintName; |
| } |
| { |
| <CONSTRAINT> constraintName = SimpleIdentifier() { |
| return constraintName; |
| } |
| } |
| |
| SqlLiteral UniqueSpec() : |
| { |
| SqlLiteral uniqueSpec; |
| } |
| { |
| ( |
| <PRIMARY> <KEY> { |
| uniqueSpec = SqlUniqueSpec.PRIMARY_KEY.symbol(getPos()); |
| } |
| | |
| <UNIQUE> { |
| uniqueSpec = SqlUniqueSpec.UNIQUE.symbol(getPos()); |
| } |
| ) |
| { |
| return uniqueSpec; |
| } |
| } |
| |
| SqlLiteral ConstraintEnforcement() : |
| { |
| SqlLiteral enforcement; |
| } |
| { |
| ( |
| <ENFORCED> { |
| enforcement = SqlConstraintEnforcement.ENFORCED.symbol(getPos()); |
| } |
| | |
| <NOT> <ENFORCED> { |
| enforcement = SqlConstraintEnforcement.NOT_ENFORCED.symbol(getPos()); |
| } |
| ) |
| { |
| return enforcement; |
| } |
| } |
| |
| SqlNode TableOption() : |
| { |
| SqlNode key; |
| SqlNode value; |
| SqlParserPos pos; |
| } |
| { |
| key = StringLiteral() |
| { pos = getPos(); } |
| <EQ> value = StringLiteral() |
| { |
| return new SqlTableOption(key, value, getPos()); |
| } |
| } |
| |
| /** Parse properties such as ('k' = 'v'). */ |
| SqlNodeList Properties(): |
| { |
| SqlNode property; |
| final List<SqlNode> proList = new ArrayList<SqlNode>(); |
| final Span span; |
| } |
| { |
| <LPAREN> { span = span(); } |
| [ |
| property = TableOption() |
| { |
| proList.add(property); |
| } |
| ( |
| <COMMA> property = TableOption() |
| { |
| proList.add(property); |
| } |
| )* |
| ] |
| <RPAREN> |
| { return new SqlNodeList(proList, span.end(this)); } |
| } |
| |
| SqlNumericLiteral IntoBuckets(SqlParserPos startPos) : |
| { |
| SqlNumericLiteral bucketCount; |
| } |
| { |
| <INTO> { bucketCount = UnsignedNumericLiteral(); |
| if (!bucketCount.isInteger()) { |
| throw SqlUtil.newContextException(getPos(), |
| ParserResource.RESOURCE.bucketCountMustBePositiveInteger()); |
| } |
| } <BUCKETS> |
| { |
| return bucketCount; |
| } |
| } |
| |
| SqlDistribution SqlDistribution(SqlParserPos startPos) : |
| { |
| String distributionKind = null; |
| SqlNumericLiteral bucketCount = null; |
| SqlNodeList bucketColumns = SqlNodeList.EMPTY; |
| } |
| { |
| ( |
| bucketCount = IntoBuckets(getPos()) |
| | |
| ( |
| <BY> ( |
| <HASH> { distributionKind = "HASH"; } |
| | <RANGE> { distributionKind = "RANGE"; } |
| | { distributionKind = null; } |
| ) |
| { bucketColumns = ParenthesizedSimpleIdentifierList(); } |
| [ bucketCount = IntoBuckets(getPos()) ] |
| ) |
| ) |
| { |
| return new SqlDistribution(startPos, distributionKind, bucketColumns, bucketCount); |
| } |
| } |
| |
| SqlCreate SqlCreateTable(Span s, boolean replace, boolean isTemporary) : |
| { |
| final SqlParserPos startPos = s.pos(); |
| boolean ifNotExists = false; |
| SqlIdentifier tableName; |
| List<SqlTableConstraint> constraints = new ArrayList<SqlTableConstraint>(); |
| SqlWatermark watermark = null; |
| SqlNodeList columnList = SqlNodeList.EMPTY; |
| SqlCharStringLiteral comment = null; |
| SqlTableLike tableLike = null; |
| SqlNode asQuery = null; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlDistribution distribution = null; |
| SqlNodeList partitionColumns = SqlNodeList.EMPTY; |
| SqlParserPos pos = startPos; |
| } |
| { |
| <TABLE> |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| tableName = CompoundIdentifier() |
| [ |
| <LPAREN> { pos = getPos(); TableCreationContext ctx = new TableCreationContext();} |
| TableColumn(ctx) |
| ( |
| <COMMA> TableColumn(ctx) |
| )* |
| { |
| pos = pos.plus(getPos()); |
| columnList = new SqlNodeList(ctx.columnList, pos); |
| constraints = ctx.constraints; |
| watermark = ctx.watermark; |
| } |
| <RPAREN> |
| ] |
| [ <COMMENT> <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| }] |
| [ |
| <DISTRIBUTED> |
| distribution = SqlDistribution(getPos()) |
| ] |
| |
| [ |
| <PARTITIONED> <BY> |
| partitionColumns = ParenthesizedSimpleIdentifierList() |
| ] |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| [ |
| <LIKE> |
| tableLike = SqlTableLike(getPos()) |
| { |
| return new SqlCreateTableLike(startPos.plus(getPos()), |
| tableName, |
| columnList, |
| constraints, |
| propertyList, |
| distribution, |
| partitionColumns, |
| watermark, |
| comment, |
| tableLike, |
| isTemporary, |
| ifNotExists); |
| } |
| | |
| <AS> |
| asQuery = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| if (replace) { |
| return new SqlReplaceTableAs(startPos.plus(getPos()), |
| tableName, |
| columnList, |
| constraints, |
| propertyList, |
| distribution, |
| partitionColumns, |
| watermark, |
| comment, |
| asQuery, |
| isTemporary, |
| ifNotExists, |
| true); |
| } else { |
| return new SqlCreateTableAs(startPos.plus(getPos()), |
| tableName, |
| columnList, |
| constraints, |
| propertyList, |
| distribution, |
| partitionColumns, |
| watermark, |
| comment, |
| asQuery, |
| isTemporary, |
| ifNotExists); |
| } |
| } |
| ] |
| { |
| return new SqlCreateTable(startPos.plus(getPos()), |
| tableName, |
| columnList, |
| constraints, |
| propertyList, |
| distribution, |
| partitionColumns, |
| watermark, |
| comment, |
| isTemporary, |
| ifNotExists); |
| } |
| } |
| |
| SqlTableLike SqlTableLike(SqlParserPos startPos): |
| { |
| final List<SqlTableLikeOption> likeOptions = new ArrayList<SqlTableLikeOption>(); |
| SqlIdentifier tableName; |
| SqlTableLikeOption likeOption; |
| } |
| { |
| tableName = CompoundIdentifier() |
| [ |
| <LPAREN> |
| ( |
| likeOption = SqlTableLikeOption() |
| { |
| likeOptions.add(likeOption); |
| } |
| )+ |
| <RPAREN> |
| ] |
| { |
| return new SqlTableLike( |
| startPos.plus(getPos()), |
| tableName, |
| likeOptions |
| ); |
| } |
| } |
| |
| SqlTableLikeOption SqlTableLikeOption(): |
| { |
| MergingStrategy mergingStrategy; |
| FeatureOption featureOption; |
| } |
| { |
| ( |
| <INCLUDING> { mergingStrategy = MergingStrategy.INCLUDING; } |
| | |
| <EXCLUDING> { mergingStrategy = MergingStrategy.EXCLUDING; } |
| | |
| <OVERWRITING> { mergingStrategy = MergingStrategy.OVERWRITING; } |
| ) |
| ( |
| <ALL> { featureOption = FeatureOption.ALL;} |
| | |
| <CONSTRAINTS> { featureOption = FeatureOption.CONSTRAINTS;} |
| | |
| <DISTRIBUTION> { featureOption = FeatureOption.DISTRIBUTION;} |
| | |
| <GENERATED> { featureOption = FeatureOption.GENERATED;} |
| | |
| <METADATA> { featureOption = FeatureOption.METADATA;} |
| | |
| <OPTIONS> { featureOption = FeatureOption.OPTIONS;} |
| | |
| <PARTITIONS> { featureOption = FeatureOption.PARTITIONS;} |
| | |
| <WATERMARKS> { featureOption = FeatureOption.WATERMARKS;} |
| ) |
| |
| { |
| return new SqlTableLikeOption(mergingStrategy, featureOption); |
| } |
| } |
| |
| SqlDrop SqlDropTable(Span s, boolean replace, boolean isTemporary) : |
| { |
| SqlIdentifier tableName = null; |
| boolean ifExists = false; |
| } |
| { |
| <TABLE> |
| |
| ifExists = IfExistsOpt() |
| |
| tableName = CompoundIdentifier() |
| |
| { |
| return new SqlDropTable(s.pos(), tableName, ifExists, isTemporary); |
| } |
| } |
| |
| /** |
| * Parser a REPLACE TABLE AS statement |
| */ |
| SqlNode SqlReplaceTable() : |
| { |
| SqlIdentifier tableName; |
| SqlCharStringLiteral comment = null; |
| SqlNode asQuery = null; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlParserPos pos; |
| boolean isTemporary = false; |
| List<SqlTableConstraint> constraints = new ArrayList<SqlTableConstraint>(); |
| SqlWatermark watermark = null; |
| SqlNodeList columnList = SqlNodeList.EMPTY; |
| SqlDistribution distribution = null; |
| SqlNodeList partitionColumns = SqlNodeList.EMPTY; |
| boolean ifNotExists = false; |
| } |
| { |
| <REPLACE> |
| [ |
| <TEMPORARY> { isTemporary = true; } |
| ] |
| <TABLE> |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| tableName = CompoundIdentifier() |
| [ |
| <LPAREN> { pos = getPos(); TableCreationContext ctx = new TableCreationContext();} |
| TableColumn(ctx) |
| ( |
| <COMMA> TableColumn(ctx) |
| )* |
| { |
| pos = getPos(); |
| columnList = new SqlNodeList(ctx.columnList, pos); |
| constraints = ctx.constraints; |
| watermark = ctx.watermark; |
| } |
| <RPAREN> |
| ] |
| [ <COMMENT> <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| }] |
| [ |
| <DISTRIBUTED> |
| distribution = SqlDistribution(getPos()) |
| ] |
| [ |
| <PARTITIONED> <BY> |
| partitionColumns = ParenthesizedSimpleIdentifierList() |
| ] |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| <AS> |
| asQuery = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| return new SqlReplaceTableAs(getPos(), |
| tableName, |
| columnList, |
| constraints, |
| propertyList, |
| distribution, |
| partitionColumns, |
| watermark, |
| comment, |
| asQuery, |
| isTemporary, |
| ifNotExists, |
| false); |
| } |
| } |
| |
| /** |
| * Parses a CREATE MATERIALIZED TABLE statement. |
| */ |
| SqlCreate SqlCreateMaterializedTable(Span s, boolean replace, boolean isTemporary) : |
| { |
| final SqlParserPos startPos = s.pos(); |
| SqlIdentifier tableName; |
| SqlCharStringLiteral comment = null; |
| SqlTableConstraint constraint = null; |
| SqlNodeList partitionColumns = SqlNodeList.EMPTY; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlNode freshness = null; |
| SqlLiteral refreshMode = null; |
| SqlNode asQuery = null; |
| } |
| { |
| <MATERIALIZED> |
| { |
| if (isTemporary) { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.createTemporaryMaterializedTableUnsupported()); |
| } |
| if (replace) { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.replaceMaterializedTableUnsupported()); |
| } |
| } |
| <TABLE> |
| tableName = CompoundIdentifier() |
| [ |
| <LPAREN> |
| constraint = TableConstraint() |
| <RPAREN> |
| ] |
| [ |
| <COMMENT> <QUOTED_STRING> |
| { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| } |
| ] |
| [ |
| <PARTITIONED> <BY> |
| partitionColumns = ParenthesizedSimpleIdentifierList() |
| ] |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| <FRESHNESS> <EQ> |
| freshness = Expression(ExprContext.ACCEPT_NON_QUERY) |
| { |
| if (!(freshness instanceof SqlIntervalLiteral)) |
| { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.unsupportedFreshnessType()); |
| } |
| } |
| [ |
| <REFRESH_MODE> <EQ> |
| ( |
| <FULL> |
| { |
| refreshMode = SqlRefreshMode.FULL.symbol(getPos()); |
| } |
| | |
| <CONTINUOUS> |
| { |
| refreshMode = SqlRefreshMode.CONTINUOUS.symbol(getPos()); |
| } |
| ) |
| ] |
| <AS> |
| asQuery = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| return new SqlCreateMaterializedTable( |
| startPos.plus(getPos()), |
| tableName, |
| comment, |
| constraint, |
| partitionColumns, |
| propertyList, |
| (SqlIntervalLiteral) freshness, |
| refreshMode, |
| asQuery); |
| } |
| } |
| |
| /** |
| * Parses a DROP MATERIALIZED TABLE statement. |
| */ |
| SqlDrop SqlDropMaterializedTable(Span s, boolean replace, boolean isTemporary) : |
| { |
| SqlIdentifier tableName = null; |
| boolean ifExists = false; |
| } |
| { |
| <MATERIALIZED> |
| { |
| if (isTemporary) { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.dropTemporaryMaterializedTableUnsupported()); |
| } |
| } |
| <TABLE> |
| |
| ifExists = IfExistsOpt() |
| |
| tableName = CompoundIdentifier() |
| |
| { |
| return new SqlDropMaterializedTable(s.pos(), tableName, ifExists); |
| } |
| } |
| |
| /** |
| * Parses alter materialized table. |
| */ |
| SqlAlterMaterializedTable SqlAlterMaterializedTable() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier tableIdentifier; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlNodeList propertyKeyList = SqlNodeList.EMPTY; |
| SqlNodeList partSpec = SqlNodeList.EMPTY; |
| SqlNode freshness = null; |
| } |
| { |
| <ALTER> <MATERIALIZED> <TABLE> { startPos = getPos();} |
| tableIdentifier = CompoundIdentifier() |
| ( |
| <SUSPEND> |
| { |
| return new SqlAlterMaterializedTableSuspend(startPos, tableIdentifier); |
| } |
| | |
| <RESUME> |
| [ <WITH> propertyList = Properties() ] |
| { |
| return new SqlAlterMaterializedTableResume( |
| startPos, |
| tableIdentifier, |
| propertyList); |
| } |
| | |
| <REFRESH> |
| [ <PARTITION> { |
| partSpec = new SqlNodeList(getPos()); |
| PartitionSpecCommaList(partSpec); |
| } |
| ] |
| { |
| return new SqlAlterMaterializedTableRefresh( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| partSpec); |
| } |
| | |
| <SET> |
| ( |
| <FRESHNESS> <EQ> freshness = Expression(ExprContext.ACCEPT_NON_QUERY) { |
| if (!(freshness instanceof SqlIntervalLiteral)) { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.unsupportedFreshnessType()); |
| } |
| return new SqlAlterMaterializedTableFreshness( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| (SqlIntervalLiteral) freshness); |
| } |
| | |
| <REFRESH_MODE> <EQ> |
| ( |
| <FULL> { |
| return new SqlAlterMaterializedTableRefreshMode( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| SqlRefreshMode.FULL.symbol(getPos())); |
| } |
| | |
| <CONTINUOUS> { |
| return new SqlAlterMaterializedTableRefreshMode( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| SqlRefreshMode.CONTINUOUS.symbol(getPos())); |
| } |
| ) |
| | |
| propertyList = Properties() |
| { |
| return new SqlAlterMaterializedTableOptions( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| propertyList); |
| } |
| ) |
| | |
| <RESET> |
| propertyKeyList = PropertyKeys() |
| { |
| return new SqlAlterMaterializedTableReset( |
| startPos.plus(getPos()), |
| tableIdentifier, |
| propertyKeyList); |
| } |
| ) |
| } |
| |
| /** |
| * Parses an INSERT statement. |
| */ |
| SqlNode RichSqlInsert() : |
| { |
| final List<SqlLiteral> keywords = new ArrayList<SqlLiteral>(); |
| final SqlNodeList keywordList; |
| final List<SqlLiteral> extendedKeywords = new ArrayList<SqlLiteral>(); |
| final SqlNodeList extendedKeywordList; |
| final SqlIdentifier tableName; |
| SqlNode tableRef; |
| final SqlNodeList extendList; |
| SqlNode source; |
| final SqlNodeList partitionList = new SqlNodeList(getPos()); |
| SqlNodeList columnList = null; |
| final Span s; |
| final Pair<SqlNodeList, SqlNodeList> p; |
| } |
| { |
| ( |
| <INSERT> |
| | |
| <UPSERT> { keywords.add(SqlInsertKeyword.UPSERT.symbol(getPos())); } |
| ) |
| ( |
| <INTO> |
| | |
| <OVERWRITE> { |
| if (RichSqlInsert.isUpsert(keywords)) { |
| throw SqlUtil.newContextException(getPos(), |
| ParserResource.RESOURCE.overwriteIsOnlyUsedWithInsert()); |
| } |
| extendedKeywords.add(RichSqlInsertKeyword.OVERWRITE.symbol(getPos())); |
| } |
| ) |
| { s = span(); } |
| SqlInsertKeywords(keywords) { |
| keywordList = new SqlNodeList(keywords, s.addAll(keywords).pos()); |
| extendedKeywordList = new SqlNodeList(extendedKeywords, s.addAll(extendedKeywords).pos()); |
| } |
| tableName = CompoundTableIdentifier() |
| ( tableRef = TableHints(tableName) | { tableRef = tableName; } ) |
| [ LOOKAHEAD(5) tableRef = ExtendTable(tableRef) ] |
| [ |
| <PARTITION> PartitionSpecCommaList(partitionList) |
| ] |
| ( |
| LOOKAHEAD(2) |
| p = ParenthesizedCompoundIdentifierList() { |
| if (p.right.size() > 0) { |
| tableRef = extend(tableRef, p.right); |
| } |
| if (p.left.size() > 0) { |
| columnList = p.left; |
| } else { |
| columnList = null; |
| } |
| } |
| | { columnList = null; } |
| ) |
| source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) { |
| return new RichSqlInsert(s.end(source), keywordList, extendedKeywordList, tableRef, source, |
| columnList, partitionList); |
| } |
| } |
| |
| /** |
| * Parses a partition specifications statement, |
| * e.g. insert into tbl1 partition(col1='val1', col2='val2') select col3 from tbl. |
| */ |
| void PartitionSpecCommaList(SqlNodeList list) : |
| { |
| SqlIdentifier key; |
| SqlNode value; |
| SqlParserPos pos; |
| } |
| { |
| <LPAREN> |
| key = SimpleIdentifier() |
| { pos = getPos(); } |
| <EQ> value = Literal() { |
| list.add(new SqlProperty(key, value, pos)); |
| } |
| ( |
| <COMMA> key = SimpleIdentifier() { pos = getPos(); } |
| <EQ> value = Literal() { |
| list.add(new SqlProperty(key, value, pos)); |
| } |
| )* |
| <RPAREN> |
| } |
| |
| /** |
| * Parses a create view or temporary view statement. |
| * CREATE [OR REPLACE] [TEMPORARY] VIEW [IF NOT EXISTS] view_name [ (field1, field2 ...) ] |
| * AS select_statement |
| * We only support [IF NOT EXISTS] semantic in Flink although the parser supports [OR REPLACE] grammar. |
| * See: FLINK-17067 |
| */ |
| SqlCreate SqlCreateView(Span s, boolean replace, boolean isTemporary) : { |
| SqlIdentifier viewName; |
| SqlCharStringLiteral comment = null; |
| SqlNode query; |
| SqlNodeList fieldList = SqlNodeList.EMPTY; |
| boolean ifNotExists = false; |
| } |
| { |
| <VIEW> |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| viewName = CompoundIdentifier() |
| [ |
| fieldList = ParenthesizedSimpleIdentifierList() |
| ] |
| [ <COMMENT> <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| } |
| ] |
| <AS> |
| query = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| return new SqlCreateView(s.pos(), viewName, fieldList, query, replace, isTemporary, ifNotExists, comment, null); |
| } |
| } |
| |
| SqlDrop SqlDropView(Span s, boolean replace, boolean isTemporary) : |
| { |
| SqlIdentifier viewName = null; |
| boolean ifExists = false; |
| } |
| { |
| <VIEW> |
| |
| ifExists = IfExistsOpt() |
| |
| viewName = CompoundIdentifier() |
| { |
| return new SqlDropView(s.pos(), viewName, ifExists, isTemporary); |
| } |
| } |
| |
| SqlAlterView SqlAlterView() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier viewName; |
| SqlIdentifier newViewName; |
| SqlNode newQuery; |
| } |
| { |
| <ALTER> <VIEW> { startPos = getPos(); } |
| viewName = CompoundIdentifier() |
| ( |
| <RENAME> <TO> |
| newViewName = CompoundIdentifier() |
| { |
| return new SqlAlterViewRename(startPos.plus(getPos()), viewName, newViewName); |
| } |
| | |
| <AS> |
| newQuery = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| return new SqlAlterViewAs(startPos.plus(getPos()), viewName, newQuery); |
| } |
| ) |
| } |
| |
| /** |
| * A sql type name extended basic data type, it has a counterpart basic |
| * sql type name but always represents as a special alias compared with the standard name. |
| * |
| * <p>For example: |
| * 1. STRING is synonym of VARCHAR(INT_MAX), |
| * 2. BYTES is synonym of VARBINARY(INT_MAX), |
| * 3. TIMESTAMP_LTZ(precision) is synonym of TIMESTAMP(precision) WITH LOCAL TIME ZONE. |
| */ |
| SqlTypeNameSpec ExtendedSqlBasicTypeName() : |
| { |
| final SqlTypeName typeName; |
| final String typeAlias; |
| int precision = -1; |
| } |
| { |
| ( |
| <STRING> { |
| typeName = SqlTypeName.VARCHAR; |
| typeAlias = token.image; |
| precision = Integer.MAX_VALUE; |
| } |
| | |
| <BYTES> { |
| typeName = SqlTypeName.VARBINARY; |
| typeAlias = token.image; |
| precision = Integer.MAX_VALUE; |
| } |
| | |
| <TIMESTAMP_LTZ> |
| { |
| typeAlias = token.image; |
| } |
| precision = PrecisionOpt() |
| { |
| typeName = SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE; |
| return new SqlTimestampLtzTypeNameSpec(typeAlias, typeName, precision, getPos()); |
| } |
| ) |
| { |
| return new SqlAlienSystemTypeNameSpec(typeAlias, typeName, precision, getPos()); |
| } |
| } |
| |
| /* |
| * Parses collection type name that does not belong to standard SQL, i.e. ARRAY<INT NOT NULL>. |
| */ |
| SqlTypeNameSpec CustomizedCollectionsTypeName() : |
| { |
| final SqlTypeName collectionTypeName; |
| final SqlTypeNameSpec elementTypeName; |
| boolean elementNullable = true; |
| } |
| { |
| ( |
| <ARRAY> { |
| collectionTypeName = SqlTypeName.ARRAY; |
| } |
| | |
| <MULTISET> { |
| collectionTypeName = SqlTypeName.MULTISET; |
| } |
| ) |
| <LT> |
| elementTypeName = TypeName() |
| elementNullable = NullableOptDefaultTrue() |
| <GT> |
| { |
| return new ExtendedSqlCollectionTypeNameSpec( |
| elementTypeName, |
| elementNullable, |
| collectionTypeName, |
| false, |
| getPos()); |
| } |
| } |
| |
| /** |
| * Parse a collection type name, the input element type name may |
| * also be a collection type. Different with #CollectionsTypeName, |
| * the element type can have a [ NULL | NOT NULL ] suffix, default is NULL(nullable). |
| */ |
| SqlTypeNameSpec ExtendedCollectionsTypeName( |
| SqlTypeNameSpec elementTypeName, |
| boolean elementNullable) : |
| { |
| final SqlTypeName collectionTypeName; |
| } |
| { |
| ( |
| <MULTISET> { collectionTypeName = SqlTypeName.MULTISET; } |
| | |
| <ARRAY> { collectionTypeName = SqlTypeName.ARRAY; } |
| ) |
| { |
| return new ExtendedSqlCollectionTypeNameSpec( |
| elementTypeName, |
| elementNullable, |
| collectionTypeName, |
| true, |
| getPos()); |
| } |
| } |
| |
| /** Parses a SQL map type, e.g. MAP<INT NOT NULL, VARCHAR NULL>. */ |
| SqlTypeNameSpec SqlMapTypeName() : |
| { |
| SqlDataTypeSpec keyType; |
| SqlDataTypeSpec valType; |
| } |
| { |
| <MAP> |
| <LT> |
| keyType = ExtendedDataType() |
| <COMMA> |
| valType = ExtendedDataType() |
| <GT> |
| { |
| return new SqlMapTypeNameSpec(keyType, valType, getPos()); |
| } |
| } |
| |
| /** Parses a SQL raw type such as {@code RAW('org.my.Class', 'sW3Djsds...')}. */ |
| SqlTypeNameSpec SqlRawTypeName() : |
| { |
| SqlNode className; |
| SqlNode serializerString; |
| } |
| { |
| <RAW> |
| <LPAREN> |
| className = StringLiteral() |
| <COMMA> |
| serializerString = StringLiteral() |
| <RPAREN> |
| { |
| return new SqlRawTypeNameSpec(className, serializerString, getPos()); |
| } |
| } |
| |
| /** |
| * Parse a "name1 type1 [ NULL | NOT NULL] [ comment ] |
| * [, name2 type2 [ NULL | NOT NULL] [ comment ] ]* ..." list. |
| * The comment and NULL syntax doest not belong to standard SQL. |
| */ |
| void ExtendedFieldNameTypeCommaList( |
| List<SqlIdentifier> fieldNames, |
| List<SqlDataTypeSpec> fieldTypes, |
| List<SqlCharStringLiteral> comments) : |
| { |
| SqlIdentifier fName; |
| SqlDataTypeSpec fType; |
| boolean nullable; |
| } |
| { |
| [ |
| fName = SimpleIdentifier() |
| fType = ExtendedDataType() |
| { |
| fieldNames.add(fName); |
| fieldTypes.add(fType); |
| } |
| ( |
| <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| comments.add(SqlLiteral.createCharString(p, getPos())); |
| } |
| | |
| { comments.add(null); } |
| ) |
| ] |
| ( |
| <COMMA> |
| fName = SimpleIdentifier() |
| fType = ExtendedDataType() |
| { |
| fieldNames.add(fName); |
| fieldTypes.add(fType); |
| } |
| ( |
| <QUOTED_STRING> { |
| String p = SqlParserUtil.parseString(token.image); |
| comments.add(SqlLiteral.createCharString(p, getPos())); |
| } |
| | |
| { comments.add(null); } |
| ) |
| )* |
| } |
| |
| /** |
| * Parse Row type, we support both Row(name1 type1, name2 type2) |
| * and Row<name1 type1, name2 type2>. |
| * Every item type can have a suffix of `NULL` or `NOT NULL` to indicate if this type is nullable. |
| * i.e. Row(f0 int not null, f1 varchar null). Default is nullable. |
| * |
| * <p>The difference with {@link #SqlRowTypeName()}: |
| * <ul> |
| * <li>Support comment syntax for every field</li> |
| * <li>Field data type default is nullable</li> |
| * <li>Support ROW type with empty fields, e.g. ROW()</li> |
| * </ul> |
| */ |
| SqlTypeNameSpec ExtendedSqlRowTypeName() : |
| { |
| List<SqlIdentifier> fieldNames = new ArrayList<SqlIdentifier>(); |
| List<SqlDataTypeSpec> fieldTypes = new ArrayList<SqlDataTypeSpec>(); |
| List<SqlCharStringLiteral> comments = new ArrayList<SqlCharStringLiteral>(); |
| final boolean unparseAsStandard; |
| } |
| { |
| <ROW> |
| ( |
| <NE> { unparseAsStandard = false; } |
| | |
| <LT> ExtendedFieldNameTypeCommaList(fieldNames, fieldTypes, comments) <GT> |
| { unparseAsStandard = false; } |
| | |
| <LPAREN> ExtendedFieldNameTypeCommaList(fieldNames, fieldTypes, comments) <RPAREN> |
| { unparseAsStandard = true; } |
| ) |
| { |
| return new ExtendedSqlRowTypeNameSpec( |
| getPos(), |
| fieldNames, |
| fieldTypes, |
| comments, |
| unparseAsStandard); |
| } |
| } |
| |
| /** |
| * Those methods should not be used in SQL. They are good for parsing identifiers |
| * in Table API. The difference between those identifiers and CompoundIdentifer is |
| * that the Table API identifiers ignore any keywords. They are also strictly limited |
| * to three part identifiers. The quoting still works the same way. |
| */ |
| SqlIdentifier TableApiIdentifier() : |
| { |
| final List<String> nameList = new ArrayList<String>(); |
| final List<SqlParserPos> posList = new ArrayList<SqlParserPos>(); |
| } |
| { |
| TableApiIdentifierSegment(nameList, posList) |
| ( |
| LOOKAHEAD(2) |
| <DOT> |
| TableApiIdentifierSegment(nameList, posList) |
| )? |
| ( |
| LOOKAHEAD(2) |
| <DOT> |
| TableApiIdentifierSegment(nameList, posList) |
| )? |
| <EOF> |
| { |
| SqlParserPos pos = SqlParserPos.sum(posList); |
| return new SqlIdentifier(nameList, null, pos, posList); |
| } |
| } |
| |
| void TableApiIdentifierSegment(List<String> names, List<SqlParserPos> positions) : |
| { |
| final String id; |
| char unicodeEscapeChar = BACKSLASH; |
| final SqlParserPos pos; |
| final Span span; |
| } |
| { |
| ( |
| <QUOTED_IDENTIFIER> { |
| id = SqlParserUtil.strip(getToken(0).image, DQ, DQ, DQDQ, |
| quotedCasing); |
| pos = getPos().withQuoting(true); |
| } |
| | |
| <BACK_QUOTED_IDENTIFIER> { |
| id = SqlParserUtil.strip(getToken(0).image, "`", "`", "``", |
| quotedCasing); |
| pos = getPos().withQuoting(true); |
| } |
| | |
| <BRACKET_QUOTED_IDENTIFIER> { |
| id = SqlParserUtil.strip(getToken(0).image, "[", "]", "]]", |
| quotedCasing); |
| pos = getPos().withQuoting(true); |
| } |
| | |
| <UNICODE_QUOTED_IDENTIFIER> { |
| span = span(); |
| String image = getToken(0).image; |
| image = image.substring(image.indexOf('"')); |
| image = SqlParserUtil.strip(image, DQ, DQ, DQDQ, quotedCasing); |
| } |
| [ |
| <UESCAPE> <QUOTED_STRING> { |
| String s = SqlParserUtil.parseString(token.image); |
| unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s); |
| } |
| ] |
| { |
| pos = span.end(this).withQuoting(true); |
| SqlLiteral lit = SqlLiteral.createCharString(image, "UTF16", pos); |
| lit = lit.unescapeUnicode(unicodeEscapeChar); |
| id = lit.toValue(); |
| } |
| | |
| { |
| |
| id = getNextToken().image; |
| pos = getPos(); |
| } |
| ) |
| { |
| if (id.length() > this.identifierMaxLength) { |
| throw SqlUtil.newContextException(pos, |
| RESOURCE.identifierTooLong(id, this.identifierMaxLength)); |
| } |
| names.add(id); |
| if (positions != null) { |
| positions.add(pos); |
| } |
| } |
| } |
| |
| SqlCreate SqlCreateExtended(Span s, boolean replace) : |
| { |
| final SqlCreate create; |
| boolean isTemporary = false; |
| } |
| { |
| [ |
| <TEMPORARY> { isTemporary = true; } |
| ] |
| ( |
| create = SqlCreateCatalog(s, replace) |
| | |
| create = SqlCreateMaterializedTable(s, replace, isTemporary) |
| | |
| create = SqlCreateTable(s, replace, isTemporary) |
| | |
| create = SqlCreateView(s, replace, isTemporary) |
| | |
| create = SqlCreateDatabase(s, replace) |
| | |
| create = SqlCreateFunction(s, replace, isTemporary) |
| | |
| create = SqlCreateModel(s, isTemporary) |
| ) |
| { |
| return create; |
| } |
| } |
| |
| SqlDrop SqlDropExtended(Span s, boolean replace) : |
| { |
| final SqlDrop drop; |
| boolean isTemporary = false; |
| } |
| { |
| [ |
| <TEMPORARY> { isTemporary = true; } |
| ] |
| ( |
| drop = SqlDropCatalog(s, replace) |
| | |
| drop = SqlDropMaterializedTable(s, replace, isTemporary) |
| | |
| drop = SqlDropTable(s, replace, isTemporary) |
| | |
| drop = SqlDropView(s, replace, isTemporary) |
| | |
| drop = SqlDropDatabase(s, replace) |
| | |
| drop = SqlDropFunction(s, replace, isTemporary) |
| | |
| drop = SqlDropModel(s, isTemporary) |
| ) |
| { |
| return drop; |
| } |
| } |
| |
| /** SHOW PARTITIONS table_name [PARTITION partition_spec]; */ |
| SqlShowPartitions SqlShowPartitions() : |
| { |
| SqlParserPos pos; |
| SqlIdentifier tableIdentifier; |
| SqlNodeList partSpec = null; |
| } |
| { |
| <SHOW> <PARTITIONS> { pos = getPos(); } |
| tableIdentifier = CompoundIdentifier() |
| [ |
| <PARTITION> { |
| partSpec = new SqlNodeList(getPos()); |
| PartitionSpecCommaList(partSpec); |
| } |
| ] |
| { return new SqlShowPartitions(pos, tableIdentifier, partSpec); } |
| } |
| |
| /** |
| * Parses a load module statement. |
| * LOAD MODULE module_name [WITH (property_name=property_value, ...)]; |
| */ |
| SqlLoadModule SqlLoadModule() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier moduleName; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| } |
| { |
| <LOAD> <MODULE> { startPos = getPos(); } |
| moduleName = SimpleIdentifier() |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| { |
| return new SqlLoadModule(startPos.plus(getPos()), |
| moduleName, |
| propertyList); |
| } |
| } |
| |
| /** |
| * Parses an unload module statement. |
| * UNLOAD MODULE module_name; |
| */ |
| SqlUnloadModule SqlUnloadModule() : |
| { |
| SqlParserPos startPos; |
| SqlIdentifier moduleName; |
| } |
| { |
| <UNLOAD> <MODULE> { startPos = getPos(); } |
| moduleName = SimpleIdentifier() |
| { |
| return new SqlUnloadModule(startPos.plus(getPos()), moduleName); |
| } |
| } |
| |
| /** |
| * Parses an use modules statement. |
| * USE MODULES module_name1 [, module_name2, ...]; |
| */ |
| SqlUseModules SqlUseModules() : |
| { |
| final Span s; |
| SqlIdentifier moduleName; |
| final List<SqlIdentifier> moduleNames = new ArrayList<SqlIdentifier>(); |
| } |
| { |
| <USE> <MODULES> { s = span(); } |
| moduleName = SimpleIdentifier() |
| { |
| moduleNames.add(moduleName); |
| } |
| [ |
| ( |
| <COMMA> |
| moduleName = SimpleIdentifier() |
| { |
| moduleNames.add(moduleName); |
| } |
| )+ |
| ] |
| { |
| return new SqlUseModules(s.end(this), moduleNames); |
| } |
| } |
| |
| /** |
| * Parses a show modules statement. |
| * SHOW [FULL] MODULES; |
| */ |
| SqlShowModules SqlShowModules() : |
| { |
| SqlParserPos startPos; |
| boolean requireFull = false; |
| } |
| { |
| <SHOW> { startPos = getPos(); } |
| [ |
| <FULL> { requireFull = true; } |
| ] |
| <MODULES> |
| { |
| return new SqlShowModules(startPos.plus(getPos()), requireFull); |
| } |
| } |
| |
| /** |
| * Parse a start statement set statement. |
| * BEGIN STATEMENT SET; |
| */ |
| SqlBeginStatementSet SqlBeginStatementSet() : |
| { |
| } |
| { |
| <BEGIN> <STATEMENT> <SET> |
| { |
| return new SqlBeginStatementSet(getPos()); |
| } |
| } |
| |
| /** |
| * Parse a end statement set statement. |
| * END; |
| */ |
| SqlEndStatementSet SqlEndStatementSet() : |
| { |
| } |
| { |
| <END> |
| { |
| return new SqlEndStatementSet(getPos()); |
| } |
| } |
| |
| /** |
| * Parse a statement set. |
| * |
| * STATEMENT SET BEGIN (RichSqlInsert();)+ END |
| */ |
| SqlNode SqlStatementSet() : |
| { |
| SqlParserPos startPos; |
| SqlNode insert; |
| List<RichSqlInsert> inserts = new ArrayList<RichSqlInsert>(); |
| } |
| { |
| <STATEMENT>{ startPos = getPos(); } <SET> <BEGIN> |
| ( |
| insert = RichSqlInsert() |
| <SEMICOLON> |
| { |
| inserts.add((RichSqlInsert) insert); |
| } |
| )+ |
| <END> |
| { |
| return new SqlStatementSet(inserts, startPos); |
| } |
| } |
| |
| /** |
| * Parses an explain module statement. |
| */ |
| SqlNode SqlRichExplain() : |
| { |
| SqlNode stmt; |
| Set<String> explainDetails = new HashSet<String>(); |
| } |
| { |
| ( |
| LOOKAHEAD(3) <EXPLAIN> <PLAN> <FOR> |
| | |
| LOOKAHEAD(2) <EXPLAIN> ParseExplainDetail(explainDetails) ( <COMMA> ParseExplainDetail(explainDetails) )* |
| | |
| <EXPLAIN> |
| ) |
| ( |
| stmt = SqlStatementSet() |
| | |
| stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| | |
| stmt = RichSqlInsert() |
| ) |
| { |
| return new SqlRichExplain(getPos(), stmt, explainDetails); |
| } |
| } |
| |
| /** |
| * Parses an execute statement. |
| */ |
| SqlNode SqlExecute() : |
| { |
| SqlParserPos startPos; |
| SqlNode stmt; |
| } |
| { |
| <EXECUTE>{ startPos = getPos(); } |
| ( |
| stmt = SqlStatementSet() |
| | |
| stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| | |
| stmt = RichSqlInsert() |
| ) |
| { |
| return new SqlExecute(stmt, startPos); |
| } |
| } |
| |
| /** |
| * Parses an execute plan statement. |
| */ |
| SqlNode SqlExecutePlan() : |
| { |
| SqlNode filePath; |
| } |
| { |
| <EXECUTE> <PLAN> |
| |
| filePath = StringLiteral() |
| |
| { |
| return new SqlExecutePlan(getPos(), filePath); |
| } |
| } |
| |
| /** |
| * Parses a compile plan statement. |
| */ |
| SqlNode SqlCompileAndExecutePlan() : |
| { |
| SqlParserPos startPos; |
| SqlNode filePath; |
| SqlNode operand; |
| } |
| { |
| <COMPILE> <AND> <EXECUTE> <PLAN> { startPos = getPos(); } |
| |
| filePath = StringLiteral() |
| |
| <FOR> |
| |
| ( |
| operand = SqlStatementSet() |
| | |
| operand = RichSqlInsert() |
| ) |
| |
| { |
| return new SqlCompileAndExecutePlan(startPos, filePath, operand); |
| } |
| } |
| |
| /** |
| * Parses a compile plan statement. |
| */ |
| SqlNode SqlCompilePlan() : |
| { |
| SqlParserPos startPos; |
| SqlNode filePath; |
| boolean ifNotExists; |
| SqlNode operand; |
| } |
| { |
| <COMPILE> <PLAN> { startPos = getPos(); } |
| |
| filePath = StringLiteral() |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| <FOR> |
| |
| ( |
| operand = SqlStatementSet() |
| | |
| operand = RichSqlInsert() |
| ) |
| |
| { |
| return new SqlCompilePlan(startPos, filePath, ifNotExists, operand); |
| } |
| } |
| |
| void ParseExplainDetail(Set<String> explainDetails): |
| { |
| } |
| { |
| ( |
| <ESTIMATED_COST> |
| | |
| <CHANGELOG_MODE> |
| | |
| <JSON_EXECUTION_PLAN> |
| | |
| <PLAN_ADVICE> |
| ) |
| { |
| if (explainDetails.contains(token.image.toUpperCase())) { |
| throw SqlUtil.newContextException( |
| getPos(), |
| ParserResource.RESOURCE.explainDetailIsDuplicate()); |
| } else { |
| explainDetails.add(token.image.toUpperCase()); |
| } |
| } |
| } |
| |
| /** |
| * Parses an ADD JAR statement. |
| */ |
| SqlAddJar SqlAddJar() : |
| { |
| SqlCharStringLiteral jarPath; |
| } |
| { |
| <ADD> <JAR> <QUOTED_STRING> |
| { |
| String path = SqlParserUtil.parseString(token.image); |
| jarPath = SqlLiteral.createCharString(path, getPos()); |
| } |
| { |
| return new SqlAddJar(getPos(), jarPath); |
| } |
| } |
| |
| /** |
| * Parses a remove jar statement. |
| * REMOVE JAR jar_path; |
| */ |
| SqlRemoveJar SqlRemoveJar() : |
| { |
| SqlCharStringLiteral jarPath; |
| } |
| { |
| <REMOVE> <JAR> <QUOTED_STRING> |
| { |
| String path = SqlParserUtil.parseString(token.image); |
| jarPath = SqlLiteral.createCharString(path, getPos()); |
| } |
| { |
| return new SqlRemoveJar(getPos(), jarPath); |
| } |
| } |
| |
| /** |
| * Parses a show jars statement. |
| * SHOW JARS; |
| */ |
| SqlShowJars SqlShowJars() : |
| { |
| } |
| { |
| <SHOW> <JARS> |
| { |
| return new SqlShowJars(getPos()); |
| } |
| } |
| |
| /* |
| * Parses a SET statement: |
| * SET ['key' = 'value']; |
| */ |
| SqlNode SqlSet() : |
| { |
| Span s; |
| SqlNode key = null; |
| SqlNode value = null; |
| } |
| { |
| <SET> { s = span(); } |
| [ |
| key = StringLiteral() |
| <EQ> |
| value = StringLiteral() |
| ] |
| { |
| if (key == null && value == null) { |
| return new SqlSet(s.end(this)); |
| } else { |
| return new SqlSet(s.end(this), key, value); |
| } |
| } |
| } |
| |
| /** |
| * Parses a RESET statement: |
| * RESET ['key']; |
| */ |
| SqlNode SqlReset() : |
| { |
| Span span; |
| SqlNode key = null; |
| } |
| { |
| <RESET> { span = span(); } |
| [ |
| key = StringLiteral() |
| ] |
| { |
| return new SqlReset(span.end(this), key); |
| } |
| } |
| |
| |
| /** Parses a TRY_CAST invocation. */ |
| SqlNode TryCastFunctionCall() : |
| { |
| final Span s; |
| final SqlOperator operator; |
| List<SqlNode> args = null; |
| SqlNode e = null; |
| } |
| { |
| <TRY_CAST> { |
| s = span(); |
| operator = new SqlUnresolvedTryCastFunction(s.pos()); |
| } |
| <LPAREN> |
| e = Expression(ExprContext.ACCEPT_SUB_QUERY) { args = startList(e); } |
| <AS> |
| ( |
| e = DataType() { args.add(e); } |
| | |
| <INTERVAL> e = IntervalQualifier() { args.add(e); } |
| ) |
| <RPAREN> |
| { |
| return operator.createCall(s.end(this), args); |
| } |
| } |
| |
| /** |
| * Parses a partition key/value, |
| * e.g. p or p = '10'. |
| */ |
| SqlPartitionSpecProperty PartitionSpecProperty(): |
| { |
| final SqlParserPos pos; |
| final SqlIdentifier key; |
| SqlNode value = null; |
| } |
| { |
| key = SimpleIdentifier() { pos = getPos(); } |
| [ |
| LOOKAHEAD(1) |
| <EQ> value = Literal() |
| ] |
| { |
| return new SqlPartitionSpecProperty(key, value, pos); |
| } |
| } |
| |
| /** |
| * Parses a partition specifications statement, |
| * e.g. ANALYZE TABLE tbl1 partition(col1='val1', col2='val2') xxx |
| * or |
| * ANALYZE TABLE tbl1 partition(col1, col2) xxx. |
| * or |
| * ANALYZE TABLE tbl1 partition(col1='val1', col2) xxx. |
| */ |
| void ExtendedPartitionSpecCommaList(SqlNodeList list) : |
| { |
| SqlPartitionSpecProperty property; |
| } |
| { |
| <LPAREN> |
| property = PartitionSpecProperty() |
| { |
| list.add(property); |
| } |
| ( |
| <COMMA> property = PartitionSpecProperty() |
| { |
| list.add(property); |
| } |
| )* |
| <RPAREN> |
| } |
| |
| /** Parses a comma-separated list of simple identifiers with position. */ |
| SqlNodeList SimpleIdentifierCommaListWithPosition() : |
| { |
| final Span s; |
| final List<SqlNode> list = new ArrayList<SqlNode>(); |
| } |
| { |
| { s = span(); } |
| AddSimpleIdentifiers(list) { |
| return new SqlNodeList(list, s.end(this)); |
| } |
| } |
| |
| /** Parses an ANALYZE TABLE statement. */ |
| SqlNode SqlAnalyzeTable(): |
| { |
| final Span s; |
| final SqlIdentifier tableName; |
| SqlNodeList partitionSpec = SqlNodeList.EMPTY; |
| SqlNodeList columns = SqlNodeList.EMPTY; |
| boolean allColumns = false; |
| } |
| { |
| <ANALYZE> <TABLE> { s = span(); } |
| tableName = CompoundIdentifier() |
| [ |
| <PARTITION> { |
| partitionSpec = new SqlNodeList(getPos()); |
| ExtendedPartitionSpecCommaList(partitionSpec); |
| } |
| ] |
| |
| <COMPUTE> <STATISTICS> [ <FOR> |
| ( |
| <COLUMNS> { columns = SimpleIdentifierCommaListWithPosition(); } |
| | |
| <ALL> <COLUMNS> { allColumns = true; } |
| ) |
| ] |
| |
| { |
| return new SqlAnalyzeTable(s.end(this), tableName, partitionSpec, columns, allColumns); |
| } |
| } |
| |
| /** |
| * Parse a "SHOW JOBS" statement. |
| */ |
| SqlShowJobs SqlShowJobs() : |
| { |
| } |
| { |
| <SHOW> <JOBS> |
| { |
| return new SqlShowJobs(getPos()); |
| } |
| } |
| |
| /** |
| * Parse a "DESCRIBE JOB" statement: |
| * DESCRIBE | DESC JOB <JOB_ID> |
| */ |
| SqlDescribeJob SqlDescribeJob() : |
| { |
| SqlCharStringLiteral jobId; |
| SqlParserPos pos; |
| } |
| { |
| ( <DESCRIBE> | <DESC> ) <JOB> <QUOTED_STRING> |
| { |
| String id = SqlParserUtil.parseString(token.image); |
| jobId = SqlLiteral.createCharString(id, getPos()); |
| return new SqlDescribeJob(getPos(), jobId); |
| } |
| } |
| |
| /** |
| * Parses a STOP JOB statement: |
| * STOP JOB <JOB_ID> [<WITH SAVEPOINT>] [<WITH DRAIN>]; |
| */ |
| SqlStopJob SqlStopJob() : |
| { |
| SqlCharStringLiteral jobId; |
| boolean isWithSavepoint = false; |
| boolean isWithDrain = false; |
| final Span span; |
| } |
| { |
| <STOP> <JOB> <QUOTED_STRING> |
| { |
| String id = SqlParserUtil.parseString(token.image); |
| jobId = SqlLiteral.createCharString(id, getPos()); |
| } |
| [ |
| LOOKAHEAD(2) |
| <WITH> <SAVEPOINT> |
| { |
| isWithSavepoint = true; |
| } |
| ] |
| [ |
| LOOKAHEAD(2) |
| <WITH> |
| { |
| span = span(); |
| } |
| <DRAIN> |
| { |
| span.end(this); |
| if (!isWithSavepoint) { |
| throw SqlUtil.newContextException(span.pos(), |
| ParserResource.RESOURCE.withDrainOnlyUsedWithSavepoint()); |
| } |
| isWithDrain = true; |
| } |
| ] |
| { |
| return new SqlStopJob(getPos(), jobId, isWithSavepoint, isWithDrain); |
| } |
| } |
| |
| /** |
| * Parses a TRUNCATE TABLE statement. |
| */ |
| SqlTruncateTable SqlTruncateTable() : |
| { |
| SqlIdentifier sqlIdentifier; |
| } |
| { |
| <TRUNCATE> <TABLE> |
| sqlIdentifier = CompoundIdentifier() |
| { |
| return new SqlTruncateTable(getPos(), sqlIdentifier); |
| } |
| } |
| |
| /** |
| * SHOW MODELS [FROM [catalog.] database] sql call. |
| */ |
| SqlShowModels SqlShowModels() : |
| { |
| SqlIdentifier databaseName = null; |
| SqlCharStringLiteral likeLiteral = null; |
| String prep = null; |
| boolean notLike = false; |
| SqlParserPos pos; |
| } |
| { |
| <SHOW> <MODELS> |
| { pos = getPos(); } |
| [ |
| ( <FROM> { prep = "FROM"; } | <IN> { prep = "IN"; } ) |
| { pos = getPos(); } |
| databaseName = CompoundIdentifier() |
| ] |
| [ |
| [ |
| <NOT> |
| { |
| notLike = true; |
| } |
| ] |
| <LIKE> <QUOTED_STRING> |
| { |
| String likeCondition = SqlParserUtil.parseString(token.image); |
| likeLiteral = SqlLiteral.createCharString(likeCondition, getPos()); |
| } |
| ] |
| { |
| return new SqlShowModels(pos, prep, databaseName, notLike, likeLiteral); |
| } |
| } |
| |
| /** |
| * ALTER MODEL [IF EXISTS] modelName SET (property_key = property_val, ...) |
| * ALTER MODEL [IF EXISTS] modelName RENAME TO newModelName |
| */ |
| SqlAlterModel SqlAlterModel() : |
| { |
| SqlParserPos startPos; |
| boolean ifExists = false; |
| SqlIdentifier modelIdentifier; |
| SqlIdentifier newModelIdentifier = null; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| } |
| { |
| <ALTER> <MODEL> { startPos = getPos(); } |
| ifExists = IfExistsOpt() |
| modelIdentifier = CompoundIdentifier() |
| ( |
| LOOKAHEAD(2) |
| <RENAME> <TO> |
| newModelIdentifier = CompoundIdentifier() |
| { |
| return new SqlAlterModel( |
| startPos.plus(getPos()), |
| modelIdentifier, |
| newModelIdentifier, |
| ifExists); |
| } |
| | |
| <SET> |
| propertyList = Properties() |
| { |
| return new SqlAlterModel( |
| startPos.plus(getPos()), |
| modelIdentifier, |
| propertyList, |
| ifExists); |
| } |
| ) |
| } |
| |
| /** |
| * DROP MODEL [IF EXIST] modelName |
| */ |
| SqlDrop SqlDropModel(Span s, boolean isTemporary) : |
| { |
| SqlIdentifier modelIdentifier = null; |
| boolean ifExists = false; |
| } |
| { |
| <MODEL> |
| |
| ifExists = IfExistsOpt() |
| |
| modelIdentifier = CompoundIdentifier() |
| |
| { |
| return new SqlDropModel(s.pos(), modelIdentifier, ifExists, isTemporary); |
| } |
| } |
| |
| /** |
| * CREATE MODEL [IF NOT EXIST] modelName |
| * [INPUT(col1 type1, col2 type2, ...)] |
| * [OUTPUT(col3 type1, col4 type4, ...)] |
| * [COMMENT model_comment] |
| * WITH (option_key = option_val, ...) |
| * [AS SELECT ...] |
| */ |
| SqlCreate SqlCreateModel(Span s, boolean isTemporary) : |
| { |
| final SqlParserPos startPos = s.pos(); |
| boolean ifNotExists = false; |
| SqlIdentifier modelIdentifier; |
| SqlNodeList inputColumnList = SqlNodeList.EMPTY; |
| SqlNodeList outputColumnList = SqlNodeList.EMPTY; |
| SqlCharStringLiteral comment = null; |
| SqlNodeList propertyList = SqlNodeList.EMPTY; |
| SqlNode asQuery = null; |
| SqlParserPos pos = startPos; |
| } |
| { |
| <MODEL> |
| |
| ifNotExists = IfNotExistsOpt() |
| |
| modelIdentifier = CompoundIdentifier() |
| [ |
| <INPUT> <LPAREN> { pos = getPos(); TableCreationContext ctx = new TableCreationContext();} |
| TableColumn(ctx) |
| ( |
| <COMMA> TableColumn(ctx) |
| )* |
| { |
| pos = pos.plus(getPos()); |
| inputColumnList = new SqlNodeList(ctx.columnList, pos); |
| } |
| <RPAREN> |
| ] |
| [ |
| <OUTPUT> <LPAREN> { pos = getPos(); TableCreationContext ctx = new TableCreationContext();} |
| TableColumn(ctx) |
| ( |
| <COMMA> TableColumn(ctx) |
| )* |
| { |
| pos = pos.plus(getPos()); |
| outputColumnList = new SqlNodeList(ctx.columnList, pos); |
| } |
| <RPAREN> |
| ] |
| [ <COMMENT> <QUOTED_STRING> |
| { |
| String p = SqlParserUtil.parseString(token.image); |
| comment = SqlLiteral.createCharString(p, getPos()); |
| } |
| ] |
| [ |
| <WITH> |
| propertyList = Properties() |
| ] |
| [ |
| <AS> |
| asQuery = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) |
| { |
| return new SqlCreateModelAs(startPos.plus(getPos()), |
| modelIdentifier, |
| comment, |
| inputColumnList, |
| outputColumnList, |
| propertyList, |
| asQuery, |
| isTemporary, |
| ifNotExists); |
| } |
| ] |
| { |
| return new SqlCreateModel(startPos.plus(getPos()), |
| modelIdentifier, |
| comment, |
| inputColumnList, |
| outputColumnList, |
| propertyList, |
| isTemporary, |
| ifNotExists); |
| } |
| } |