ClickHouse/utils/antlr/ClickHouseParser.g4

492 lines
26 KiB
ANTLR

parser grammar ClickHouseParser;
options {
tokenVocab = ClickHouseLexer;
}
// Top-level statements
queryStmt: query (INTO OUTFILE STRING_LITERAL)? (FORMAT identifierOrNull)? (SEMICOLON)? | insertStmt;
query
: alterStmt // DDL
| attachStmt // DDL
| checkStmt
| createStmt // DDL
| describeStmt
| dropStmt // DDL
| existsStmt
| explainStmt
| killStmt // DDL
| optimizeStmt // DDL
| renameStmt // DDL
| selectUnionStmt
| setStmt
| showStmt
| systemStmt
| truncateStmt // DDL
| useStmt
| watchStmt
;
// ALTER statement
alterStmt
: ALTER TABLE tableIdentifier clusterClause? alterTableClause (COMMA alterTableClause)* # AlterTableStmt
;
alterTableClause
: ADD COLUMN (IF NOT EXISTS)? tableColumnDfnt (AFTER nestedIdentifier)? # AlterTableClauseAddColumn
| ADD INDEX (IF NOT EXISTS)? tableIndexDfnt (AFTER nestedIdentifier)? # AlterTableClauseAddIndex
| ADD PROJECTION (IF NOT EXISTS)? tableProjectionDfnt (AFTER nestedIdentifier)? # AlterTableClauseAddProjection
| ATTACH partitionClause (FROM tableIdentifier)? # AlterTableClauseAttach
| CLEAR COLUMN (IF EXISTS)? nestedIdentifier (IN partitionClause)? # AlterTableClauseClearColumn
| CLEAR INDEX (IF EXISTS)? nestedIdentifier (IN partitionClause)? # AlterTableClauseClearIndex
| CLEAR PROJECTION (IF EXISTS)? nestedIdentifier (IN partitionClause)? # AlterTableClauseClearProjection
| COMMENT COLUMN (IF EXISTS)? nestedIdentifier STRING_LITERAL # AlterTableClauseComment
| DELETE WHERE columnExpr # AlterTableClauseDelete
| DETACH partitionClause # AlterTableClauseDetach
| DROP COLUMN (IF EXISTS)? nestedIdentifier # AlterTableClauseDropColumn
| DROP INDEX (IF EXISTS)? nestedIdentifier # AlterTableClauseDropIndex
| DROP PROJECTION (IF EXISTS)? nestedIdentifier # AlterTableClauseDropProjection
| DROP partitionClause # AlterTableClauseDropPartition
| FREEZE partitionClause? # AlterTableClauseFreezePartition
| MATERIALIZE INDEX (IF EXISTS)? nestedIdentifier (IN partitionClause)? # AlterTableClauseMaterializeIndex
| MATERIALIZE PROJECTION (IF EXISTS)? nestedIdentifier (IN partitionClause)? # AlterTableClauseMaterializeProjection
| MODIFY COLUMN (IF EXISTS)? nestedIdentifier codecExpr # AlterTableClauseModifyCodec
| MODIFY COLUMN (IF EXISTS)? nestedIdentifier COMMENT STRING_LITERAL # AlterTableClauseModifyComment
| MODIFY COLUMN (IF EXISTS)? nestedIdentifier REMOVE tableColumnPropertyType # AlterTableClauseModifyRemove
| MODIFY COLUMN (IF EXISTS)? tableColumnDfnt # AlterTableClauseModify
| MODIFY ORDER BY columnExpr # AlterTableClauseModifyOrderBy
| MODIFY ttlClause # AlterTableClauseModifyTTL
| MOVE partitionClause ( TO DISK STRING_LITERAL
| TO VOLUME STRING_LITERAL
| TO TABLE tableIdentifier
) # AlterTableClauseMovePartition
| REMOVE TTL # AlterTableClauseRemoveTTL
| RENAME COLUMN (IF EXISTS)? nestedIdentifier TO nestedIdentifier # AlterTableClauseRename
| REPLACE partitionClause FROM tableIdentifier # AlterTableClauseReplace
| UPDATE assignmentExprList whereClause # AlterTableClauseUpdate
;
assignmentExprList: assignmentExpr (COMMA assignmentExpr)*;
assignmentExpr: nestedIdentifier EQ_SINGLE columnExpr;
tableColumnPropertyType: ALIAS | CODEC | COMMENT | DEFAULT | MATERIALIZED | TTL;
partitionClause
: PARTITION columnExpr // actually we expect here any form of tuple of literals
| PARTITION ID STRING_LITERAL
;
// ATTACH statement
attachStmt
: ATTACH DICTIONARY tableIdentifier clusterClause? # AttachDictionaryStmt
;
// CHECK statement
checkStmt: CHECK TABLE tableIdentifier partitionClause?;
// CREATE statement
createStmt
: (ATTACH | CREATE) DATABASE (IF NOT EXISTS)? databaseIdentifier clusterClause? engineExpr? # CreateDatabaseStmt
| (ATTACH | CREATE (OR REPLACE)? | REPLACE) DICTIONARY (IF NOT EXISTS)? tableIdentifier uuidClause? clusterClause? dictionarySchemaClause dictionaryEngineClause # CreateDictionaryStmt
| (ATTACH | CREATE) LIVE VIEW (IF NOT EXISTS)? tableIdentifier uuidClause? clusterClause? (WITH TIMEOUT DECIMAL_LITERAL?)? destinationClause? tableSchemaClause? subqueryClause # CreateLiveViewStmt
| (ATTACH | CREATE) MATERIALIZED VIEW (IF NOT EXISTS)? tableIdentifier uuidClause? clusterClause? tableSchemaClause? (destinationClause | engineClause POPULATE?) subqueryClause # CreateMaterializedViewStmt
| (ATTACH | CREATE (OR REPLACE)? | REPLACE) TEMPORARY? TABLE (IF NOT EXISTS)? tableIdentifier uuidClause? clusterClause? tableSchemaClause? engineClause? subqueryClause? # CreateTableStmt
| (ATTACH | CREATE) (OR REPLACE)? VIEW (IF NOT EXISTS)? tableIdentifier uuidClause? clusterClause? tableSchemaClause? subqueryClause # CreateViewStmt
;
dictionarySchemaClause: LPAREN dictionaryAttrDfnt (COMMA dictionaryAttrDfnt)* RPAREN;
dictionaryAttrDfnt
locals [std::set<std::string> attrs]:
identifier columnTypeExpr
( {!$attrs.count("default")}? DEFAULT literal {$attrs.insert("default");}
| {!$attrs.count("expression")}? EXPRESSION columnExpr {$attrs.insert("expression");}
| {!$attrs.count("hierarchical")}? HIERARCHICAL {$attrs.insert("hierarchical");}
| {!$attrs.count("injective")}? INJECTIVE {$attrs.insert("injective");}
| {!$attrs.count("is_object_id")}? IS_OBJECT_ID {$attrs.insert("is_object_id");}
)*
;
dictionaryEngineClause
locals [std::set<std::string> clauses]:
dictionaryPrimaryKeyClause?
( {!$clauses.count("source")}? sourceClause {$clauses.insert("source");}
| {!$clauses.count("lifetime")}? lifetimeClause {$clauses.insert("lifetime");}
| {!$clauses.count("layout")}? layoutClause {$clauses.insert("layout");}
| {!$clauses.count("range")}? rangeClause {$clauses.insert("range");}
| {!$clauses.count("settings")}? dictionarySettingsClause {$clauses.insert("settings");}
)*
;
dictionaryPrimaryKeyClause: PRIMARY KEY columnExprList;
dictionaryArgExpr: identifier (identifier (LPAREN RPAREN)? | literal);
sourceClause: SOURCE LPAREN identifier LPAREN dictionaryArgExpr* RPAREN RPAREN;
lifetimeClause: LIFETIME LPAREN ( DECIMAL_LITERAL
| MIN DECIMAL_LITERAL MAX DECIMAL_LITERAL
| MAX DECIMAL_LITERAL MIN DECIMAL_LITERAL
) RPAREN;
layoutClause: LAYOUT LPAREN identifier LPAREN dictionaryArgExpr* RPAREN RPAREN;
rangeClause: RANGE LPAREN (MIN identifier MAX identifier | MAX identifier MIN identifier) RPAREN;
dictionarySettingsClause: SETTINGS LPAREN settingExprList RPAREN;
clusterClause: ON CLUSTER (identifier | STRING_LITERAL);
uuidClause: UUID STRING_LITERAL;
destinationClause: TO tableIdentifier;
subqueryClause: AS selectUnionStmt;
tableSchemaClause
: LPAREN tableElementExpr (COMMA tableElementExpr)* RPAREN # SchemaDescriptionClause
| AS tableIdentifier # SchemaAsTableClause
| AS tableFunctionExpr # SchemaAsFunctionClause
;
engineClause
locals [std::set<std::string> clauses]:
engineExpr
( {!$clauses.count("orderByClause")}? orderByClause {$clauses.insert("orderByClause");}
| {!$clauses.count("partitionByClause")}? partitionByClause {$clauses.insert("partitionByClause");}
| {!$clauses.count("primaryKeyClause")}? primaryKeyClause {$clauses.insert("primaryKeyClause");}
| {!$clauses.count("sampleByClause")}? sampleByClause {$clauses.insert("sampleByClause");}
| {!$clauses.count("ttlClause")}? ttlClause {$clauses.insert("ttlClause");}
| {!$clauses.count("settingsClause")}? settingsClause {$clauses.insert("settingsClause");}
)*
;
partitionByClause: PARTITION BY columnExpr;
primaryKeyClause: PRIMARY KEY columnExpr;
sampleByClause: SAMPLE BY columnExpr;
ttlClause: TTL ttlExpr (COMMA ttlExpr)*;
engineExpr: ENGINE EQ_SINGLE? identifierOrNull (LPAREN columnExprList? RPAREN)?;
tableElementExpr
: tableColumnDfnt # TableElementExprColumn
| CONSTRAINT identifier CHECK columnExpr # TableElementExprConstraint
| INDEX tableIndexDfnt # TableElementExprIndex
| PROJECTION tableProjectionDfnt # TableElementExprProjection
;
tableColumnDfnt
: nestedIdentifier columnTypeExpr tableColumnPropertyExpr? (COMMENT STRING_LITERAL)? codecExpr? (TTL columnExpr)?
| nestedIdentifier columnTypeExpr? tableColumnPropertyExpr (COMMENT STRING_LITERAL)? codecExpr? (TTL columnExpr)?
;
tableColumnPropertyExpr: (DEFAULT | MATERIALIZED | ALIAS) columnExpr;
tableIndexDfnt: nestedIdentifier columnExpr TYPE columnTypeExpr GRANULARITY DECIMAL_LITERAL;
tableProjectionDfnt: nestedIdentifier projectionSelectStmt;
codecExpr: CODEC LPAREN codecArgExpr (COMMA codecArgExpr)* RPAREN;
codecArgExpr: identifier (LPAREN columnExprList? RPAREN)?;
ttlExpr: columnExpr (DELETE | TO DISK STRING_LITERAL | TO VOLUME STRING_LITERAL)?;
// DESCRIBE statement
describeStmt: (DESCRIBE | DESC) TABLE? tableExpr;
// DROP statement
dropStmt
: (DETACH | DROP) DATABASE (IF EXISTS)? databaseIdentifier clusterClause? # DropDatabaseStmt
| (DETACH | DROP) (DICTIONARY | TEMPORARY? TABLE | VIEW) (IF EXISTS)? tableIdentifier clusterClause? (NO DELAY)? # DropTableStmt
;
// EXISTS statement
existsStmt
: EXISTS DATABASE databaseIdentifier # ExistsDatabaseStmt
| EXISTS (DICTIONARY | TEMPORARY? TABLE | VIEW)? tableIdentifier # ExistsTableStmt
;
// EXPLAIN statement
explainStmt
: EXPLAIN AST query # ExplainASTStmt
| EXPLAIN SYNTAX query # ExplainSyntaxStmt
;
// INSERT statement
insertStmt: INSERT INTO TABLE? (tableIdentifier | FUNCTION tableFunctionExpr) columnsClause? dataClause;
columnsClause: LPAREN nestedIdentifier (COMMA nestedIdentifier)* RPAREN;
dataClause
: FORMAT identifier # DataClauseFormat
| VALUES # DataClauseValues
| selectUnionStmt SEMICOLON? EOF # DataClauseSelect
;
// KILL statement
killStmt
: KILL MUTATION clusterClause? whereClause (SYNC | ASYNC | TEST)? # KillMutationStmt
;
// OPTIMIZE statement
optimizeStmt: OPTIMIZE TABLE tableIdentifier clusterClause? partitionClause? FINAL? DEDUPLICATE?;
// RENAME statement
renameStmt: RENAME TABLE tableIdentifier TO tableIdentifier (COMMA tableIdentifier TO tableIdentifier)* clusterClause?;
// PROJECTION SELECT statement
projectionSelectStmt:
LPAREN
withClause?
SELECT columnExprList
groupByClause?
projectionOrderByClause?
RPAREN
;
// SELECT statement
selectUnionStmt: selectStmtWithParens (UNION ALL selectStmtWithParens)*;
selectStmtWithParens: selectStmt | LPAREN selectUnionStmt RPAREN;
selectStmt:
withClause?
SELECT DISTINCT? topClause? columnExprList
fromClause?
arrayJoinClause?
windowClause?
prewhereClause?
whereClause?
groupByClause? (WITH (CUBE | ROLLUP))? (WITH TOTALS)?
havingClause?
orderByClause?
limitByClause?
limitClause?
settingsClause?
;
withClause: WITH columnExprList;
topClause: TOP DECIMAL_LITERAL (WITH TIES)?;
fromClause: FROM joinExpr;
arrayJoinClause: (LEFT | INNER)? ARRAY JOIN columnExprList;
windowClause: WINDOW identifier AS LPAREN windowExpr RPAREN;
prewhereClause: PREWHERE columnExpr;
whereClause: WHERE columnExpr;
groupByClause: GROUP BY ((CUBE | ROLLUP) LPAREN columnExprList RPAREN | columnExprList);
havingClause: HAVING columnExpr;
orderByClause: ORDER BY orderExprList;
projectionOrderByClause: ORDER BY columnExprList;
limitByClause: LIMIT limitExpr BY columnExprList;
limitClause: LIMIT limitExpr (WITH TIES)?;
settingsClause: SETTINGS settingExprList;
joinExpr
: joinExpr (GLOBAL | LOCAL)? joinOp? JOIN joinExpr joinConstraintClause # JoinExprOp
| joinExpr joinOpCross joinExpr # JoinExprCrossOp
| tableExpr FINAL? sampleClause? # JoinExprTable
| LPAREN joinExpr RPAREN # JoinExprParens
;
joinOp
: ((ALL | ANY | ASOF)? INNER | INNER (ALL | ANY | ASOF)? | (ALL | ANY | ASOF)) # JoinOpInner
| ( (SEMI | ALL | ANTI | ANY | ASOF)? (LEFT | RIGHT) OUTER?
| (LEFT | RIGHT) OUTER? (SEMI | ALL | ANTI | ANY | ASOF)?
) # JoinOpLeftRight
| ((ALL | ANY)? FULL OUTER? | FULL OUTER? (ALL | ANY)?) # JoinOpFull
;
joinOpCross
: (GLOBAL|LOCAL)? CROSS JOIN
| COMMA
;
joinConstraintClause
: ON columnExprList
| USING LPAREN columnExprList RPAREN
| USING columnExprList
;
sampleClause: SAMPLE ratioExpr (OFFSET ratioExpr)?;
limitExpr: columnExpr ((COMMA | OFFSET) columnExpr)?;
orderExprList: orderExpr (COMMA orderExpr)*;
orderExpr: columnExpr (ASCENDING | DESCENDING | DESC)? (NULLS (FIRST | LAST))? (COLLATE STRING_LITERAL)?;
ratioExpr: numberLiteral (SLASH numberLiteral)?;
settingExprList: settingExpr (COMMA settingExpr)*;
settingExpr: identifier EQ_SINGLE literal;
windowExpr: winPartitionByClause? winOrderByClause? winFrameClause?;
winPartitionByClause: PARTITION BY columnExprList;
winOrderByClause: ORDER BY orderExprList;
winFrameClause: (ROWS | RANGE) winFrameExtend;
winFrameExtend
: winFrameBound # frameStart
| BETWEEN winFrameBound AND winFrameBound # frameBetween
;
winFrameBound: (CURRENT ROW | UNBOUNDED PRECEDING | UNBOUNDED FOLLOWING | numberLiteral PRECEDING | numberLiteral FOLLOWING);
//rangeClause: RANGE LPAREN (MIN identifier MAX identifier | MAX identifier MIN identifier) RPAREN;
// SET statement
setStmt: SET settingExprList;
// SHOW statements
showStmt
: SHOW CREATE DATABASE databaseIdentifier # showCreateDatabaseStmt
| SHOW CREATE DICTIONARY tableIdentifier # showCreateDictionaryStmt
| SHOW CREATE TEMPORARY? TABLE? tableIdentifier # showCreateTableStmt
| SHOW DATABASES # showDatabasesStmt
| SHOW DICTIONARIES (FROM databaseIdentifier)? # showDictionariesStmt
| SHOW TEMPORARY? TABLES ((FROM | IN) databaseIdentifier)? (LIKE STRING_LITERAL | whereClause)? limitClause? # showTablesStmt
;
// SYSTEM statements
systemStmt
: SYSTEM FLUSH DISTRIBUTED tableIdentifier
| SYSTEM FLUSH LOGS
| SYSTEM RELOAD DICTIONARIES
| SYSTEM RELOAD DICTIONARY tableIdentifier
| SYSTEM (START | STOP) (DISTRIBUTED SENDS | FETCHES | TTL? MERGES) tableIdentifier
| SYSTEM (START | STOP) REPLICATED SENDS
| SYSTEM SYNC REPLICA tableIdentifier
;
// TRUNCATE statements
truncateStmt: TRUNCATE TEMPORARY? TABLE? (IF EXISTS)? tableIdentifier clusterClause?;
// USE statement
useStmt: USE databaseIdentifier;
// WATCH statement
watchStmt: WATCH tableIdentifier EVENTS? (LIMIT DECIMAL_LITERAL)?;
// Columns
columnTypeExpr
: identifier # ColumnTypeExprSimple // UInt64
| identifier LPAREN identifier columnTypeExpr (COMMA identifier columnTypeExpr)* RPAREN # ColumnTypeExprNested // Nested
| identifier LPAREN enumValue (COMMA enumValue)* RPAREN # ColumnTypeExprEnum // Enum
| identifier LPAREN columnTypeExpr (COMMA columnTypeExpr)* RPAREN # ColumnTypeExprComplex // Array, Tuple
| identifier LPAREN columnExprList? RPAREN # ColumnTypeExprParam // FixedString(N)
;
columnExprList: columnsExpr (COMMA columnsExpr)*;
columnsExpr
: (tableIdentifier DOT)? ASTERISK # ColumnsExprAsterisk
| LPAREN selectUnionStmt RPAREN # ColumnsExprSubquery
// NOTE: asterisk and subquery goes before |columnExpr| so that we can mark them as multi-column expressions.
| columnExpr # ColumnsExprColumn
;
columnExpr
: CASE columnExpr? (WHEN columnExpr THEN columnExpr)+ (ELSE columnExpr)? END # ColumnExprCase
| CAST LPAREN columnExpr AS columnTypeExpr RPAREN # ColumnExprCast
| DATE STRING_LITERAL # ColumnExprDate
| EXTRACT LPAREN interval FROM columnExpr RPAREN # ColumnExprExtract
| INTERVAL columnExpr interval # ColumnExprInterval
| SUBSTRING LPAREN columnExpr FROM columnExpr (FOR columnExpr)? RPAREN # ColumnExprSubstring
| TIMESTAMP STRING_LITERAL # ColumnExprTimestamp
| TRIM LPAREN (BOTH | LEADING | TRAILING) STRING_LITERAL FROM columnExpr RPAREN # ColumnExprTrim
| identifier (LPAREN columnExprList? RPAREN) OVER LPAREN windowExpr RPAREN # ColumnExprWinFunction
| identifier (LPAREN columnExprList? RPAREN) OVER identifier # ColumnExprWinFunctionTarget
| identifier (LPAREN columnExprList? RPAREN)? LPAREN DISTINCT? columnArgList? RPAREN # ColumnExprFunction
| literal # ColumnExprLiteral
// FIXME(ilezhankin): this part looks very ugly, maybe there is another way to express it
| columnExpr LBRACKET columnExpr RBRACKET # ColumnExprArrayAccess
| columnExpr DOT DECIMAL_LITERAL # ColumnExprTupleAccess
| DASH columnExpr # ColumnExprNegate
| columnExpr ( ASTERISK // multiply
| SLASH // divide
| PERCENT // modulo
) columnExpr # ColumnExprPrecedence1
| columnExpr ( PLUS // plus
| DASH // minus
| CONCAT // concat
) columnExpr # ColumnExprPrecedence2
| columnExpr ( EQ_DOUBLE // equals
| EQ_SINGLE // equals
| NOT_EQ // notEquals
| LE // lessOrEquals
| GE // greaterOrEquals
| LT // less
| GT // greater
| GLOBAL? NOT? IN // in, notIn, globalIn, globalNotIn
| NOT? (LIKE | ILIKE) // like, notLike, ilike, notILike
) columnExpr # ColumnExprPrecedence3
| columnExpr IS NOT? NULL_SQL # ColumnExprIsNull
| NOT columnExpr # ColumnExprNot
| columnExpr AND columnExpr # ColumnExprAnd
| columnExpr OR columnExpr # ColumnExprOr
// TODO(ilezhankin): `BETWEEN a AND b AND c` is parsed in a wrong way: `BETWEEN (a AND b) AND c`
| columnExpr NOT? BETWEEN columnExpr AND columnExpr # ColumnExprBetween
| <assoc=right> columnExpr QUERY columnExpr COLON columnExpr # ColumnExprTernaryOp
| columnExpr (alias | AS identifier) # ColumnExprAlias
| (tableIdentifier DOT)? ASTERISK # ColumnExprAsterisk // single-column only
| LPAREN selectUnionStmt RPAREN # ColumnExprSubquery // single-column only
| LPAREN columnExpr RPAREN # ColumnExprParens // single-column only
| LPAREN columnExprList RPAREN # ColumnExprTuple
| LBRACKET columnExprList? RBRACKET # ColumnExprArray
| columnIdentifier # ColumnExprIdentifier
;
columnArgList: columnArgExpr (COMMA columnArgExpr)*;
columnArgExpr: columnLambdaExpr | columnExpr;
columnLambdaExpr:
( LPAREN identifier (COMMA identifier)* RPAREN
| identifier (COMMA identifier)*
)
ARROW columnExpr
;
columnIdentifier: (tableIdentifier DOT)? nestedIdentifier;
nestedIdentifier: identifier (DOT identifier)?;
// Tables
tableExpr
: tableIdentifier # TableExprIdentifier
| tableFunctionExpr # TableExprFunction
| LPAREN selectUnionStmt RPAREN # TableExprSubquery
| tableExpr (alias | AS identifier) # TableExprAlias
;
tableFunctionExpr: identifier LPAREN tableArgList? RPAREN;
tableIdentifier: (databaseIdentifier DOT)? identifier;
tableArgList: tableArgExpr (COMMA tableArgExpr)*;
tableArgExpr
: nestedIdentifier
| tableFunctionExpr
| literal
;
// Databases
databaseIdentifier: identifier;
// Basics
floatingLiteral
: FLOATING_LITERAL
| DOT (DECIMAL_LITERAL | OCTAL_LITERAL)
| DECIMAL_LITERAL DOT (DECIMAL_LITERAL | OCTAL_LITERAL)? // can't move this to the lexer or it will break nested tuple access: t.1.2
;
numberLiteral: (PLUS | DASH)? (floatingLiteral | OCTAL_LITERAL | DECIMAL_LITERAL | HEXADECIMAL_LITERAL | INF | NAN_SQL);
literal
: numberLiteral
| STRING_LITERAL
| NULL_SQL
;
interval: SECOND | MINUTE | HOUR | DAY | WEEK | MONTH | QUARTER | YEAR;
keyword
// except NULL_SQL, INF, NAN_SQL
: AFTER | ALIAS | ALL | ALTER | AND | ANTI | ANY | ARRAY | AS | ASCENDING | ASOF | AST | ASYNC | ATTACH | BETWEEN | BOTH | BY | CASE
| CAST | CHECK | CLEAR | CLUSTER | CODEC | COLLATE | COLUMN | COMMENT | CONSTRAINT | CREATE | CROSS | CUBE | CURRENT | DATABASE
| DATABASES | DATE | DEDUPLICATE | DEFAULT | DELAY | DELETE | DESCRIBE | DESC | DESCENDING | DETACH | DICTIONARIES | DICTIONARY | DISK
| DISTINCT | DISTRIBUTED | DROP | ELSE | END | ENGINE | EVENTS | EXISTS | EXPLAIN | EXPRESSION | EXTRACT | FETCHES | FINAL | FIRST
| FLUSH | FOR | FOLLOWING | FOR | FORMAT | FREEZE | FROM | FULL | FUNCTION | GLOBAL | GRANULARITY | GROUP | HAVING | HIERARCHICAL | ID
| IF | ILIKE | IN | INDEX | INJECTIVE | INNER | INSERT | INTERVAL | INTO | IS | IS_OBJECT_ID | JOIN | JSON_FALSE | JSON_TRUE | KEY
| KILL | LAST | LAYOUT | LEADING | LEFT | LIFETIME | LIKE | LIMIT | LIVE | LOCAL | LOGS | MATERIALIZE | MATERIALIZED | MAX | MERGES
| MIN | MODIFY | MOVE | MUTATION | NO | NOT | NULLS | OFFSET | ON | OPTIMIZE | OR | ORDER | OUTER | OUTFILE | OVER | PARTITION
| POPULATE | PRECEDING | PREWHERE | PRIMARY | RANGE | RELOAD | REMOVE | RENAME | REPLACE | REPLICA | REPLICATED | RIGHT | ROLLUP | ROW
| ROWS | SAMPLE | SELECT | SEMI | SENDS | SET | SETTINGS | SHOW | SOURCE | START | STOP | SUBSTRING | SYNC | SYNTAX | SYSTEM | TABLE
| TABLES | TEMPORARY | TEST | THEN | TIES | TIMEOUT | TIMESTAMP | TOTALS | TRAILING | TRIM | TRUNCATE | TO | TOP | TTL | TYPE
| UNBOUNDED | UNION | UPDATE | USE | USING | UUID | VALUES | VIEW | VOLUME | WATCH | WHEN | WHERE | WINDOW | WITH
;
keywordForAlias
: DATE | FIRST | ID | KEY
;
alias: IDENTIFIER | keywordForAlias; // |interval| can't be an alias, otherwise 'INTERVAL 1 SOMETHING' becomes ambiguous.
identifier: IDENTIFIER | interval | keyword;
identifierOrNull: identifier | NULL_SQL; // NULL_SQL can be only 'Null' here.
enumValue: STRING_LITERAL EQ_SINGLE numberLiteral;