statement   ::= explain | ddl | dml | dql | acl | call
explain     ::= 'EXPLAIN' (dml | ('(' 'RAW' (',' 'FMT')? ')')? dql )
dql         ::= (with? select | values)
                ('OPTION' '('
                    (
                        'read_preference' '=' ('LEADER' | 'REPLICA' | 'ANY')
                        | ('sql_motion_row_max' | 'sql_vdbe_opcode_max') '=' unsigned
                    )
                    (','
                        (
                            'read_preference' '=' ('LEADER' | 'REPLICA' | 'ANY')
                            | ('sql_motion_row_max' | 'sql_vdbe_opcode_max') '=' unsigned
                        )
                    )*
                ')')?
with        ::= 'WITH'
                cte ('(' column (',' column)* ')')? 'AS' '(' (select | values) ')'
                (',' cte ('(' column (',' column)* ')')? 'AS' '(' (select | values) ')')*
select      ::= 'SELECT' 'DISTINCT'? projection (',' projection)* from?
                ('LIMIT' (unsigned | 'ALL' | 'NULL'))?
from        ::= 'FROM' scan
                (( 'INNER' | 'LEFT' 'OUTER'? )? 'JOIN' scan 'ON' expression)*
                ('WHERE' expression)?
                ('GROUP' 'BY' expression (',' expression)*)?
                ('HAVING' expression)?
                ('WINDOW' name 'AS' '(' partition ')')?
                ('ORDER' 'BY' expression ('ASC' | 'DESC')? (',' expression ('ASC' | 'DESC')? ('NULLS' ('FIRST' | 'LAST'))?)*)?
                (('UNION' 'ALL'? | 'EXCEPT' 'DISTINCT'?) select)?
                ('LIMIT' (unsigned | 'ALL' | 'NULL'))?
projection  ::= (table '.')? '*' | expression (('AS')? name)? | aggregate | window (('AS')? name)?
scan_table  ::= (table ('AS'? name)? ('INDEXED' 'BY' index)?)
scan        ::= (table ('AS'? name)? ('INDEXED BY' index)? | '(' dql ')' ('AS'? name)? )
expression  ::= (('NOT'* (
                    (table '.')? column
                    | abs
                    | case
                    | cast
                    | coalesce
                    | current_date
                    | ilike
                    | json_extract_path
                    | instance_uuid
                    | literal
                    | localtimestamp
                    | lower
                    | pico_config_file_path
                    | pico_instance_dir
                    | pico_instance_name
                    | pico_instance_uuid
                    | pico_raft_leader_id
                    | pico_raft_leader_uuid
                    | pico_replicaset_name
                    | pico_tier_name
                    | _pico_bucket
                    | substr
                    | substring
                    | to_char
                    | to_date
                    | trim
                    | upper
                    | version
                    | 'NOT'? 'EXISTS' '(' dql ')'
                    | '(' dql ')'
                    | '(' expression (',' expression)* ')'
                )) | like ) ('IS' 'NOT'? ('NULL' | 'TRUE' | 'FALSE' | 'UNKNOWN'))*
                | expression
                (
                    'NOT'? 'BETWEEN' expression 'AND'
                    | ('+' | '-' | '*' | '/' | '%')
                    | ('<>' | '!=' | '>=' | '>' | '<=' | '<' | '=' | 'NOT'? 'IN')
                    | '||'
                    | 'AND'
                    | 'OR'
                )
                expression
aggregate   ::= ('AVG' | 'COUNT' | 'MAX' | 'MIN' | 'SUM' | 'TOTAL') '(' ('DISTINCT'? expression) ')'
               | ('GROUP_CONCAT' | 'STRING_AGG') '(' expression ',' "'" string "'" ')'
window      ::= (builtin | aggregate) ('FILTER' '(' 'WHERE' expression ')')?
                 'OVER' (name | ('(' partition ')'))
partition   ::= ('PARTITION' 'BY' expression (',' expression)*)?
                 ('ORDER' 'BY' expression ('ASC' | 'DESC')? (',' expression ('ASC' | 'DESC')?)*)?
                 (('RANGE' | 'ROWS') (
                   (
                      'BETWEEN'
                      (
                        ('UNBOUNDED' 'PRECEDING')
                        | (expression ('FOLLOWING' | 'PRECEDING'))
                        | ('CURRENT' 'ROW')
                      )
                      'AND'
                      (
                        ('UNBOUNDED' 'FOLLOWING')
                        | (expression ('FOLLOWING' | 'PRECEDING'))
                        | ('CURRENT' 'ROW')
                      )
                   ) | ('UNBOUNDED' 'PRECEDING') | ('CURRENT' 'ROW') | ( expression 'PRECEDING')
                 ))?
builtin     ::= 'LAST_VALUE' '(' expression ')'
                | 'ROW_NUMBER' '(' ')'
case        ::= 'CASE' expression?
                ('WHEN' expression 'THEN' expression)+
                ('ELSE' expression)? 'END'
cast        ::= 'CAST' '(' expression 'AS' unrestricted_type ')' | expression '::' unrestricted_type
coalesce    ::= 'COALESCE' '(' expression ',' expression (',' expression)* ')'
like        ::= expression 'LIKE' expression ('ESCAPE' expression)?
localtimestamp ::= 'LOCALTIMESTAMP' ('(' unsigned ')')?
ilike       ::= expression 'ILIKE' expression ('ESCAPE' expression)?
json_extract_path ::= 'JSON_EXTRACT_PATH' '(' expression ',' expression (',' expression)* ')'
instance_uuid    ::= 'INSTANCE_UUID' '(' ')'
pico_config_file_path      ::= 'PICO_CONFIG_FILE_PATH' '(' text ')'
pico_instance_dir     ::= 'PICO_INSTANCE_DIR' '(' text ')'
pico_instance_name    ::= 'PICO_INSTANCE_NAME' '(' text ')'
pico_instance_uuid    ::= 'PICO_INSTANCE_UUID' '(' ')'
pico_replicaset_name  ::= 'PICO_REPLICASET_NAME' '(' text ')'
pico_tier_name        ::= 'PICO_TIER_NAME' '(' text ')'
_pico_bucket          ::= '_PICO_BUCKET' '(' text ')'
to_char     ::= 'TO_CHAR' '(' expression ',' format ')'
to_date     ::= 'TO_DATE' '(' expression ',' format ')'
trim        ::= 'TRIM' '('
                ((('LEADING' | 'TRAILING' | 'BOTH')? removal_chars
                | ('LEADING' | 'TRAILING' | 'BOTH')) 'FROM')? string ')'
substr      ::= 'SUBSTR' '(' string ',' from (',' count)? ')'
substring   ::= 'SUBSTRING' '(' substringVariant ')'
substringVariant ::= substringFromFor | substringRegular | substringFor | substringFrom | substringSimilar
substringFromFor ::= expression 'FROM' expression 'FOR' expression
substringRegular ::= expression ',' expression ',' expression
substringFor ::= expression 'FOR' expression
substringFrom ::= expression ('FROM' | ',') expression
substringSimilar ::= expression 'SIMILAR' expression 'ESCAPE' expression
lower       ::= 'LOWER' '(' string ')'
upper       ::= 'UPPER' '(' string ')'
abs         ::= 'ABS' '(' ( decimal | double | integer ) ')'
values      ::= 'VALUES'
                ('(' (expression(',' expression)*) ')')
                (',' ('(' (expression(',' expression)*) ')'))*
literal     ::= 'TRUE'
                | 'FALSE'
                | 'NULL'
                | decimal
                | double
                | integer
                | string
                | unsigned
                | ('$' unsigned)
                | '?'
dml         ::= (call | delete | insert | update)
                ('OPTION' '('
                    (('sql_motion_row_max' | 'sql_vdbe_opcode_max') '=' unsigned)
                    (',' (('sql_motion_row_max' | 'sql_vdbe_opcode_max') '=' unsigned))*
                ')')?
call        ::= 'CALL' procedure '(' (literal (',' literal)*)? ')'
delete      ::= 'DELETE' 'FROM' table ('INDEXED' 'BY' index)? ('WHERE' expression)?
insert      ::= 'INSERT' 'INTO' table ('(' column (',' column)* ')')? dql
                ('ON' 'CONFLICT' 'DO' ('NOTHING' | 'REPLACE' | 'FAIL'))?
update      ::= 'UPDATE' table ('INDEXED' 'BY' index)? 'SET'
                column '=' expression (',' column '=' expression)*
                ('FROM' scan)? ('WHERE' expression)?
acl         ::= (alter_user | create_role | create_user | drop_role | drop_user | grant | revoke | audit_policy)
revoke      ::= 'REVOKE' (
                    (('CREATE' | 'ALTER' | 'DROP') 'USER')
                    | (('ALTER' | 'DROP') 'ON' 'USER' user)
                    | (('CREATE' | 'DROP') 'ROLE')
                    | ('DROP' 'ON' 'ROLE' role)
                    | (('CREATE' | 'ALTER' | 'DROP' | 'READ' | 'WRITE') 'TABLE')
                    | (('CREATE' | 'ALTER' | 'DROP' | 'READ' | 'WRITE') 'ON' 'TABLE' table)
                    | (('CREATE' | 'EXECUTE' | 'DROP') 'PROCEDURE')
                    | (('EXECUTE' | 'DROP') 'ON' 'PROCEDURE' procedure ('(' unrestricted_type (',' type)* ')')?)
                    | role
                )
                'FROM' (role | user)
                ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                ('OPTION' '(' ('TIMEOUT' '=' double)')')?
grant       ::= 'GRANT' (
                    (('CREATE' | 'ALTER' | 'DROP') 'USER')
                    | (('ALTER' | 'DROP') 'ON' 'USER' user)
                    | (('CREATE' | 'DROP') 'ROLE')
                    | ('DROP' 'ON' 'ROLE' role)
                    | (('CREATE' | 'ALTER' | 'DROP' | 'READ' | 'WRITE') 'TABLE')
                    | (('CREATE' | 'ALTER' | 'DROP' | 'READ' | 'WRITE') 'ON' 'TABLE' table)
                    | (('CREATE' | 'EXECUTE' | 'DROP') 'PROCEDURE')
                    | (('EXECUTE' | 'DROP') 'ON' 'PROCEDURE' procedure ('(' unrestricted_type (',' unrestricted_type)* ')')?)
                    | role
                )
                'TO' (role | user)
                ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                ('OPTION' '(' ('TIMEOUT' '=' double)')')?
ddl         ::= (alter_index | alter_plugin | alter_procedure | alter_system | alter_table
                | create_index | create_plugin | create_procedure | create_table
                | drop_index | drop_plugin | drop_procedure | drop_table | truncate_table | backup)
alter_system ::= 'ALTER' 'SYSTEM'
                    (
                        'RESET' ('ALL' | param_name)
                        | 'SET' param_name ('=' | 'TO') ('DEFAULT' | param_value)
                    )
                    ('FOR' ('ALL' 'TIERS' | 'TIER' tier))?
                    ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                    ('OPTION' '(' ('TIMEOUT' '=' double)')')?
alter_procedure ::= 'ALTER' 'PROCEDURE' procedure ('(' unrestricted_type (',' unrestricted_type)* ')')?
                     'RENAME' 'TO' procedure
                     ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                     ('OPTION' '(' ('TIMEOUT' '=' double)')')?
alter_index ::=     'ALTER' 'INDEX' ('IF' 'EXISTS')? index
                     'RENAME' 'TO' index
                     ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                     ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_index ::= 'CREATE' 'UNIQUE'? 'INDEX' ('IF' 'NOT' 'EXISTS')? index 'ON' table
                 ('USING' ('TREE' | 'HASH' | 'RTREE' | 'BITSET'))?
                 '(' column (',' column)* ')' ('WITH' '('
                     (
                         ('BLOOM_FPR' '=' decimal)
                         | ('PAGE_SIZE' '=' unsigned)
                         | ('RANGE_SIZE' '=' unsigned)
                         | ('RUN_COUNT_PER_LEVEL' '=' unsigned)
                         | ('RUN_SIZE_RATIO' '=' decimal)
                         | ('DIMENSION' '=' unsigned)
                         | ('DISTANCE' '=' ('EUCLID' | 'MANHATTAN'))
                         | ('HINT' '=' ('TRUE' | 'FALSE'))
                         | ('COMPRESSION_LEVEL' '=' integer)
                     )
                     (
                        ','
                         (
                             ('BLOOM_FPR' '=' decimal)
                             | ('PAGE_SIZE' '=' unsigned)
                             | ('RANGE_SIZE' '=' unsigned)
                             | ('RUN_COUNT_PER_LEVEL' '=' unsigned)
                             | ('RUN_SIZE_RATIO' '=' decimal)
                             | ('DIMENSION' '=' unsigned)
                             | ('DISTANCE' '=' ('EUCLID' | 'MANHATTAN'))
                             | ('HINT' '=' ('TRUE' | 'FALSE'))
                             | ('COMPRESSION_LEVEL' '=' integer)
                         )
                     )*
                 ')')?
                 ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                 ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_procedure ::= 'CREATE' 'PROCEDURE' ('IF' 'NOT' 'EXISTS')? procedure '(' unrestricted_type (',' unrestricted_type)* ')'
                     ('LANGUAGE' 'SQL')? (
                         ('AS' '$$' (insert | update | delete) '$$')
                         | ('BEGIN' 'ATOMIC' (insert | update | delete) 'END')
                     )
                     ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                     ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_role    ::= 'CREATE' 'ROLE' ('IF' 'NOT' 'EXISTS')? role
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_table   ::= 'CREATE' 'UNLOGGED'? 'TABLE' ('IF' 'NOT' 'EXISTS')? table
                   '('
                       column column_def_type ('NOT'? 'NULL')? ('PRIMARY' 'KEY')? (',' column column_def_type ('NOT'? 'NULL')? ('PRIMARY' 'KEY')?)*
                       (',' 'PRIMARY' 'KEY' '(' (bucket_id ',')? column (',' column)* ')')?
                   ')'
                   ('USING' ('MEMTX' | 'VINYL' 
                   ('WITH' '('
                     (
                         ('BLOOM_FPR' '=' decimal)
                         | ('PAGE_SIZE' '=' unsigned)
                         | ('RANGE_SIZE' '=' unsigned)
                         | ('RUN_COUNT_PER_LEVEL' '=' unsigned)
                         | ('RUN_SIZE_RATIO' '=' decimal)
                         | ('COMPRESSION_LEVEL' '=' integer)
                     )
                     (
                        ','
                         (
                             ('BLOOM_FPR' '=' decimal)
                             | ('PAGE_SIZE' '=' unsigned)
                             | ('RANGE_SIZE' '=' unsigned)
                             | ('RUN_COUNT_PER_LEVEL' '=' unsigned)
                             | ('RUN_SIZE_RATIO' '=' decimal)
                             | ('COMPRESSION_LEVEL' '=' integer)
                         )
                     )*
                 ')')?
                   ))?
                   (('DISTRIBUTED' (('BY' '(' column (',' column)* ')' ('IN' 'TIER' tier)?) | 'GLOBALLY'))?)?
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_user    ::= 'CREATE' 'USER' ('IF' 'NOT' 'EXISTS')? user (('USING' ('LDAP')) | ('WITH'? 'PASSWORD' "'" password "'" ('USING' ('CHAP-SHA1' | 'MD5' | 'SCRAM-SHA256')?)?))
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
alter_user     ::= 'ALTER' 'USER' user
                   'WITH'? (
                       'LOGIN'
                       | 'NOLOGIN'
                       | 'PASSWORD' (('USING' ('LDAP')) | ("'" password "'" ('USING' ('CHAP-SHA1' | 'MD5' | 'SCRAM-SHA256'))?))
                       | 'RENAME' 'TO' user
                   )
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_index     ::= 'DROP' 'INDEX' ('IF' 'EXISTS')? index
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_procedure ::= 'DROP' 'PROCEDURE' ('IF' 'EXISTS')? procedure ('('  (',' unrestricted_type)* ')')?
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_table     ::= 'DROP' 'TABLE' ('IF' 'EXISTS')? table
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
truncate_table ::= 'TRUNCATE' ('TABLE')? table
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
backup         ::= 'BACKUP'
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
alter_table    ::= 'ALTER' 'TABLE' table
                   (
                       ('RENAME' (('COLUMN' column 'TO' column)? | ('TO' table)?))
                       | (
                            ('ADD' 'COLUMN'? ('IF' 'NOT' 'EXISTS')? column column_def_type ('NOT' 'NULL')?)
                            (
                            ','
                                (
                                    ('ADD' 'COLUMN'? ('IF' 'NOT' 'EXISTS')? column column_def_type ('NOT' 'NULL')?)
                                )
                            )*
                       )
                   )
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_role      ::= 'DROP' 'ROLE' ('IF' 'EXISTS')? role
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_user      ::= 'DROP' 'USER' ('IF' 'EXISTS')? user
                   ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                   ('OPTION' '(' ('TIMEOUT' '=' double)')')?
create_plugin  ::= 'CREATE' 'PLUGIN' ('IF' 'NOT' 'EXISTS')? plugin version
                    ('OPTION' '(' ('TIMEOUT' '=' double)')')?
drop_plugin    ::= 'DROP' 'PLUGIN' ('IF' 'EXISTS')? plugin version ('WITH' 'DATA')?
                    ('OPTION' '(' ('TIMEOUT' '=' double)')')?
alter_plugin  ::= 'ALTER' 'PLUGIN' plugin (
                        (version (
                            'ENABLE' | 'DISABLE'
                            | ('ADD' 'SERVICE' service 'TO' 'TIER' tier)
                            | ('REMOVE' 'SERVICE' service 'FROM' 'TIER' tier)
                            | ('SET' ((service'.'key '=' text) (',' service'.'key '=' text)*))
                        ))
                        ('OPTION' '(' ('TIMEOUT' '=' double)')')?
                        | ('MIGRATE' 'TO' version)
                          ( 'OPTION' '('
                            (('TIMEOUT' | 'ROLLBACK_TIMEOUT') '=' double)
                            (',' (('TIMEOUT' | 'ROLLBACK_TIMEOUT') '=' double))*')'
                          )?
                   )
audit_policy     ::= 'AUDIT' 'POLICY' policy ('BY' | 'EXCEPT') user
                     ('WAIT' 'APPLIED' ('GLOBALLY' | 'LOCALLY'))?
                     ('OPTION' '(' ('TIMEOUT' '=' double)')')?

unrestricted_type ::= 'BOOL'
                    | 'BOOLEAN'
                    | 'DATETIME'
                    | 'DECIMAL'
                    | 'DOUBLE'
                    | 'INT'
                    | 'INTEGER'
                    | 'JSON'
                    | 'STRING'
                    | 'TEXT'
                    | 'UUID'
                    | 'VARCHAR' '(' length ')'

/* Technically, only unsigned qualifies as a domain type, but unrestricted_type was added to the diagram to make it more comprehensive. */
domain_type   ::= 'UNSIGNED'

                | 'BOOL'
                | 'BOOLEAN'
                | 'DATETIME'
                | 'DECIMAL'
                | 'DOUBLE'
                | 'INT'
                | 'INTEGER'
                | 'JSON'
                | 'STRING'
                | 'TEXT'
                | 'UUID'
                | 'VARCHAR' '(' length ')'
