SQL Grammar
The SQL parser in Wvlet is based on Apache Calcite's SQL Language definition.
Identifiers and Keywords
Reserved Keywords
Reserved keywords are SQL language tokens that have special meaning and cannot be used as unquoted identifiers. Examples include: SELECT
, FROM
, WHERE
, GROUP
, BY
, ORDER
, JOIN
, etc.
Non-Reserved Keywords
Non-reserved keywords are SQL language tokens that have special meaning in certain contexts but can still be used as unquoted identifiers. These keywords can be used as table names, column names, or function names without requiring quotes.
Examples of non-reserved keywords:
IF
- Can be used as a function name:IF(condition, true_value, false_value)
KEY
,PRIMARY
,UNIQUE
,INDEX
- Can be used as column namesSYSTEM
,FIRST
,LAST
,ASC
,DESC
- Can be used as identifiersROW
,ROWS
,RANGE
- Can be used in window specifications or as identifiers- And others related to DDL and window functions
This allows for more flexible SQL writing without requiring quoted identifiers in many common cases.
statement:
setStatement
| resetStatement
| explain
| describe
| insert
| update
| merge
| delete
| query
statementList:
statement [ ';' statement ]* [ ';' ]
setStatement:
[ ALTER { SYSTEM | SESSION } ] SET identifier '=' expression
resetStatement:
[ ALTER { SYSTEM | SESSION } ] RESET identifier
| [ ALTER { SYSTEM | SESSION } ] RESET ALL
explain:
EXPLAIN PLAN
[ WITH TYPE | WITH IMPLEMENTATION | WITHOUT IMPLEMENTATION ]
[ EXCLUDING ATTRIBUTES | INCLUDING [ ALL ] ATTRIBUTES ]
[ AS JSON | AS XML | AS DOT ]
FOR { query | insert | update | merge | delete }
describe:
DESCRIBE DATABASE databaseName
| DESCRIBE CATALOG [ databaseName . ] catalogName
| DESCRIBE SCHEMA [ [ databaseName . ] catalogName ] . schemaName
| DESCRIBE [ TABLE ] [ [ [ databaseName . ] catalogName . ] schemaName . ] tableName [ columnName ]
| DESCRIBE [ STATEMENT ] { query | insert | update | merge | delete }
insert:
{ INSERT | UPSERT } INTO tablePrimary
[ '(' column [, column ]* ')' ]
query
update:
UPDATE tablePrimary
SET assign [, assign ]*
[ WHERE booleanExpression ]
assign:
identifier '=' expression
merge:
MERGE INTO tablePrimary [ [ AS ] alias ]
USING tablePrimary
ON booleanExpression
[ WHEN MATCHED THEN UPDATE SET assign [, assign ]* ]
[ WHEN NOT MATCHED THEN INSERT VALUES '(' value [ , value ]* ')' ]
delete:
DELETE FROM tablePrimary [ [ AS ] alias ]
[ WHERE booleanExpression ]
query:
values
| WITH [ RECURSIVE ] withItem [ , withItem ]* query
| {
select
| selectWithoutFrom
| query UNION [ ALL | DISTINCT ] query
| query EXCEPT [ ALL | DISTINCT ] query
| query MINUS [ ALL | DISTINCT ] query
| query INTERSECT [ ALL | DISTINCT ] query
}
[ ORDER BY orderItem [, orderItem ]* ]
[ LIMIT [ start, ] { count | ALL } ]
[ OFFSET start { ROW | ROWS } ]
[ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
withItem:
name
[ '(' column [, column ]* ')' ]
AS '(' query ')'
orderItem:
expression [ ASC | DESC ] [ NULLS FIRST | NULLS LAST ]
select:
SELECT [ hintComment ] [ STREAM ] [ ALL | DISTINCT ]
{ * | projectItem [, projectItem ]* }
FROM tableExpression
[ WHERE booleanExpression ]
[ GROUP BY [ ALL | DISTINCT ] { groupItem [, groupItem ]* } ]
[ HAVING booleanExpression ]
[ WINDOW windowName AS windowSpec [, windowName AS windowSpec ]* ]
[ QUALIFY booleanExpression ]
selectWithoutFrom:
SELECT [ ALL | DISTINCT ]
{ * | projectItem [, projectItem ]* }
projectItem:
expression [ [ AS ] columnAlias ]
| tableAlias . *
tableExpression:
tableReference [, tableReference ]*
| tableExpression [ NATURAL ] [ { LEFT | RIGHT | FULL } [ OUTER ] ] [ ASOF ] JOIN tableExpression [ joinCondition ]
| tableExpression CROSS JOIN tableExpression
| tableExpression [ CROSS | OUTER ] APPLY tableExpression
joinCondition:
ON booleanExpression
| MATCH_CONDITION booleanExpression ON booleanExpression
| USING '(' column [, column ]* ')'
tableReference:
tablePrimary
[ FOR SYSTEM_TIME AS OF expression ]
[ pivot ]
[ unpivot ]
[ matchRecognize ]
[ [ AS ] alias [ '(' columnAlias [, columnAlias ]* ')' ] ]
tablePrimary:
[ [ catalogName . ] schemaName . ] tableName
'(' TABLE [ [ catalogName . ] schemaName . ] tableName ')'
| tablePrimary [ hintComment ] [ EXTEND ] '(' columnDecl [, columnDecl ]* ')'
| [ LATERAL ] '(' query ')'
| UNNEST '(' expression ')' [ WITH ORDINALITY ]
| [ LATERAL ] TABLE '(' [ SPECIFIC ] functionName '(' expression [, expression ]* ')' ')'
columnDecl:
column type [ NOT NULL ]
hint:
hintName
| hintName '(' hintOptions ')'
hintOptions:
hintKVOption [, hintKVOption ]*
| optionName [, optionName ]*
| optionValue [, optionValue ]*
hintKVOption:
optionName '=' stringLiteral
| stringLiteral '=' stringLiteral
optionValue:
stringLiteral
| numericLiteral
columnOrList:
column
| '(' column [, column ]* ')'
exprOrList:
expr
| '(' expr [, expr ]* ')'
pivot:
PIVOT '('
pivotAgg [, pivotAgg ]*
FOR pivotList
IN '(' pivotExpr [, pivotExpr ]* ')'
')'
pivotAgg:
agg '(' [ ALL | DISTINCT ] value [, value ]* ')'
[ [ AS ] alias ]
pivotList:
columnOrList
pivotExpr:
exprOrList [ [ AS ] alias ]
unpivot:
UNPIVOT [ INCLUDING NULLS | EXCLUDING NULLS ] '('
unpivotMeasureList
FOR unpivotAxisList
IN '(' unpivotValue [, unpivotValue ]* ')'
')'
unpivotMeasureList:
columnOrList
unpivotAxisList:
columnOrList
unpivotValue:
column [ AS literal ]
| '(' column [, column ]* ')' [ AS '(' literal [, literal ]* ')' ]
values:
{ VALUES | VALUE } expression [, expression ]*
groupItem:
expression
| '(' ')'
| '(' expression [, expression ]* ')'
| CUBE '(' expression [, expression ]* ')'
| ROLLUP '(' expression [, expression ]* ')'
| GROUPING SETS '(' groupItem [, groupItem ]* ')'
window:
windowName
| windowSpec
windowSpec:
'('
[ windowName ]
[ ORDER BY orderItem [, orderItem ]* ]
[ PARTITION BY expression [, expression ]* ]
[
RANGE numericOrIntervalExpression { PRECEDING | FOLLOWING [exclude]}
| ROWS numericExpression { PRECEDING | FOLLOWING [exclude] }
]
')'
exclude:
EXCLUDE NO OTHERS
| EXCLUDE CURRENT ROW
| EXCLUDE GROUP
| EXCLUDE TIES