diff --git a/pard-parser/README.md b/pard-parser/README.md new file mode 100644 index 0000000..212607e --- /dev/null +++ b/pard-parser/README.md @@ -0,0 +1,45 @@ +## SQL Parser +### SQL SYNTAX +#### PARTITION +We support three kinds of partitions. +1. Range partition. +2. List partition. +3. Hash partition. +##### RANGE PARTITION +```sql +CREATE TABLE orders_range +( +id INT PRIMARY KEY, +name VARCHAR(30), +order_date DATE, +) PARTITION BY RANGE(id) +( +p0 VALUES LESS THAN (5), +p1 VALUES LESS THAN (10), +p2 VALUES LESS THAN (15), +p3 VALUES LESS THAN (MAXVALUE) +); +``` +##### LIST PARTITION +```sql +CREATE TABLE orders_range +( +id INT PRIMARY KEY, +name VARCHAR(30), +order_date DATE, +) PARTITION BY LIST(id) +( +p0 VALUES IN (1, 2, 3), +p1 VALUES IN (4, 5), +p2 VALUES IN (8, 9, 10) +); +``` +##### HASH PARTITION +```sql +CREATE TABLE orders_range +( +id INT PRIMARY KEY, +name VARCHAR(30), +order_date DATE, +) PARTITION BY HASH(id) PARTITIONS 4; +``` \ No newline at end of file diff --git a/pard-parser/src/main/antlr4/cn/edu/ruc/iir/pard/sql/parser/PardSqlBase.g4 b/pard-parser/src/main/antlr4/cn/edu/ruc/iir/pard/sql/parser/PardSqlBase.g4 new file mode 100644 index 0000000..ea7c72f --- /dev/null +++ b/pard-parser/src/main/antlr4/cn/edu/ruc/iir/pard/sql/parser/PardSqlBase.g4 @@ -0,0 +1,738 @@ + +grammar PardSqlBase; + +tokens { + DELIMITER +} + +singleStatement + : statement EOF + ; + +singleExpression + : expression EOF + ; + +statement + : query #statementDefault + | USE schema=identifier #use + | USE catalog=identifier '.' schema=identifier #use + | CREATE SCHEMA (IF NOT EXISTS)? qualifiedName + (WITH properties)? #createSchema + | DROP SCHEMA (IF EXISTS)? qualifiedName (CASCADE | RESTRICT)? #dropSchema + | ALTER SCHEMA qualifiedName RENAME TO identifier #renameSchema + | CREATE TABLE (IF NOT EXISTS)? qualifiedName + tableElementPart + (',' tableElementPart)* + partitionOps? #createTable + | DROP TABLE (IF EXISTS)? qualifiedName #dropTable + | INSERT INTO qualifiedName columnAliases? query #insertInto + | DELETE FROM qualifiedName (WHERE booleanExpression)? #delete + | ALTER TABLE from=qualifiedName RENAME TO to=qualifiedName #renameTable + | ALTER TABLE tableName=qualifiedName + RENAME COLUMN from=identifier TO to=identifier #renameColumn + | ALTER TABLE tableName=qualifiedName + DROP COLUMN column=qualifiedName #dropColumn + | ALTER TABLE tableName=qualifiedName + ADD COLUMN column=columnDefinition #addColumn + | GRANT + (privilege (',' privilege)* | ALL PRIVILEGES) + ON TABLE? qualifiedName TO grantee=identifier + (WITH GRANT OPTION)? #grant + | REVOKE + (GRANT OPTION FOR)? + (privilege (',' privilege)* | ALL PRIVILEGES) + ON TABLE? qualifiedName FROM grantee=identifier #revoke + | SHOW GRANTS + (ON TABLE? qualifiedName)? #showGrants + | EXPLAIN ANALYZE? VERBOSE? + ('(' explainOption (',' explainOption)* ')')? statement #explain + | SHOW STATS (FOR | ON) qualifiedName #showStats + | SHOW STATS FOR '(' querySpecification ')' #showStatsForQuery + | DESCRIBE qualifiedName #showColumns + | DESC qualifiedName #showColumns + | START TRANSACTION (transactionMode (',' transactionMode)*)? #startTransaction + | COMMIT WORK? #commit + | ROLLBACK WORK? #rollback + | SHOW PARTITIONS (FROM | IN) qualifiedName #showPartitions + ; + +query + : with? queryNoWith + ; + +with + : WITH RECURSIVE? namedQuery (',' namedQuery)* + ; + +partitionOps + : PARTITION BY HASH(partitionKey=expression) PARTITIONS INTEGER_VALUE #hashPartition + | PARTITION BY RANGE(partitionKey=expression) + '(' rangePartitionElement + (',' rangePartitionElement)* ')' #rangePartition + | PARTITION BY LIST(partitionKey=expression) + '(' listPartitionElement + (',' listPartitionElement)* ')' #listPartition + ; + +tableElementPart + : '(' tableElement (',' tableElement)* ')' + ; + +tableElement + : columnDefinition + | likeClause + ; + +rangePartitionElement + : partitionName=identifier VALUES LESS THAN (partitionCon=expression | MAXVALUE) + ; + +listPartitionElement + : (partitionName=identifier VALUES IN '('expression (',' expression)*')') + ; + +columnDefinition + : identifier type (COMMENT string)? + ; + +likeClause + : LIKE qualifiedName (optionType=(INCLUDING | EXCLUDING) PROPERTIES)? + ; + +properties + : '(' property (',' property)* ')' + ; + +property + : identifier EQ expression + ; + +queryNoWith: + queryTerm + (ORDER BY sortItem (',' sortItem)*)? + (LIMIT limit=(INTEGER_VALUE | ALL))? + ; + +queryTerm + : queryPrimary #queryTermDefault + | left=queryTerm operator=INTERSECT setQuantifier? right=queryTerm #setOperation + | left=queryTerm operator=(UNION | EXCEPT) setQuantifier? right=queryTerm #setOperation + ; + +queryPrimary + : querySpecification #queryPrimaryDefault + | TABLE qualifiedName #table + | VALUES expression (',' expression)* #inlineTable + | '(' queryNoWith ')' #subquery + ; + +sortItem + : expression ordering=(ASC | DESC)? (NULLS nullOrdering=(FIRST | LAST))? + ; + +querySpecification + : SELECT setQuantifier? selectItem (',' selectItem)* + (FROM relation (',' relation)*)? + (WHERE where=booleanExpression)? + (GROUP BY groupBy)? + (HAVING having=booleanExpression)? + ; + +groupBy + : setQuantifier? groupingElement (',' groupingElement)* + ; + +groupingElement + : groupingExpressions #singleGroupingSet + | ROLLUP '(' (qualifiedName (',' qualifiedName)*)? ')' #rollup + | CUBE '(' (qualifiedName (',' qualifiedName)*)? ')' #cube + | GROUPING SETS '(' groupingSet (',' groupingSet)* ')' #multipleGroupingSets + ; + +groupingExpressions + : '(' (expression (',' expression)*)? ')' + | expression + ; + +groupingSet + : '(' (qualifiedName (',' qualifiedName)*)? ')' + | qualifiedName + ; + +namedQuery + : name=identifier (columnAliases)? AS '(' query ')' + ; + +setQuantifier + : DISTINCT + | ALL + ; + +selectItem + : expression (AS? identifier)? #selectSingle + | qualifiedName '.' ASTERISK #selectAll + | ASTERISK #selectAll + ; + +relation + : left=relation + ( CROSS JOIN right=sampledRelation + | joinType JOIN rightRelation=relation joinCriteria + | NATURAL joinType JOIN right=sampledRelation + ) #joinRelation + | sampledRelation #relationDefault + ; + +joinType + : INNER? + | LEFT OUTER? + | RIGHT OUTER? + | FULL OUTER? + ; + +joinCriteria + : ON booleanExpression + | USING '(' identifier (',' identifier)* ')' + ; + +sampledRelation + : aliasedRelation ( + TABLESAMPLE sampleType '(' percentage=expression ')' + )? + ; + +sampleType + : BERNOULLI + | SYSTEM + ; + +aliasedRelation + : relationPrimary (AS? identifier columnAliases?)? + ; + +columnAliases + : '(' identifier (',' identifier)* ')' + ; + +relationPrimary + : qualifiedName #tableName + | '(' query ')' #subqueryRelation + | UNNEST '(' expression (',' expression)* ')' (WITH ORDINALITY)? #unnest + | LATERAL '(' query ')' #lateral + | '(' relation ')' #parenthesizedRelation + ; + +expression + : booleanExpression + ; + +booleanExpression + : predicated #booleanDefault + | NOT booleanExpression #logicalNot + | left=booleanExpression operator=AND right=booleanExpression #logicalBinary + | left=booleanExpression operator=OR right=booleanExpression #logicalBinary + ; + +// workaround for: +// https://github.com/antlr/antlr4/issues/780 +// https://github.com/antlr/antlr4/issues/781 +predicated + : valueExpression predicate[$valueExpression.ctx]? + ; + +predicate[ParserRuleContext value] + : comparisonOperator right=valueExpression #comparison + | comparisonOperator comparisonQuantifier '(' query ')' #quantifiedComparison + | NOT? BETWEEN lower=valueExpression AND upper=valueExpression #between + | NOT? IN '(' expression (',' expression)* ')' #inList + | NOT? IN '(' query ')' #inSubquery + | NOT? LIKE pattern=valueExpression (ESCAPE escape=valueExpression)? #like + | IS NOT? NULL #nullPredicate + | IS NOT? DISTINCT FROM right=valueExpression #distinctFrom + ; + +valueExpression + : primaryExpression #valueExpressionDefault + | valueExpression AT timeZoneSpecifier #atTimeZone + | operator=(MINUS | PLUS) valueExpression #arithmeticUnary + | left=valueExpression operator=(ASTERISK | SLASH | PERCENT) right=valueExpression #arithmeticBinary + | left=valueExpression operator=(PLUS | MINUS) right=valueExpression #arithmeticBinary + | left=valueExpression CONCAT right=valueExpression #concatenation + ; + +primaryExpression + : NULL #nullLiteral + | interval #intervalLiteral + | identifier string #typeConstructor + | DOUBLE_PRECISION string #typeConstructor + | number #numericLiteral + | booleanValue #booleanLiteral + | string #stringLiteral + | BINARY_LITERAL #binaryLiteral + | '?' #parameter + | POSITION '(' valueExpression IN valueExpression ')' #position + | '(' expression (',' expression)+ ')' #rowConstructor + | ROW '(' expression (',' expression)* ')' #rowConstructor + | qualifiedName '(' ASTERISK ')' filter? over? #functionCall + | qualifiedName '(' (setQuantifier? expression (',' expression)*)? + (ORDER BY sortItem (',' sortItem)*)? ')' filter? over? #functionCall + | identifier '->' expression #lambda + | '(' (identifier (',' identifier)*)? ')' '->' expression #lambda + | '(' query ')' #subqueryExpression + // This is an extension to ANSI SQL, which considers EXISTS to be a + | EXISTS '(' query ')' #exists + | CASE valueExpression whenClause+ (ELSE elseExpression=expression)? END #simpleCase + | CASE whenClause+ (ELSE elseExpression=expression)? END #searchedCase + | CAST '(' expression AS type ')' #cast + | TRY_CAST '(' expression AS type ')' #cast + | ARRAY '[' (expression (',' expression)*)? ']' #arrayConstructor + | value=primaryExpression '[' index=valueExpression ']' #subscript + | identifier #columnReference + | base=primaryExpression '.' fieldName=identifier #dereference + | name=CURRENT_DATE #specialDateTimeFunction + | name=CURRENT_TIME ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction + | name=CURRENT_TIMESTAMP ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction + | name=LOCALTIME ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction + | name=LOCALTIMESTAMP ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction + | SUBSTRING '(' valueExpression FROM valueExpression (FOR valueExpression)? ')' #substring + | NORMALIZE '(' valueExpression (',' normalForm)? ')' #normalize + | EXTRACT '(' identifier FROM valueExpression ')' #extract + | '(' expression ')' #parenthesizedExpression + | GROUPING '(' (qualifiedName (',' qualifiedName)*)? ')' #groupingOperation + ; + +string + : STRING #basicStringLiteral + | UNICODE_STRING (UESCAPE STRING)? #unicodeStringLiteral + ; + +timeZoneSpecifier + : TIME ZONE interval #timeZoneInterval + | TIME ZONE string #timeZoneString + ; + +comparisonOperator + : EQ | NEQ | LT | LTE | GT | GTE + ; + +comparisonQuantifier + : ALL | SOME | ANY + ; + +booleanValue + : TRUE | FALSE + ; + +interval + : INTERVAL sign=(PLUS | MINUS)? string from=intervalField (TO to=intervalField)? + ; + +intervalField + : YEAR | MONTH | DAY | HOUR | MINUTE | SECOND + ; + +normalForm + : NFD | NFC | NFKD | NFKC + ; + +type + : type ARRAY + | ARRAY '<' type '>' + | MAP '<' type ',' type '>' + | ROW '(' identifier type (',' identifier type)* ')' + | baseType ('(' typeParameter (',' typeParameter)* ')')? + | INTERVAL from=intervalField TO to=intervalField + ; + +typeParameter + : INTEGER_VALUE | type + ; + +baseType + : TIME_WITH_TIME_ZONE + | TIMESTAMP_WITH_TIME_ZONE + | DOUBLE_PRECISION + | identifier + ; + +whenClause + : WHEN condition=expression THEN result=expression + ; + +filter + : FILTER '(' WHERE booleanExpression ')' + ; + +over + : OVER '(' + (PARTITION BY partition+=expression (',' partition+=expression)*)? + (ORDER BY sortItem (',' sortItem)*)? + windowFrame? + ')' + ; + +windowFrame + : frameType=RANGE start=frameBound + | frameType=ROWS start=frameBound + | frameType=RANGE BETWEEN start=frameBound AND end=frameBound + | frameType=ROWS BETWEEN start=frameBound AND end=frameBound + ; + +frameBound + : UNBOUNDED boundType=PRECEDING #unboundedFrame + | UNBOUNDED boundType=FOLLOWING #unboundedFrame + | CURRENT ROW #currentRowBound + | expression boundType=(PRECEDING | FOLLOWING) #boundedFrame // expression should be unsignedLiteral + ; + + +explainOption + : FORMAT value=(TEXT | GRAPHVIZ) #explainFormat + | TYPE value=(LOGICAL | DISTRIBUTED | VALIDATE) #explainType + ; + +transactionMode + : ISOLATION LEVEL levelOfIsolation #isolationLevel + | READ accessMode=(ONLY | WRITE) #transactionAccessMode + ; + +levelOfIsolation + : READ UNCOMMITTED #readUncommitted + | READ COMMITTED #readCommitted + | REPEATABLE READ #repeatableRead + | SERIALIZABLE #serializable + ; + +privilege + : SELECT | DELETE | INSERT | identifier + ; + +qualifiedName + : identifier ('.' identifier)* + ; + +identifier + : IDENTIFIER #unquotedIdentifier + | QUOTED_IDENTIFIER #quotedIdentifier + | nonReserved #unquotedIdentifier + | BACKQUOTED_IDENTIFIER #backQuotedIdentifier + | DIGIT_IDENTIFIER #digitIdentifier + ; + +number + : DECIMAL_VALUE #decimalLiteral + | INTEGER_VALUE #integerLiteral + ; + +nonReserved + // IMPORTANT: this rule must only contain tokens. Nested rules are not supported. See SqlParser.exitNonReserved + : ADD | ALL | ANALYZE | ANY | ARRAY | ASC | AT + | BERNOULLI + | CALL | CASCADE | CATALOGS | COALESCE | COLUMN | COLUMNS | COMMENT | COMMIT | COMMITTED | CURRENT + | DATA | DATE | DAY | DESC | DISTRIBUTED + | EXCLUDING | EXPLAIN + | FILTER | FIRST | FOLLOWING | FORMAT | FUNCTIONS + | GRANT | GRANTS | GRAPHVIZ + | HOUR + | IF | INCLUDING | INPUT | INTEGER | INTERVAL | ISOLATION + | LAST | LATERAL | LEVEL | LIMIT | LOGICAL + | MAP | MINUTE | MONTH + | NFC | NFD | NFKC | NFKD | NO | NULLIF | NULLS + | ONLY | OPTION | ORDINALITY | OUTPUT | OVER + | PARTITION | PARTITIONS | POSITION | PRECEDING | PRIVILEGES | PROPERTIES | PUBLIC + | RANGE | READ | RENAME | REPEATABLE | REPLACE | RESET | RESTRICT | REVOKE | ROLLBACK | ROW | ROWS + | SCHEMA | SCHEMAS | SECOND | SERIALIZABLE | SESSION | SET | SETS + | SHOW | SMALLINT | SOME | START | STATS | SUBSTRING | SYSTEM + | TABLES | TABLESAMPLE | TEXT | TIME | TIMESTAMP | TINYINT | TO | TRANSACTION | TRY_CAST | TYPE + | UNBOUNDED | UNCOMMITTED | USE + | VALIDATE | VERBOSE | VIEW + | WORK | WRITE + | YEAR + | ZONE + ; + +ADD: 'ADD'; +ALL: 'ALL'; +ALTER: 'ALTER'; +ANALYZE: 'ANALYZE'; +AND: 'AND'; +ANY: 'ANY'; +ARRAY: 'ARRAY'; +AS: 'AS'; +ASC: 'ASC'; +AT: 'AT'; +BERNOULLI: 'BERNOULLI'; +BETWEEN: 'BETWEEN'; +BY: 'BY'; +CALL: 'CALL'; +CASCADE: 'CASCADE'; +CASE: 'CASE'; +CAST: 'CAST'; +CATALOGS: 'CATALOGS'; +COALESCE: 'COALESCE'; +COLUMN: 'COLUMN'; +COLUMNS: 'COLUMNS'; +COMMENT: 'COMMENT'; +COMMIT: 'COMMIT'; +COMMITTED: 'COMMITTED'; +CONSTRAINT: 'CONSTRAINT'; +CREATE: 'CREATE'; +CROSS: 'CROSS'; +CUBE: 'CUBE'; +CURRENT: 'CURRENT'; +CURRENT_DATE: 'CURRENT_DATE'; +CURRENT_TIME: 'CURRENT_TIME'; +CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'; +DATA: 'DATA'; +DATE: 'DATE'; +DAY: 'DAY'; +DEALLOCATE: 'DEALLOCATE'; +DELETE: 'DELETE'; +DESC: 'DESC'; +DESCRIBE: 'DESCRIBE'; +DISTINCT: 'DISTINCT'; +DISTRIBUTED: 'DISTRIBUTED'; +DROP: 'DROP'; +ELSE: 'ELSE'; +END: 'END'; +ESCAPE: 'ESCAPE'; +EXCEPT: 'EXCEPT'; +EXCLUDING: 'EXCLUDING'; +EXECUTE: 'EXECUTE'; +EXISTS: 'EXISTS'; +EXPLAIN: 'EXPLAIN'; +EXTRACT: 'EXTRACT'; +FALSE: 'FALSE'; +FILTER: 'FILTER'; +FIRST: 'FIRST'; +FOLLOWING: 'FOLLOWING'; +FOR: 'FOR'; +FORMAT: 'FORMAT'; +FROM: 'FROM'; +FULL: 'FULL'; +FUNCTIONS: 'FUNCTIONS'; +GRANT: 'GRANT'; +GRANTS: 'GRANTS'; +GRAPHVIZ: 'GRAPHVIZ'; +GROUP: 'GROUP'; +GROUPING: 'GROUPING'; +HASH: 'HASH'; +HAVING: 'HAVING'; +HOUR: 'HOUR'; +IF: 'IF'; +IN: 'IN'; +INCLUDING: 'INCLUDING'; +INNER: 'INNER'; +INPUT: 'INPUT'; +INSERT: 'INSERT'; +INTEGER: 'INTEGER'; +INTERSECT: 'INTERSECT'; +INTERVAL: 'INTERVAL'; +INTO: 'INTO'; +IS: 'IS'; +ISOLATION: 'ISOLATION'; +JOIN: 'JOIN'; +LAST: 'LAST'; +LATERAL: 'LATERAL'; +LEFT: 'LEFT'; +LESS: 'LESS'; +LEVEL: 'LEVEL'; +LIKE: 'LIKE'; +LIMIT: 'LIMIT'; +LIST: 'LIST'; +LOCALTIME: 'LOCALTIME'; +LOCALTIMESTAMP: 'LOCALTIMESTAMP'; +LOGICAL: 'LOGICAL'; +MAP: 'MAP'; +MAXVALUE: 'MAXVALUE'; +MINUTE: 'MINUTE'; +MONTH: 'MONTH'; +NATURAL: 'NATURAL'; +NFC : 'NFC'; +NFD : 'NFD'; +NFKC : 'NFKC'; +NFKD : 'NFKD'; +NO: 'NO'; +NORMALIZE: 'NORMALIZE'; +NOT: 'NOT'; +NULL: 'NULL'; +NULLIF: 'NULLIF'; +NULLS: 'NULLS'; +ON: 'ON'; +ONLY: 'ONLY'; +OPTION: 'OPTION'; +OR: 'OR'; +ORDER: 'ORDER'; +ORDINALITY: 'ORDINALITY'; +OUTER: 'OUTER'; +OUTPUT: 'OUTPUT'; +OVER: 'OVER'; +PARTITION: 'PARTITION'; +PARTITIONS: 'PARTITIONS'; +POSITION: 'POSITION'; +PRECEDING: 'PRECEDING'; +PREPARE: 'PREPARE'; +PRIVILEGES: 'PRIVILEGES'; +PROPERTIES: 'PROPERTIES'; +PUBLIC: 'PUBLIC'; +RANGE: 'RANGE'; +READ: 'READ'; +RECURSIVE: 'RECURSIVE'; +RENAME: 'RENAME'; +REPEATABLE: 'REPEATABLE'; +REPLACE: 'REPLACE'; +RESET: 'RESET'; +RESTRICT: 'RESTRICT'; +REVOKE: 'REVOKE'; +RIGHT: 'RIGHT'; +ROLLBACK: 'ROLLBACK'; +ROLLUP: 'ROLLUP'; +ROW: 'ROW'; +ROWS: 'ROWS'; +SCHEMA: 'SCHEMA'; +SCHEMAS: 'SCHEMAS'; +SECOND: 'SECOND'; +SELECT: 'SELECT'; +SERIALIZABLE: 'SERIALIZABLE'; +SESSION: 'SESSION'; +SET: 'SET'; +SETS: 'SETS'; +SHOW: 'SHOW'; +SMALLINT: 'SMALLINT'; +SOME: 'SOME'; +START: 'START'; +STATS: 'STATS'; +SUBSTRING: 'SUBSTRING'; +SYSTEM: 'SYSTEM'; +TABLE: 'TABLE'; +TABLES: 'TABLES'; +TABLESAMPLE: 'TABLESAMPLE'; +TEXT: 'TEXT'; +THAN: 'THAN'; +THEN: 'THEN'; +TIME: 'TIME'; +TIMESTAMP: 'TIMESTAMP'; +TINYINT: 'TINYINT'; +TO: 'TO'; +TRANSACTION: 'TRANSACTION'; +TRUE: 'TRUE'; +TRY_CAST: 'TRY_CAST'; +TYPE: 'TYPE'; +UESCAPE: 'UESCAPE'; +UNBOUNDED: 'UNBOUNDED'; +UNCOMMITTED: 'UNCOMMITTED'; +UNION: 'UNION'; +UNNEST: 'UNNEST'; +USE: 'USE'; +USING: 'USING'; +VALIDATE: 'VALIDATE'; +VALUES: 'VALUES'; +VERBOSE: 'VERBOSE'; +VIEW: 'VIEW'; +WHEN: 'WHEN'; +WHERE: 'WHERE'; +WITH: 'WITH'; +WORK: 'WORK'; +WRITE: 'WRITE'; +YEAR: 'YEAR'; +ZONE: 'ZONE'; + +EQ : '='; +NEQ : '<>' | '!='; +LT : '<'; +LTE : '<='; +GT : '>'; +GTE : '>='; + +PLUS: '+'; +MINUS: '-'; +ASTERISK: '*'; +SLASH: '/'; +PERCENT: '%'; +CONCAT: '||'; + +STRING + : '\'' ( ~'\'' | '\'\'' )* '\'' + ; + +UNICODE_STRING + : 'U&\'' ( ~'\'' | '\'\'' )* '\'' + ; + +// Note: we allow any character inside the binary literal and validate +// its a correct literal when the AST is being constructed. This +// allows us to provide more meaningful error messages to the user +BINARY_LITERAL + : 'X\'' (~'\'')* '\'' + ; + +INTEGER_VALUE + : DIGIT+ + ; + +DECIMAL_VALUE + : DIGIT+ '.' DIGIT* + | '.' DIGIT+ + | DIGIT+ ('.' DIGIT*)? EXPONENT + | '.' DIGIT+ EXPONENT + ; + +IDENTIFIER + : (LETTER | '_') (LETTER | DIGIT | '_' | '@' | ':')* + ; + +DIGIT_IDENTIFIER + : DIGIT (LETTER | DIGIT | '_' | '@' | ':')+ + ; + +QUOTED_IDENTIFIER + : '"' ( ~'"' | '""' )* '"' + ; + +BACKQUOTED_IDENTIFIER + : '`' ( ~'`' | '``' )* '`' + ; + +TIME_WITH_TIME_ZONE + : 'TIME' WS 'WITH' WS 'TIME' WS 'ZONE' + ; + +TIMESTAMP_WITH_TIME_ZONE + : 'TIMESTAMP' WS 'WITH' WS 'TIME' WS 'ZONE' + ; + +DOUBLE_PRECISION + : 'DOUBLE' WS 'PRECISION' + ; + +fragment EXPONENT + : 'E' [+-]? DIGIT+ + ; + +fragment DIGIT + : [0-9] + ; + +fragment LETTER + : [A-Z] + ; + +SIMPLE_COMMENT + : '--' ~[\r\n]* '\r'? '\n'? -> channel(HIDDEN) + ; + +BRACKETED_COMMENT + : '/*' .*? '*/' -> channel(HIDDEN) + ; + +WS + : [ \r\n\t]+ -> channel(HIDDEN) + ; + +// Catch-all for anything we can't recognize. +// We use this to be able to ignore and recover all the text +// when splitting statements with DelimiterLexer +UNRECOGNIZED + : . + ;