All Downloads are FREE. Search and download functionalities are using the official Maven repository.

th2.codec-oracle-log-miner.0.2.1-dev.source-code.PlSqlParser.g4 Maven / Gradle / Ivy

The newest version!
/**
 * Oracle(c) PL/SQL 11g Parser
 *
 * Copyright (c) 2009-2011 Alexandre Porcelli 
 * Copyright (c) 2015-2019 Ivan Kochurkin (KvanTTT, [email protected], Positive Technologies).
 * Copyright (c) 2017-2018 Mark Adams 
 *
 * Licensed 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.
 */

// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging

/*
 * Copyright 2024 Exactpro (Exactpro Systems Limited)
 *
 * Licensed 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.
 */

 /*
 This file hac been changed to improve performance of parsing queries from Oracle redo log by Exactpro
 */

parser grammar PlSqlParser;

options {
    tokenVocab = PlSqlLexer;
    superClass = PlSqlParserBase;
}

@parser::postinclude {
#include 
}

sql_script
    : sql_plus_command_no_semicolon? (
        (sql_plus_command | unit_statement) (SEMICOLON '/'? (sql_plus_command | unit_statement))* SEMICOLON? '/'?
    ) EOF
    ;

unit_statement
    : alter_analytic_view
    | alter_attribute_dimension
    | alter_audit_policy
    | alter_cluster
    | alter_database
    | alter_database_link
    | alter_dimension
    | alter_diskgroup
    | alter_flashback_archive
    | alter_function
    | alter_hierarchy
    | alter_index
    | alter_inmemory_join_group
    | alter_java
    | alter_library
    | alter_lockdown_profile
    | alter_materialized_view
    | alter_materialized_view_log
    | alter_materialized_zonemap
    | alter_operator
    | alter_outline
    | alter_package
    | alter_pmem_filestore
    | alter_procedure
    | alter_resource_cost
    | alter_role
    | alter_rollback_segment
    | alter_sequence
    | alter_session
    | alter_synonym
    | alter_table
    | alter_tablespace
    | alter_tablespace_set
    | alter_trigger
    | alter_type
    | alter_user
    | alter_view
    | call_statement
    | create_analytic_view
    | create_attribute_dimension
    | create_audit_policy
    | create_cluster
    | create_context
    | create_controlfile
    | create_database
    | create_database_link
    | create_dimension
    | create_directory
    | create_diskgroup
    | create_edition
    | create_flashback_archive
    | create_function_body
    | create_hierarchy
    | create_index
    | create_inmemory_join_group
    | create_java
    | create_library
    | create_lockdown_profile
    | create_materialized_view
    | create_materialized_view_log
    | create_materialized_zonemap
    | create_operator
    | create_outline
    | create_package
    | create_package_body
    | create_pmem_filestore
    | create_procedure_body
    | create_profile
    | create_restore_point
    | create_role
    | create_rollback_segment
    | create_sequence
    | create_spfile
    | create_synonym
    | create_table
    | create_tablespace
    | create_tablespace_set
    | create_trigger
    | create_type
    | create_user
    | create_view
    | drop_analytic_view
    | drop_attribute_dimension
    | drop_audit_policy
    | drop_cluster
    | drop_context
    | drop_database
    | drop_database_link
    | drop_directory
    | drop_diskgroup
    | drop_edition
    | drop_flashback_archive
    | drop_function
    | drop_hierarchy
    | drop_index
    | drop_indextype
    | drop_inmemory_join_group
    | drop_java
    | drop_library
    | drop_lockdown_profile
    | drop_materialized_view
    | drop_materialized_zonemap
    | drop_operator
    | drop_outline
    | drop_package
    | drop_pmem_filestore
    | drop_procedure
    | drop_restore_point
    | drop_role
    | drop_rollback_segment
    | drop_sequence
    | drop_synonym
    | drop_table
    | drop_tablespace
    | drop_tablespace_set
    | drop_trigger
    | drop_type
    | drop_user
    | drop_view
    | administer_key_management
    | analyze
    | anonymous_block
    | associate_statistics
    | audit_traditional
    | comment_on_column
    | comment_on_materialized
    | comment_on_table
    | data_manipulation_language_statements
    | disassociate_statistics
    | flashback_table
    | grant_statement
    | noaudit_statement
    | purge_statement
    | rename_object
    | revoke_statement
    | transaction_control_statements
    | truncate_cluster
    | truncate_table
    | unified_auditing
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-DISKGROUP.html
alter_diskgroup
    : ALTER DISKGROUP (
        id_expression (
            ((add_disk_clause | drop_disk_clause)+ | resize_disk_clause) rebalance_diskgroup_clause?
            | (
                replace_disk_clause
                | rename_disk_clause
                | disk_online_clause
                | disk_offline_clause
                | rebalance_diskgroup_clause
                | check_diskgroup_clause
                | diskgroup_template_clauses
                | diskgroup_directory_clauses
                | diskgroup_alias_clauses
                | diskgroup_volume_clauses
                | diskgroup_attributes
                | drop_diskgroup_file_clause
                | convert_redundancy_clause
                | usergroup_clauses
                | user_clauses
                | file_permissions_clause
                | file_owner_clause
                | scrub_clause
                | quotagroup_clauses
                | filegroup_clauses
            )
        )
        | (id_expression (',' id_expression)* | ALL) (
            undrop_disk_clause
            | diskgroup_availability
            | enable_disable_volume
        )
    )
    ;

add_disk_clause
    : ADD (
        (SITE sn = id_expression)? quorum_regular? (FAILGROUP fgn = id_expression)? DISK qualified_disk_clause (
            ',' qualified_disk_clause
        )*
    )+
    ;

drop_disk_clause
    : DROP (
        quorum_regular? DISK id_expression force_noforce? (',' id_expression force_noforce?)*
        | DISKS IN quorum_regular? FAILGROUP id_expression force_noforce? (
            ',' id_expression force_noforce?
        )*
    )
    ;

resize_disk_clause
    : RESIZE ALL (SIZE size_clause)?
    ;

replace_disk_clause
    : REPLACE DISK id_expression WITH CHAR_STRING force_noforce? (
        ',' id_expression WITH CHAR_STRING force_noforce?
    )* (POWER numeric)? wait_nowait?
    ;

wait_nowait
    : WAIT
    | NOWAIT
    ;

rename_disk_clause
    : RENAME (
        DISK id_expression TO id_expression (',' id_expression TO id_expression)*
        | DISKS ALL
    )
    ;

disk_online_clause
    : ONLINE (
        (
            quorum_regular? DISK id_expression (',' id_expression)*
            | DISKS IN quorum_regular? FAILGROUP id_expression (',' id_expression)*
        )+
        | ALL
    ) (POWER numeric)? wait_nowait?
    ;

disk_offline_clause
    : OFFLINE (
        quorum_regular? DISK id_expression (',' id_expression)*
        | DISKS IN quorum_regular? FAILGROUP id_expression (',' id_expression)*
    ) timeout_clause?
    ;

timeout_clause
    : DROP AFTER numeric (M_LETTER | H_LETTER)
    ;

rebalance_diskgroup_clause
    : REBALANCE (
        ((WITH | WITHOUT) phase+)? (POWER numeric) (WAIT | NOWAIT)?
        | MODIFY POWER numeric?
    )
    ;

phase
    : id_expression //TODO
    ;

check_diskgroup_clause
    : CHECK ALL? (REPAIR | NOREPAIR)? //inconsistent documentation
    ;

diskgroup_template_clauses
    : (ADD | MODIFY) TEMPLATE id_expression qualified_template_clause (
        ',' id_expression qualified_template_clause
    )*
    | DROP TEMPLATE id_expression (',' id_expression)*
    ;

qualified_template_clause
    : ATTRIBUTES '(' redundancy_clause? striping_clause? ')' //inconsistent documentation
    ;

redundancy_clause
    : MIRROR
    | HIGH
    | UNPROTECTED
    | PARITY
    | DOUBLE
    ;

striping_clause
    : FINE
    | COARSE
    ;

force_noforce
    : FORCE
    | NOFORCE
    ;

diskgroup_directory_clauses
    : ADD DIRECTORY filename (',' filename)*
    | DROP DIRECTORY filename force_noforce? (',' filename force_noforce?)*
    | RENAME DIRECTORY dir_name TO dir_name (',' dir_name TO dir_name)*
    ;

dir_name
    : CHAR_STRING
    ;

diskgroup_alias_clauses
    : ADD ALIAS CHAR_STRING FOR CHAR_STRING (',' CHAR_STRING FOR CHAR_STRING)*
    | DROP ALIAS CHAR_STRING (',' CHAR_STRING)*
    | RENAME ALIAS CHAR_STRING TO CHAR_STRING (',' CHAR_STRING TO CHAR_STRING)*
    ;

diskgroup_volume_clauses
    : add_volume_clause
    | modify_volume_clause
    | RESIZE VOLUME id_expression SIZE size_clause
    | DROP VOLUME id_expression
    ;

add_volume_clause
    : ADD VOLUME id_expression SIZE size_clause redundancy_clause? (
        STRIPE_WIDTH numeric (K_LETTER | M_LETTER)
    )? (STRIPE_COLUMNS numeric)?
    ;

modify_volume_clause
    : MODIFY VOLUME id_expression (MOUNTPATH CHAR_STRING)? (USAGE CHAR_STRING)?
    ;

diskgroup_attributes
    : SET ATTRIBUTE CHAR_STRING '=' CHAR_STRING
    ;

modify_diskgroup_file
    : MODIFY FILE CHAR_STRING ATTRIBUTE '(' disk_region_clause ')' (
        ',' CHAR_STRING ATTRIBUTE '(' disk_region_clause ')'
    )*
    ;

disk_region_clause
    :
    ;

drop_diskgroup_file_clause
    : DROP FILE filename (',' filename)*
    ;

convert_redundancy_clause
    : CONVERT REDUNDANCY TO FLEX
    ;

usergroup_clauses
    : ADD USERGROUP CHAR_STRING WITH MEMBER CHAR_STRING (',' CHAR_STRING)*
    | MODIFY USERGROUP CHAR_STRING (ADD | DROP) MEMBER CHAR_STRING (',' CHAR_STRING)*
    | DROP USERGROUP CHAR_STRING
    ;

user_clauses
    : ADD USER CHAR_STRING (',' CHAR_STRING)*
    | DROP USER CHAR_STRING (',' CHAR_STRING)* CASCADE?
    | REPLACE USER CHAR_STRING WITH CHAR_STRING (',' CHAR_STRING WITH CHAR_STRING)*
    ;

file_permissions_clause
    : SET PERMISSION (OWNER | GROUP | OTHER) '=' (NONE | READ (ONLY | WRITE)) (
        ',' (OWNER | GROUP | OTHER) '=' (NONE | READ (ONLY | WRITE))
    )* FOR FILE CHAR_STRING (',' CHAR_STRING)*
    ;

file_owner_clause
    : SET OWNERSHIP (OWNER | GROUP) '=' CHAR_STRING (',' (OWNER | GROUP) '=' CHAR_STRING)* FOR FILE CHAR_STRING (
        ',' CHAR_STRING
    )*
    ;

scrub_clause
    : SCRUB (FILE CHAR_STRING | DISK id_expression)? (REPAIR | NOREPAIR)? (
        POWER (AUTO | LOW | HIGH | MAX)
    )? wait_nowait? force_noforce? STOP?
    ;

quotagroup_clauses
    : ADD QUOTAGROUP id_expression (SET property_name '=' property_value)?
    | MODIFY QUOTAGROUP id_expression SET property_name '=' property_value
    | MOVE QUOTAGROUP id_expression TO id_expression
    | DROP QUOTAGROUP id_expression
    ;

property_name
    : id_expression
    ;

property_value
    : id_expression
    ;

filegroup_clauses
    : add_filegroup_clause
    | modify_filegroup_clause
    | move_to_filegroup_clause
    | drop_filegroup_clause
    ;

add_filegroup_clause
    : ADD FILEGROUP id_expression ((DATABASE | CLUSTER | VOLUME) id_expression | TEMPLATE) (
        FROM TEMPLATE id_expression
    )? (SET CHAR_STRING '=' CHAR_STRING)?
    ;

modify_filegroup_clause
    : MODIFY FILEGROUP id_expression SET CHAR_STRING '=' CHAR_STRING
    ;

move_to_filegroup_clause
    : MOVE FILE CHAR_STRING TO FILEGROUP id_expression
    ;

drop_filegroup_clause
    : DROP FILEGROUP id_expression CASCADE?
    ;

quorum_regular
    : QUORUM
    | REGULAR
    ;

undrop_disk_clause
    : UNDROP DISKS
    ;

diskgroup_availability
    : MOUNT (RESTRICTED | NORMAL)? (FORCE | NOFORCE)?
    | DISMOUNT (FORCE | NOFORCE)?
    ;

enable_disable_volume
    : (ENABLE | DISABLE) VOLUME (id_expression (',' id_expression)* | ALL)
    ;

// DDL -> SQL Statements for Stored PL/SQL Units

// Function DDLs

drop_function
    : DROP FUNCTION function_name
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-FLASHBACK-ARCHIVE.html
alter_flashback_archive
    : ALTER FLASHBACK ARCHIVE fa = id_expression (
        SET DEFAULT
        | (ADD | MODIFY) TABLESPACE ts = id_expression flashback_archive_quota?
        | REMOVE TABLESPACE rts = id_expression
        | MODIFY /*RETENTION*/ flashback_archive_retention // inconsistent documentation
        | PURGE (ALL | BEFORE (SCN expression | TIMESTAMP expression))
        | NO? OPTIMIZE DATA
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-HIERARCHY.html
alter_hierarchy
    : ALTER HIERARCHY (schema_name '.')? hn = id_expression (
        RENAME TO nhn = id_expression
        | COMPILE
    )
    ;

alter_function
    : ALTER FUNCTION function_name COMPILE DEBUG? compiler_parameters_clause* (REUSE SETTINGS)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-JAVA.html
alter_java
    : ALTER JAVA (SOURCE | CLASS) (schema_name '.')? o = id_expression (
        RESOLVER '(' ('(' match_string ','? (schema_name | '-') ')')+ ')'
    )? (COMPILE | RESOLVE | invoker_rights_clause)
    ;

match_string
    : DELIMITED_ID
    | '*'
    ;

create_function_body
    : CREATE (OR REPLACE)? (EDITIONABLE | NONEDITIONABLE)? FUNCTION function_name (
        '(' parameter (',' parameter)* ')'
    )? RETURN type_spec (
        invoker_rights_clause
        | accessible_by_clause
        | default_collation_clause
        | parallel_enable_clause
        | result_cache_clause
        | DETERMINISTIC
    )* (
        (PIPELINED? (IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec))
        | (PIPELINED | AGGREGATE) USING implementation_type_name
        | sql_macro_body
    ) ';'
    ;

sql_macro_body
    : SQL_MACRO IS BEGIN RETURN quoted_string SEMICOLON END
    ;

// Creation Function - Specific Clauses

parallel_enable_clause
    : PARALLEL_ENABLE partition_by_clause?
    ;

partition_by_clause
    : '(' PARTITION expression BY (ANY | (HASH | RANGE | LIST) paren_column_list) streaming_clause? ')'
    ;

result_cache_clause
    : RESULT_CACHE relies_on_part?
    ;

accessible_by_clause
    : ACCESSIBLE BY '(' accessor (',' accessor)* ')'
    ;

default_collation_clause
    : DEFAULT COLLATION USING_NLS_COMP
    ;

accessor
    :  unitKind=(FUNCTION | PROCEDURE | PACKAGE | TRIGGER | TYPE) function_name
    ;

relies_on_part
    : RELIES_ON '(' tableview_name (',' tableview_name)* ')'
    ;

streaming_clause
    : (ORDER | CLUSTER) expression BY paren_column_list
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-OUTLINE.html
alter_outline
    : ALTER OUTLINE (PUBLIC | PRIVATE)? o = id_expression outline_options+
    ;

outline_options
    : REBUILD
    | RENAME TO non = id_expression
    | CHANGE CATEGORY TO ncn = id_expression
    | ENABLE
    | DISABLE
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-LOCKDOWN-PROFILE.html
alter_lockdown_profile
    : ALTER LOCKDOWN PROFILE id_expression (
        lockdown_feature
        | lockdown_options
        | lockdown_statements
    ) (USERS '=' (ALL | COMMON | LOCAL))?
    ;

lockdown_feature
    : disable_enable FEATURE ('=' '(' string_list ')' | ALL (EXCEPT '=' '(' string_list ')')?)
    ;

lockdown_options
    : disable_enable OPTION ('=' '(' string_list ')' | ALL (EXCEPT '=' '(' string_list ')')?)
    ;

lockdown_statements
    : disable_enable STATEMENT (
        '=' '(' string_list ')'
        | '=' '(' CHAR_STRING ')' statement_clauses
        | ALL (EXCEPT '=' '(' string_list ')')?
    )
    ;

statement_clauses
    : CLAUSE (
        '=' '(' string_list ')'
        | '=' '(' CHAR_STRING ')' clause_options
        | ALL (EXCEPT '=' '(' string_list ')')?
    )
    ;

clause_options
    : OPTION (
        '=' '(' string_list ')'
        | '=' '(' CHAR_STRING ')' option_values+
        | ALL (EXCEPT '=' '(' string_list ')')?
    )
    ;

option_values
    : VALUE '=' '(' string_list ')'
    | (MINVALUE | MAXVALUE) '=' CHAR_STRING
    ;

string_list
    : CHAR_STRING (',' CHAR_STRING)*
    ;

disable_enable
    : DISABLE
    | ENABLE
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-LOCKDOWN-PROFILE.html
drop_lockdown_profile
    : DROP LOCKDOWN PROFILE p = id_expression
    ;

// Package DDLs

drop_package
    : DROP PACKAGE BODY? (schema_object_name '.')? package_name
    ;

alter_package
    : ALTER PACKAGE package_name COMPILE DEBUG? (PACKAGE | BODY | SPECIFICATION)? compiler_parameters_clause* (
        REUSE SETTINGS
    )?
    ;

create_package
    : CREATE (OR REPLACE)? (EDITIONABLE | NONEDITIONABLE)? PACKAGE (schema_object_name '.')? package_name invoker_rights_clause? (
        IS
        | AS
    ) package_obj_spec* END package_name?
    ;

create_package_body
    : CREATE (OR REPLACE)? (EDITIONABLE | NONEDITIONABLE)? PACKAGE BODY (schema_object_name '.')? package_name (
        IS
        | AS
    ) package_obj_body* (BEGIN seq_of_statements)? END package_name?
    ;

// Create Package Specific Clauses

package_obj_spec
    : pragma_declaration
    | exception_declaration
    | procedure_spec
    | function_spec
    | variable_declaration
    | subtype_declaration
    | cursor_declaration
    | type_declaration
    ;

procedure_spec
    : PROCEDURE identifier ('(' parameter ( ',' parameter)* ')')? ';'
    ;

function_spec
    : FUNCTION identifier ('(' parameter ( ',' parameter)* ')')? RETURN type_spec PIPELINED? DETERMINISTIC? (
        RESULT_CACHE
    )? ';'
    ;

package_obj_body
    : pragma_declaration
    | exception_declaration
    | procedure_spec
    | function_spec
    | subtype_declaration
    | cursor_declaration
    | variable_declaration
    | type_declaration
    | procedure_body
    | function_body
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/alter-pmem-filestore.html
alter_pmem_filestore
    : ALTER PMEM FILESTORE fsn = id_expression (
        RESIZE size_clause
        | autoextend_clause
        | MOUNT (MOUNTPOINT file_path)? (BACKINGFILE filename)? FORCE? //inconsistent documentation
        | DISMOUNT
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/drop-pmem-filestore.html
drop_pmem_filestore
    : DROP PMEM FILESTORE fsn = id_expression ((FORCE? INCLUDING | EXCLUDING) CONTENTS)?
    ;

// Procedure DDLs

drop_procedure
    : DROP PROCEDURE procedure_name
    ;

alter_procedure
    : ALTER PROCEDURE procedure_name COMPILE DEBUG? compiler_parameters_clause* (REUSE SETTINGS)?
    ;

function_body
    : FUNCTION identifier ('(' parameter (',' parameter)* ')')? RETURN type_spec (
        invoker_rights_clause
        | parallel_enable_clause
        | result_cache_clause
        | DETERMINISTIC
    )* (
        (PIPELINED? DETERMINISTIC? (IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec))
        | (PIPELINED | AGGREGATE) USING implementation_type_name
    ) ';'
    ;

procedure_body
    : PROCEDURE identifier ('(' parameter (',' parameter)* ')')? (IS | AS) (
        DECLARE? seq_of_declare_specs? body
        | call_spec
        | EXTERNAL
    ) ';'
    ;

create_procedure_body
    : CREATE (OR REPLACE)? PROCEDURE procedure_name ('(' parameter (',' parameter)* ')')? invoker_rights_clause? (
        IS
        | AS
    ) (DECLARE? seq_of_declare_specs? body | call_spec | EXTERNAL) ';'
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-RESOURCE-COST.html
alter_resource_cost
    : ALTER RESOURCE COST (
        (CPU_PER_SESSION | CONNECT_TIME | LOGICAL_READS_PER_SESSION | PRIVATE_SGA) UNSIGNED_INTEGER
    )+
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-OUTLINE.html
drop_outline
    : DROP OUTLINE o = id_expression
    ;

// Rollback Segment DDLs

//https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_2011.htm#SQLRF00816
alter_rollback_segment
    : ALTER ROLLBACK SEGMENT rollback_segment_name (
        ONLINE
        | OFFLINE
        | storage_clause
        | SHRINK (TO size_clause)?
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-RESTORE-POINT.html
drop_restore_point
    : DROP RESTORE POINT rp = id_expression (FOR PLUGGABLE DATABASE pdb = id_expression)?
    ;

drop_rollback_segment
    : DROP ROLLBACK SEGMENT rollback_segment_name
    ;

drop_role
    : DROP ROLE role_name
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/create-pmem-filestore.html
create_pmem_filestore
    : CREATE PMEM FILESTORE fsn = id_expression pmem_filestore_options+
    ;

pmem_filestore_options
    : MOUNTPOINT file_path
    | BACKINGFILE filename REUSE?
    | (SIZE | BLOCKSIZE) size_clause
    | autoextend_clause
    ;

file_path
    : CHAR_STRING
    ;

create_rollback_segment
    : CREATE PUBLIC? ROLLBACK SEGMENT rollback_segment_name (
        TABLESPACE tablespace
        | storage_clause
    )*
    ;

// Trigger DDLs

drop_trigger
    : DROP TRIGGER trigger_name
    ;

alter_trigger
    : ALTER TRIGGER alter_trigger_name = trigger_name (
        (ENABLE | DISABLE)
        | RENAME TO rename_trigger_name = trigger_name
        | COMPILE DEBUG? compiler_parameters_clause* (REUSE SETTINGS)?
    )
    ;

create_trigger
    : CREATE (OR REPLACE)? TRIGGER trigger_name (
        simple_dml_trigger
        | compound_dml_trigger
        | non_dml_trigger
    ) trigger_follows_clause? (ENABLE | DISABLE)? trigger_when_clause? trigger_body
    ;

trigger_follows_clause
    : FOLLOWS trigger_name (',' trigger_name)*
    ;

trigger_when_clause
    : WHEN '(' condition ')'
    ;

// Create Trigger Specific Clauses

simple_dml_trigger
    : (BEFORE | AFTER | INSTEAD OF) dml_event_clause referencing_clause? for_each_row?
    ;

for_each_row
    : FOR EACH ROW
    ;

compound_dml_trigger
    : FOR dml_event_clause referencing_clause?
    ;

non_dml_trigger
    : (BEFORE | AFTER) non_dml_event (OR non_dml_event)* ON (DATABASE | (schema_name '.')? SCHEMA)
    ;

trigger_body
    : compound_trigger_block
    | CALL identifier
    | trigger_block
    ;

routine_clause
    : routine_name function_argument?
    ;

compound_trigger_block
    : COMPOUND TRIGGER seq_of_declare_specs? timing_point_section+ END trigger_name?
    ;

timing_point_section
    : bk = BEFORE STATEMENT IS BEGIN tps_body END BEFORE STATEMENT ';'
    | bk = BEFORE EACH ROW IS BEGIN tps_body END BEFORE EACH ROW ';'
    | ak = AFTER STATEMENT IS BEGIN tps_body END AFTER STATEMENT ';'
    | ak = AFTER EACH ROW IS BEGIN tps_body END AFTER EACH ROW ';'
    ;

non_dml_event
    : ALTER
    | ANALYZE
    | ASSOCIATE STATISTICS
    | AUDIT
    | COMMENT
    | CREATE
    | DISASSOCIATE STATISTICS
    | DROP
    | GRANT
    | NOAUDIT
    | RENAME
    | REVOKE
    | TRUNCATE
    | DDL
    | STARTUP
    | SHUTDOWN
    | DB_ROLE_CHANGE
    | LOGON
    | LOGOFF
    | SERVERERROR
    | SUSPEND
    | DATABASE
    | SCHEMA
    | FOLLOWS
    ;

dml_event_clause
    : dml_event_element (OR dml_event_element)* ON dml_event_nested_clause? tableview_name
    ;

dml_event_element
    : (DELETE | INSERT | UPDATE) (OF column_list)?
    ;

dml_event_nested_clause
    : NESTED TABLE tableview_name OF
    ;

referencing_clause
    : REFERENCING referencing_element+
    ;

referencing_element
    : (NEW | OLD | PARENT) column_alias
    ;

// DDLs

drop_type
    : DROP TYPE BODY? type_name (FORCE | VALIDATE)?
    ;

alter_type
    : ALTER TYPE type_name (
        compile_type_clause
        | replace_type_clause
        //TODO | {input.LT(2).getText().equalsIgnoreCase("attribute")}? alter_attribute_definition
        | alter_method_spec
        | alter_collection_clauses
        | modifier_clause
        | overriding_subprogram_spec
    ) dependent_handling_clause?
    ;

// Alter Type Specific Clauses

compile_type_clause
    : COMPILE DEBUG? (SPECIFICATION | BODY)? compiler_parameters_clause* (REUSE SETTINGS)?
    ;

replace_type_clause
    : REPLACE invoker_rights_clause? AS OBJECT '(' object_member_spec (',' object_member_spec)* ')'
    ;

alter_method_spec
    : alter_method_element (',' alter_method_element)*
    ;

alter_method_element
    : (ADD | DROP) (map_order_function_spec | subprogram_spec)
    ;

alter_attribute_definition
    : (ADD | MODIFY | DROP) ATTRIBUTE (
        attribute_definition
        | '(' attribute_definition (',' attribute_definition)* ')'
    )
    ;

attribute_definition
    : attribute_name type_spec?
    ;

alter_collection_clauses
    : MODIFY (LIMIT expression | ELEMENT TYPE type_spec)
    ;

dependent_handling_clause
    : INVALIDATE
    | CASCADE (CONVERT TO SUBSTITUTABLE | NOT? INCLUDING TABLE DATA)? dependent_exceptions_part?
    ;

dependent_exceptions_part
    : FORCE? EXCEPTIONS INTO tableview_name
    ;

create_type
    : CREATE (OR REPLACE)? TYPE (type_definition | type_body)
    ;

// Create Type Specific Clauses

type_definition
    : type_name (OID CHAR_STRING)? FORCE? object_type_def?
    ;

object_type_def
    : invoker_rights_clause? (object_as_part | object_under_part) sqlj_object_type? (
        '(' object_member_spec (',' object_member_spec)* ')'
    )? modifier_clause*
    ;

object_as_part
    : (IS | AS) (OBJECT | varray_type_def | nested_table_type_def)
    ;

object_under_part
    : UNDER type_spec
    ;

nested_table_type_def
    : TABLE OF type_spec (NOT NULL_)?
    ;

sqlj_object_type
    : EXTERNAL NAME expression LANGUAGE JAVA USING (SQLDATA | CUSTOMDATUM | ORADATA)
    ;

type_body
    : BODY type_name (IS | AS) (type_body_elements)+ END
    ;

type_body_elements
    : map_order_func_declaration
    | subprog_decl_in_type
    | overriding_subprogram_spec
    ;

map_order_func_declaration
    : (MAP | ORDER) MEMBER func_decl_in_type
    ;

subprog_decl_in_type
    : (MEMBER | STATIC) (proc_decl_in_type | func_decl_in_type | constructor_declaration)
    ;

proc_decl_in_type
    : PROCEDURE procedure_name '(' type_elements_parameter (',' type_elements_parameter)* ')' (
        IS
        | AS
    ) (call_spec | DECLARE? seq_of_declare_specs? body ';')
    ;

func_decl_in_type
    : FUNCTION function_name ('(' type_elements_parameter (',' type_elements_parameter)* ')')? RETURN type_spec (
        IS
        | AS
    ) (call_spec | DECLARE? seq_of_declare_specs? body ';')
    ;

constructor_declaration
    : FINAL? INSTANTIABLE? CONSTRUCTOR FUNCTION type_spec (
        '(' (SELF IN OUT type_spec ',') type_elements_parameter (',' type_elements_parameter)* ')'
    )? RETURN SELF AS RESULT (IS | AS) (call_spec | DECLARE? seq_of_declare_specs? body ';')
    ;

// Common Type Clauses

modifier_clause
    : NOT? (INSTANTIABLE | FINAL | OVERRIDING)
    ;

object_member_spec
    : identifier type_spec sqlj_object_type_attr?
    | element_spec
    ;

sqlj_object_type_attr
    : EXTERNAL NAME expression
    ;

element_spec
    : modifier_clause? element_spec_options+ (',' pragma_clause)?
    ;

element_spec_options
    : subprogram_spec
    | constructor_spec
    | map_order_function_spec
    ;

subprogram_spec
    : (MEMBER | STATIC) (type_procedure_spec | type_function_spec)
    ;

// TODO: should be refactored such as Procedure body and Function body, maybe Type_Function_Body and overriding_function_body
overriding_subprogram_spec
    : OVERRIDING MEMBER overriding_function_spec
    ;

overriding_function_spec
    : FUNCTION function_name ('(' type_elements_parameter (',' type_elements_parameter)* ')')? RETURN (
        type_spec
        | SELF AS RESULT
    ) (PIPELINED? (IS | AS) (DECLARE? seq_of_declare_specs? body))? ';'?
    ;

type_procedure_spec
    : PROCEDURE procedure_name '(' type_elements_parameter (',' type_elements_parameter)* ')' (
        (IS | AS) call_spec
    )?
    ;

type_function_spec
    : FUNCTION function_name ('(' type_elements_parameter (',' type_elements_parameter)* ')')? RETURN (
        type_spec
        | SELF AS RESULT
    ) ((IS | AS) call_spec | EXTERNAL VARIABLE? NAME expression)?
    ;

constructor_spec
    : FINAL? INSTANTIABLE? CONSTRUCTOR FUNCTION type_spec (
        '(' (SELF IN OUT type_spec ',') type_elements_parameter (',' type_elements_parameter)* ')'
    )? RETURN SELF AS RESULT ((IS | AS) call_spec)?
    ;

map_order_function_spec
    : (MAP | ORDER) MEMBER type_function_spec
    ;

pragma_clause
    : PRAGMA RESTRICT_REFERENCES '(' pragma_elements (',' pragma_elements)* ')'
    ;

pragma_elements
    : identifier
    | DEFAULT
    ;

type_elements_parameter
    : parameter_name type_spec
    ;

// Sequence DDLs

drop_sequence
    : DROP SEQUENCE sequence_name
    ;

alter_sequence
    : ALTER SEQUENCE sequence_name sequence_spec+
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-SESSION.html
alter_session
    : ALTER SESSION (
        ADVISE ( COMMIT | ROLLBACK | NOTHING)
        | CLOSE DATABASE LINK parameter_name
        | enable_or_disable COMMIT IN PROCEDURE
        | enable_or_disable GUARD
        | (enable_or_disable | FORCE) PARALLEL (DML | DDL | QUERY) (
            PARALLEL (literal | parameter_name)
        )?
        | SET alter_session_set_clause
    )
    ;

alter_session_set_clause
    : (parameter_name '=' parameter_value)+
    | EDITION '=' en = id_expression
    | CONTAINER '=' cn = id_expression (SERVICE '=' sn = id_expression)?
    | ROW ARCHIVAL VISIBILITY '=' (ACTIVE | ALL)
    | DEFAULT_COLLATION '=' (c = id_expression | NONE)
    ;

create_sequence
    : CREATE SEQUENCE sequence_name (sequence_start_clause | sequence_spec)*
    ;

// Common Sequence

sequence_spec
    : INCREMENT BY UNSIGNED_INTEGER
    | MAXVALUE UNSIGNED_INTEGER
    | NOMAXVALUE
    | MINVALUE UNSIGNED_INTEGER
    | NOMINVALUE
    | CYCLE
    | NOCYCLE
    | CACHE UNSIGNED_INTEGER
    | NOCACHE
    | ORDER
    | NOORDER
    ;

sequence_start_clause
    : START WITH UNSIGNED_INTEGER
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-ANALYTIC-VIEW.html
create_analytic_view
    : CREATE (OR REPLACE)? (NOFORCE | FORCE)? ANALYTIC VIEW av = id_expression (
        SHARING '=' (METADATA | NONE)
    )? classification_clause* cav_using_clause? dim_by_clause? measures_clause? default_measure_clause? default_aggregate_clause? cache_clause?
        fact_columns_clause? qry_transform_clause?
    ;

classification_clause
    // : (CAPTION c=quoted_string)? (DESCRIPTION d=quoted_string)? classification_item*
    // to handle - 'rule contains a closure with at least one alternative that can match an empty string'
    : (caption_clause description_clause? | caption_clause? description_clause) classification_item*
    | caption_clause? description_clause? classification_item+
    ;

caption_clause
    : CAPTION c = quoted_string
    ;

description_clause
    : DESCRIPTION d = quoted_string
    ;

classification_item
    : CLASSIFICATION cn = id_expression (VALUE cv = quoted_string)? (LANGUAGE language)?
    ;

language
    : NULL_
    | nls = id_expression
    ;

cav_using_clause
    : USING (schema_name '.')? t = id_expression REMOTE? (AS? ta = id_expression)?
    ;

dim_by_clause
    : DIMENSION BY '(' dim_key (',' dim_key)* ')'
    ;

dim_key
    : dim_ref classification_clause* KEY (
        '(' (a = id_expression '.')? f = column_name (',' (a = id_expression '.')? f = column_name)* ')'
        | (a = id_expression '.')? f = column_name
    ) REFERENCES DISTINCT? ('(' attribute_name (',' attribute_name) ')' | attribute_name) HIERARCHIES '(' hier_ref (
        ',' hier_ref
    )* ')'
    ;

dim_ref
    : (schema_name '.')? ad = id_expression (AS? da = id_expression)?
    ;

hier_ref
    : (schema_name '.')? h = id_expression (AS? ha = id_expression)? DEFAULT?
    ;

measures_clause
    : MEASURES '(' av_measure (',' av_measure)* ')'
    ;

av_measure
    : mn = id_expression (base_meas_clause | calc_meas_clause)? //classification_clause*
    ;

base_meas_clause
    : FACT /*FOR MEASURE*/ bm = id_expression meas_aggregate_clause? //FIXME inconsistent documentation
    ;

meas_aggregate_clause
    : AGGREGATE BY aggregate_function_name
    ;

calc_meas_clause
    : /*m=id_expression*/ AS '(' expression ')' //FIXME inconsistent documentation
    ;

default_measure_clause
    : DEFAULT MEASURE m = id_expression
    ;

default_aggregate_clause
    : DEFAULT AGGREGATE BY aggregate_function_name
    ;

cache_clause
    : CACHE cache_specification (',' cache_specification)*
    ;

cache_specification
    : MEASURE GROUP (
        ALL
        | '(' id_expression (',' id_expression)* ')' levels_clause (',' levels_clause)*
    )
    ;

levels_clause
    : LEVELS '(' level_specification (',' level_specification)* ')' level_group_type
    ;

level_specification
    : '(' ((d = id_expression '.')? h = id_expression '.')? l = id_expression ')'
    ;

level_group_type
    : DYNAMIC
    | MATERIALIZED (USING (schema_name '.')? t = id_expression)?
    ;

fact_columns_clause
    : FACT COLUMN f = column_name (AS? fa = id_expression (',' AS? fa = id_expression)*)?
    ;

qry_transform_clause
    : ENABLE QUERY TRANSFORM (RELY | NORELY)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-ATTRIBUTE-DIMENSION.html
create_attribute_dimension
    : CREATE (OR REPLACE)? (NOFORCE | FORCE)? ATTRIBUTE DIMENSION (schema_name '.')? ad = id_expression (
        SHARING '=' (METADATA | NONE)
    )? classification_clause* (DIMENSION TYPE (STANDARD | TIME))? ad_using_clause attributes_clause ad_level_clause+ all_clause?
    ;

ad_using_clause
    : USING source_clause (',' source_clause)* join_path_clause*
    ;

source_clause
    : (schema_name '.')? ftov = id_expression REMOTE? (AS? a = id_expression)?
    ;

join_path_clause
    : JOIN PATH jpn = id_expression ON join_condition
    ;

join_condition
    : join_condition_item (AND join_condition_item)*
    ;

join_condition_item
    : (a = id_expression '.')? column_name '=' (b = id_expression '.')? column_name
    ;

attributes_clause
    : ATTRIBUTES '(' ad_attributes_clause (',' ad_attributes_clause)* ')'
    ;

ad_attributes_clause
    : (a = id_expression '.')? column_name (AS? an = id_expression)? classification_clause*
    ;

ad_level_clause
    : LEVEL l = id_expression (NOT NULL_ | SKIP_ WHEN NULL_)? (
        LEVEL TYPE (
            STANDARD
            | YEARS
            | HALF_YEARS
            | QUARTERS
            | MONTHS
            | WEEKS
            | DAYS
            | HOURS
            | MINUTES
            | SECONDS
        )
    )? classification_clause* //inconsistent documentation - LEVEL TYPE goes after the classification_clause rule
    key_clause alternate_key_clause? (MEMBER NAME expression)? (MEMBER CAPTION expression)? (
        MEMBER DESCRIPTION expression
    )? (ORDER BY (MIN | MAX)? dim_order_clause (',' (MIN | MAX)? dim_order_clause)*)? (
        DETERMINES '(' id_expression (',' id_expression)* ')'
    )?
    ;

key_clause
    : KEY (a = id_expression | '(' id_expression (',' id_expression)* ')')
    ;

alternate_key_clause
    : ALTERNATE key_clause
    ;

dim_order_clause
    : a = id_expression (ASC | DESC)? (NULLS (FIRST | LAST))?
    ;

all_clause
    : ALL MEMBER (
        NAME expression (MEMBER CAPTION expression)?
        | CAPTION expression (MEMBER DESCRIPTION expression)?
        | DESCRIPTION expression
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-AUDIT-POLICY-Unified-Auditing.html
create_audit_policy
    : CREATE AUDIT POLICY p = id_expression privilege_audit_clause? action_audit_clause? role_audit_clause? (
        WHEN quoted_string EVALUATE PER (STATEMENT | SESSION | INSTANCE)
    )? (ONLY TOPLEVEL)? container_clause?
    ;

privilege_audit_clause
    : PRIVILEGES system_privilege (',' system_privilege)*
    ;

action_audit_clause
    : (standard_actions | component_actions | system_actions)+
    ;

system_actions
    : ACTIONS system_privilege (',' system_privilege)*
    ;

standard_actions
    : ACTIONS actions_clause (',' actions_clause)*
    ;

actions_clause
    : (object_action | ALL) ON (
        DIRECTORY directory_name
        | (MINING MODEL)? (schema_name '.')? id_expression
    )
    | (system_action | ALL)
    ;

object_action
    : ALTER
    | GRANT
    | READ
    | EXECUTE
    | AUDIT
    | COMMENT
    | DELETE
    | INDEX
    | INSERT
    | LOCK
    | SELECT
    | UPDATE
    | FLASHBACK
    | RENAME
    ;

system_action
    : id_expression // SELECT name FROM AUDITABLE_SYSTEM_ACTIONS WHERE component = 'Standard';
    | (CREATE | ALTER | DROP) JAVA
    | LOCK TABLE
    | (READ | WRITE | EXECUTE) DIRECTORY
    ;

component_actions
    : ACTIONS COMPONENT '=' (
        (DATAPUMP | DIRECT_LOAD | OLS | XS) component_action (',' component_action)*
        | DV component_action ON id_expression (',' component_action ON id_expression)*
        | PROTOCOL (FTP | HTTP | AUTHENTICATION)
    )
    ;

component_action
    : id_expression // SELECT name FROM auditable_system_actions WHERE component = 'Datapump';
    ;

role_audit_clause
    : ROLES role_name (',' role_name)*
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-CONTROLFILE.html
create_controlfile
    : CREATE CONTROLFILE REUSE? SET? DATABASE d = id_expression logfile_clause? (
        RESETLOGS
        | NORESETLOGS
    ) (DATAFILE file_specification (',' file_specification)*)? controlfile_options* character_set_clause?
    ;

controlfile_options
    : MAXLOGFILES numeric
    | MAXLOGMEMBERS numeric
    | MAXLOGHISTORY numeric
    | MAXDATAFILES numeric
    | MAXINSTANCES numeric
    | ARCHIVELOG
    | NOARCHIVELOG
    | FORCE LOGGING
    | SET STANDBY NOLOGGING FOR (DATA AVAILABILITY | LOAD PERFORMANCE)
    ;

logfile_clause
    : LOGFILE (GROUP? numeric)? file_specification (',' (GROUP? numeric)? file_specification)*
    ;

character_set_clause
    : CHARACTER SET cs = id_expression
    ;

file_specification
    : datafile_tempfile_spec
    | redo_log_file_spec
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-DISKGROUP.html
create_diskgroup
    : CREATE DISKGROUP id_expression (
        (HIGH | NORMAL | FLEX | EXTENDED (SITE sn = id_expression)? | EXTERNAL) REDUNDANCY
    )? (
        quorum_regular? (FAILGROUP fg = id_expression)? DISK qualified_disk_clause (
            ',' qualified_disk_clause
        )*
    )+ (ATTRIBUTE an = CHAR_STRING '=' av = CHAR_STRING (',' CHAR_STRING '=' CHAR_STRING)*)?
    ;

qualified_disk_clause
    : ss = CHAR_STRING (NAME dn = id_expression)? (SIZE size_clause)? force_noforce?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-EDITION.html
create_edition
    : CREATE EDITION e = id_expression (AS CHILD OF pe = id_expression)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-FLASHBACK-ARCHIVE.html
create_flashback_archive
    : CREATE FLASHBACK ARCHIVE DEFAULT? fa = id_expression TABLESPACE ts = id_expression flashback_archive_quota? (
        NO? OPTIMIZE DATA
    )? flashback_archive_retention
    ;

flashback_archive_quota
    : QUOTA UNSIGNED_INTEGER (M_LETTER | G_LETTER | T_LETTER | P_LETTER | E_LETTER)
    ;

flashback_archive_retention
    : RETENTION UNSIGNED_INTEGER (YEAR | MONTH | DAY)
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-HIERARCHY.html
create_hierarchy
    : CREATE (OR REPLACE)? (NO? FORCE)? HIERARCHY (schema_name '.')? h = id_expression (
        SHARING '=' (METADATA | NONE)
    )? classification_clause* hier_using_clause level_hier_clause hier_attrs_clause?
    ;

hier_using_clause
    : USING (schema_name '.')? ad = id_expression
    ;

level_hier_clause
    : '(' (l = id_expression (CHILD OF)?)+ ')'
    ;

hier_attrs_clause
    : HIERARCHICAL ATTRIBUTES '(' hier_attr_clause ')'
    ;

hier_attr_clause
    : hier_attr_name classification_clause*
    ;

hier_attr_name
    : MEMBER_NAME
    | MEMBER_UNIQUE_NAME
    | MEMBER_CAPTION
    | MEMBER_DESCRIPTION
    | LEVEL_NAME
    | HIER_ORDER
    | DEPTH
    | IS_LEAF
    | PARENT_LEVEL_NAME
    | PARENT_UNIQUE_NAME
    ;

create_index
    : CREATE (UNIQUE | BITMAP)? INDEX index_name ON (
        cluster_index_clause
        | table_index_clause
        | bitmap_join_index_clause
    ) (USABLE | UNUSABLE)? ((DEFERRED | IMMEDIATE) INVALIDATION)?
    ;

cluster_index_clause
    : CLUSTER cluster_name index_attributes?
    ;

cluster_name
    : (id_expression '.')? id_expression
    ;

table_index_clause
    : tableview_name table_alias? '(' index_expr (ASC | DESC)? (',' index_expr (ASC | DESC)?)* ')' index_properties?
    ;

bitmap_join_index_clause
    : tableview_name '(' (tableview_name | table_alias)? column_name (ASC | DESC)? (
        ',' (tableview_name | table_alias)? column_name (ASC | DESC)?
    )* ')' FROM tableview_name table_alias (',' tableview_name table_alias)* where_clause local_partitioned_index? index_attributes?
    ;

index_expr
    : column_name
    | expression
    ;

index_properties
    : (global_partitioned_index | local_partitioned_index | index_attributes)+
    | INDEXTYPE IS (domain_index_clause | xmlindex_clause)
    ;

domain_index_clause
    : indextype local_domain_index_clause? parallel_clause? (PARAMETERS '(' odci_parameters ')')?
    ;

local_domain_index_clause
    : LOCAL (
        '(' PARTITION partition_name (PARAMETERS '(' odci_parameters ')')? (
            ',' PARTITION partition_name (PARAMETERS '(' odci_parameters ')')?
        )* ')'
    )?
    ;

xmlindex_clause
    : (XDB '.')? XMLINDEX local_xmlindex_clause? parallel_clause? //TODO xmlindex_parameters_clause?
    ;

local_xmlindex_clause
    : LOCAL (
        '(' PARTITION partition_name (
            ',' PARTITION partition_name //TODO xmlindex_parameters_clause?
        )* ')'
    )?
    ;

global_partitioned_index
    : GLOBAL PARTITION BY (
        RANGE '(' column_name (',' column_name)* ')' '(' index_partitioning_clause (
            ',' index_partitioning_clause
        )* ')'
        | HASH '(' column_name (',' column_name)* ')' (
            individual_hash_partitions
            | hash_partitions_by_quantity
        )
    )
    ;

index_partitioning_clause
    : PARTITION partition_name? VALUES LESS THAN '(' literal (',' literal)* ')' segment_attributes_clause?
    ;

local_partitioned_index
    : LOCAL (
        on_range_partitioned_table
        | on_list_partitioned_table
        | on_hash_partitioned_table
        | on_comp_partitioned_table
    )?
    ;

on_range_partitioned_table
    : '(' partitioned_table (',' partitioned_table)* ')'
    ;

on_list_partitioned_table
    : '(' partitioned_table (',' partitioned_table)* ')'
    ;

partitioned_table
    : PARTITION partition_name? (segment_attributes_clause | key_compression)* UNUSABLE?
    ;

on_hash_partitioned_table
    : STORE IN '(' tablespace (',' tablespace)* ')'
    | '(' on_hash_partitioned_clause (',' on_hash_partitioned_clause)* ')'
    ;

on_hash_partitioned_clause
    : PARTITION partition_name? (TABLESPACE tablespace)? key_compression? UNUSABLE?
    ;

on_comp_partitioned_table
    : (STORE IN '(' tablespace (',' tablespace)* ')')? '(' on_comp_partitioned_clause (
        ',' on_comp_partitioned_clause
    )* ')'
    ;

on_comp_partitioned_clause
    : PARTITION partition_name? (segment_attributes_clause | key_compression)* UNUSABLE index_subpartition_clause?
    ;

index_subpartition_clause
    : STORE IN '(' tablespace (',' tablespace)* ')'
    | '(' index_subpartition_subclause (',' index_subpartition_subclause)* ')'
    ;

index_subpartition_subclause
    : SUBPARTITION subpartition_name? (TABLESPACE tablespace)? key_compression? UNUSABLE?
    ;

odci_parameters
    : CHAR_STRING
    ;

indextype
    : (id_expression '.')? id_expression
    ;

//https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_1010.htm#SQLRF00805
alter_index
    : ALTER INDEX index_name (alter_index_ops_set1 | alter_index_ops_set2)
    ;

alter_index_ops_set1
    : (
        deallocate_unused_clause
        | allocate_extent_clause
        | shrink_clause
        | parallel_clause
        | physical_attributes_clause
        | logging_clause
    )+
    ;

alter_index_ops_set2
    : rebuild_clause
    | PARAMETERS '(' odci_parameters ')'
    | COMPILE
    | enable_or_disable
    | UNUSABLE
    | visible_or_invisible
    | RENAME TO new_index_name
    | COALESCE
    | monitoring_nomonitoring USAGE
    | UPDATE BLOCK REFERENCES
    | alter_index_partitioning
    ;

visible_or_invisible
    : VISIBLE
    | INVISIBLE
    ;

monitoring_nomonitoring
    : MONITORING
    | NOMONITORING
    ;

rebuild_clause
    : REBUILD (PARTITION partition_name | SUBPARTITION subpartition_name | REVERSE | NOREVERSE)? (
        parallel_clause
        | TABLESPACE tablespace
        | PARAMETERS '(' odci_parameters ')'
        //TODO        | xmlindex_parameters_clause
        | ONLINE
        | physical_attributes_clause
        | key_compression
        | logging_clause
    )*
    ;

alter_index_partitioning
    : modify_index_default_attrs
    | add_hash_index_partition
    | modify_index_partition
    | rename_index_partition
    | drop_index_partition
    | split_index_partition
    | coalesce_index_partition
    | modify_index_subpartition
    ;

modify_index_default_attrs
    : MODIFY DEFAULT ATTRIBUTES (FOR PARTITION partition_name)? (
        physical_attributes_clause
        | TABLESPACE (tablespace | DEFAULT)
        | logging_clause
    )
    ;

add_hash_index_partition
    : ADD PARTITION partition_name? (TABLESPACE tablespace)? key_compression? parallel_clause?
    ;

coalesce_index_partition
    : COALESCE PARTITION parallel_clause?
    ;

modify_index_partition
    : MODIFY PARTITION partition_name (
        modify_index_partitions_ops+
        | PARAMETERS '(' odci_parameters ')'
        | COALESCE
        | UPDATE BLOCK REFERENCES
        | UNUSABLE
    )
    ;

modify_index_partitions_ops
    : deallocate_unused_clause
    | allocate_extent_clause
    | physical_attributes_clause
    | logging_clause
    | key_compression
    ;

rename_index_partition
    : RENAME (PARTITION partition_name | SUBPARTITION subpartition_name) TO new_partition_name
    ;

drop_index_partition
    : DROP PARTITION partition_name
    ;

split_index_partition
    : SPLIT PARTITION partition_name_old AT '(' literal (',' literal)* ')' (
        INTO '(' index_partition_description ',' index_partition_description ')'
    )? parallel_clause?
    ;

index_partition_description
    : PARTITION (
        partition_name (
            (segment_attributes_clause | key_compression)+
            | PARAMETERS '(' odci_parameters ')'
        ) UNUSABLE?
    )?
    ;

modify_index_subpartition
    : MODIFY SUBPARTITION subpartition_name (
        UNUSABLE
        | allocate_extent_clause
        | deallocate_unused_clause
    )
    ;

partition_name_old
    : partition_name
    ;

new_partition_name
    : partition_name
    ;

new_index_name
    : index_name
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-INMEMORY-JOIN-GROUP.html
alter_inmemory_join_group
    : ALTER INMEMORY JOIN GROUP (schema_name '.')? jg = id_expression (ADD | REMOVE) '(' (
        schema_name '.'
    )? t = id_expression '(' c = id_expression ')' ')'
    ;

create_user
    : CREATE USER user_object_name (
        identified_by
        | identified_other_clause
        | user_tablespace_clause
        | quota_clause
        | profile_clause
        | password_expire_clause
        | user_lock_clause
        | user_editions_clause
        | container_clause
    )+
    ;

// The standard clauses only permit one user per statement.
// The proxy clause allows multiple users for a proxy designation.
alter_user
    : ALTER USER user_object_name (
        alter_identified_by
        | identified_other_clause
        | user_tablespace_clause
        | quota_clause
        | profile_clause
        | user_default_role_clause
        | password_expire_clause
        | user_lock_clause
        | alter_user_editions_clause
        | container_clause
        | container_data_clause
    )+
    | user_object_name (',' user_object_name)* proxy_clause
    ;

drop_user
    : DROP USER user_object_name CASCADE?
    ;

alter_identified_by
    : identified_by (REPLACE id_expression)?
    ;

identified_by
    : IDENTIFIED BY id_expression
    ;

identified_other_clause
    : IDENTIFIED (EXTERNALLY | GLOBALLY) (AS quoted_string)?
    ;

user_tablespace_clause
    : (DEFAULT | TEMPORARY) TABLESPACE id_expression
    ;

quota_clause
    : QUOTA (size_clause | UNLIMITED) ON id_expression
    ;

profile_clause
    : PROFILE id_expression
    ;

role_clause
    : role_name (',' role_name)*
    | ALL (EXCEPT role_name (',' role_name)*)*
    ;

user_default_role_clause
    : DEFAULT ROLE (NONE | role_clause)
    ;

password_expire_clause
    : PASSWORD EXPIRE
    ;

user_lock_clause
    : ACCOUNT (LOCK | UNLOCK)
    ;

user_editions_clause
    : ENABLE EDITIONS
    ;

alter_user_editions_clause
    : user_editions_clause (FOR regular_id (',' regular_id)*)? FORCE?
    ;

proxy_clause
    : REVOKE CONNECT THROUGH (ENTERPRISE USERS | user_object_name)
    | GRANT CONNECT THROUGH (
        ENTERPRISE USERS
        | user_object_name (WITH (NO ROLES | ROLE role_clause))? (AUTHENTICATION REQUIRED)? (
            AUTHENTICATED USING (PASSWORD | CERTIFICATE | DISTINGUISHED NAME)
        )?
    )
    ;

container_names
    : LEFT_PAREN id_expression (',' id_expression)* RIGHT_PAREN
    ;

set_container_data
    : SET CONTAINER_DATA EQUALS_OP (ALL | DEFAULT | container_names)
    ;

add_rem_container_data
    : (ADD | REMOVE) CONTAINER_DATA EQUALS_OP container_names
    ;

container_data_clause
    : set_container_data
    | add_rem_container_data (FOR container_tableview_name)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ADMINISTER-KEY-MANAGEMENT.html
administer_key_management
    : ADMINISTER KEY MANAGEMENT (
        keystore_management_clauses
        | key_management_clauses
        | secret_management_clauses
        | zero_downtime_software_patching_clauses
    )
    ;

keystore_management_clauses
    : create_keystore
    | open_keystore
    | close_keystore
    | backup_keystore
    | alter_keystore_password
    | merge_into_new_keystore
    | merge_into_existing_keystore
    | isolate_keystore
    | unite_keystore
    ;

create_keystore
    : CREATE (
        KEYSTORE ksl = CHAR_STRING
        | LOCAL? AUTO_LOGIN KEYSTORE FROM KEYSTORE ksl = CHAR_STRING
    ) IDENTIFIED BY keystore_password
    ;

open_keystore
    : SET KEYSTORE OPEN force_keystore? identified_by_store container_clause?
    ;

force_keystore
    : FORCE KEYSTORE
    ;

close_keystore
    : SET KEYSTORE CLOSE identified_by_store? container_clause?
    ;

backup_keystore
    : BACKUP KEYSTORE (USING bi = CHAR_STRING)? force_keystore? identified_by_store (
        TO ksl = CHAR_STRING
    )?
    ;

alter_keystore_password
    : ALTER KEYSTORE PASSWORD force_keystore? IDENTIFIED BY o = keystore_password SET n = keystore_password with_backup_clause?
    ;

merge_into_new_keystore
    : MERGE KEYSTORE ksl1 = CHAR_STRING identified_by_password_clause? AND KEYSTORE ksl2 = CHAR_STRING identified_by_password_clause? INTO NEW
        KEYSTORE ksl2 = CHAR_STRING identified_by_password_clause
    ;

merge_into_existing_keystore
    : MERGE KEYSTORE ksl1 = CHAR_STRING identified_by_password_clause? INTO EXISTING KEYSTORE ksl2 = CHAR_STRING identified_by_password_clause
        with_backup_clause?
    ;

isolate_keystore
    : FORCE? ISOLATE KEYSTORE IDENTIFIED BY i = keystore_password FROM ROOT KEYSTORE force_keystore? identified_by_store with_backup_clause?
    ;

unite_keystore
    : UNITE KEYSTORE IDENTIFIED BY i = keystore_password WITH ROOT KEYSTORE force_keystore? identified_by_store with_backup_clause?
    ;

key_management_clauses
    : set_key
    | create_key
    | use_key
    | set_key_tag
    | export_keys
    | import_keys
    | migrate_keys
    | reverse_migrate_keys
    | move_keys
    ;

set_key
    : SET ENCRYPTION? KEY ((mkid ':')? mk)? using_tag_clause? using_algorithm_clause? force_keystore? identified_by_store with_backup_clause?
        container_clause?
    ;

create_key
    : CREATE ENCRYPTION? KEY ((mkid ':')? mk)? using_tag_clause? using_algorithm_clause? force_keystore? identified_by_store with_backup_clause?
        container_clause?
    ;

mkid
    : CHAR_STRING
    ;

mk
    : CHAR_STRING
    ;

use_key
    : USE ENCRYPTION? KEY k = CHAR_STRING using_tag_clause? force_keystore? identified_by_store with_backup_clause?
    ;

set_key_tag
    : SET TAG t = CHAR_STRING FOR k = CHAR_STRING force_keystore? identified_by_store with_backup_clause?
    ;

export_keys
    : EXPORT ENCRYPTION? KEYS WITH SECRET secret TO filename force_keystore? identified_by_store (
        WITH IDENTIFIER IN (CHAR_STRING (',' CHAR_STRING)* | '(' subquery ')')
    )?
    ;

import_keys
    : IMPORT ENCRYPTION? KEYS WITH SECRET secret FROM filename force_keystore? identified_by_store with_backup_clause?
    ;

migrate_keys
    : SET ENCRYPTION? KEY IDENTIFIED BY hsm = secret force_keystore? MIGRATE USING keystore_password with_backup_clause?
    ;

reverse_migrate_keys
    : SET ENCRYPTION? KEY IDENTIFIED BY s = secret force_keystore? REVERSE MIGRATE USING hsm = secret
    ;

move_keys
    : MOVE ENCRYPTION? KEYS TO NEW KEYSTORE ksl1 = CHAR_STRING IDENTIFIED BY ksp1 = keystore_password FROM FORCE? KEYSTORE IDENTIFIED BY ksp =
        keystore_password (WITH IDENTIFIER IN (CHAR_STRING (',' CHAR_STRING)* | subquery))? with_backup_clause?
    ;

identified_by_store
    : IDENTIFIED BY (EXTERNAL STORE | keystore_password)
    ;

using_algorithm_clause
    : USING ALGORITHM ea = CHAR_STRING
    ;

using_tag_clause
    : USING TAG t = CHAR_STRING
    ;

secret_management_clauses
    : add_update_secret
    | delete_secret
    | add_update_secret_seps
    | delete_secret_seps
    ;

add_update_secret
    : (ADD | UPDATE) SECRET s = CHAR_STRING FOR CLIENT ci = CHAR_STRING using_tag_clause? force_keystore? identified_by_store? with_backup_clause?
    ;

delete_secret
    : DELETE SECRET FOR CLIENT ci = CHAR_STRING force_keystore? identified_by_store with_backup_clause?
    ;

add_update_secret_seps
    : (ADD | UPDATE) SECRET s = CHAR_STRING FOR CLIENT ci = CHAR_STRING using_tag_clause? TO LOCAL? AUTO_LOGIN KEYSTORE directory_path
    ;

delete_secret_seps
    : DELETE SECRET s = CHAR_STRING SQ FOR CLIENT ci = CHAR_STRING FROM LOCAL? AUTO_LOGIN KEYSTORE directory_path
    ;

zero_downtime_software_patching_clauses
    : SWITCHOVER TO? LIBRARY path FOR ALL CONTAINERS //inconsistent documentation
    ;

with_backup_clause
    : WITH BACKUP (USING bi = CHAR_STRING)?
    ;

identified_by_password_clause
    : IDENTIFIED BY keystore_password
    ;

keystore_password
    : DELIMITED_ID
    ;

path
    : CHAR_STRING
    ;

secret
    : DELIMITED_ID
    ;

// https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_4005.htm#SQLRF01105
analyze
    : (
        ANALYZE (TABLE tableview_name | INDEX index_name) partition_extention_clause?
        | ANALYZE CLUSTER cluster_name
    ) (validation_clauses | LIST CHAINED ROWS into_clause1? | DELETE SYSTEM? STATISTICS)
    ;

partition_extention_clause
    : PARTITION (
        '(' partition_name ')'
        | FOR '(' partition_key_value (',' partition_key_value)* ')'
    )
    | SUBPARTITION (
        '(' subpartition_name ')'
        | FOR '(' subpartition_key_value (',' subpartition_key_value)* ')'
    )
    ;

validation_clauses
    : VALIDATE REF UPDATE (SET DANGLING TO NULL_)?
    | VALIDATE STRUCTURE (CASCADE FAST | CASCADE online_or_offline? into_clause? | CASCADE)? online_or_offline? into_clause?
    ;

compute_clauses
    : COMPUTE SYSTEM? STATISTICS for_clause?
    ;

for_clause
    : FOR (
        TABLE for_clause*
        | ALL (INDEXED? COLUMNS (SIZE UNSIGNED_INTEGER)? for_clause* | LOCAL? INDEXES)
        | COLUMNS (SIZE UNSIGNED_INTEGER)? (column_name SIZE UNSIGNED_INTEGER)+ for_clause*
    )
    ;

online_or_offline
    : OFFLINE
    | ONLINE
    ;

into_clause1
    : INTO tableview_name?
    ;

//Making assumption on partition ad subpartition key value clauses
partition_key_value
    : literal
    | TIMESTAMP quoted_string
    ;

subpartition_key_value
    : literal
    | TIMESTAMP quoted_string
    ;

//https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_4006.htm#SQLRF01106
associate_statistics
    : ASSOCIATE STATISTICS WITH (column_association | function_association) storage_table_clause?
    ;

column_association
    : COLUMNS tableview_name '.' column_name (',' tableview_name '.' column_name)* using_statistics_type
    ;

function_association
    : (
        FUNCTIONS function_name (',' function_name)*
        | PACKAGES package_name (',' package_name)*
        | TYPES type_name (',' type_name)*
        | INDEXES index_name (',' index_name)*
        | INDEXTYPES indextype_name (',' indextype_name)*
    ) (
        using_statistics_type
        | default_cost_clause (',' default_selectivity_clause)?
        | default_selectivity_clause (',' default_cost_clause)?
    )
    ;

indextype_name
    : id_expression
    ;

using_statistics_type
    : USING (statistics_type_name | NULL_)
    ;

statistics_type_name
    : regular_id
    ;

default_cost_clause
    : DEFAULT COST '(' cpu_cost ',' io_cost ',' network_cost ')'
    ;

cpu_cost
    : UNSIGNED_INTEGER
    ;

io_cost
    : UNSIGNED_INTEGER
    ;

network_cost
    : UNSIGNED_INTEGER
    ;

default_selectivity_clause
    : DEFAULT SELECTIVITY default_selectivity
    ;

default_selectivity
    : UNSIGNED_INTEGER
    ;

storage_table_clause
    : WITH (SYSTEM | USER) MANAGED STORAGE TABLES
    ;

// https://docs.oracle.com/database/121/SQLRF/statements_4008.htm#SQLRF56110
unified_auditing
    : {this.isVersion12()}? AUDIT (
        POLICY policy_name ((BY | EXCEPT) audit_user (',' audit_user)*)? (WHENEVER NOT? SUCCESSFUL)?
        | CONTEXT NAMESPACE oracle_namespace ATTRIBUTES attribute_name (',' attribute_name)* (
            BY audit_user (',' audit_user)*
        )?
    )
    ;

policy_name
    : identifier
    ;

// https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_4007.htm#SQLRF01107
// https://docs.oracle.com/database/121/SQLRF/statements_4007.htm#SQLRF01107

audit_traditional
    : AUDIT (
        audit_operation_clause (auditing_by_clause | IN SESSION CURRENT)?
        | audit_schema_object_clause
        | NETWORK
        | audit_direct_path
    ) (BY (SESSION | ACCESS))? (WHENEVER NOT? SUCCESSFUL)? audit_container_clause?
    ;

audit_direct_path
    : {this.isVersion12()}? DIRECT_PATH auditing_by_clause
    ;

audit_container_clause
    : {this.isVersion12()}? (CONTAINER EQUALS_OP (CURRENT | ALL))
    ;

audit_operation_clause
    : (
        (sql_statement_shortcut | ALL STATEMENTS?) (',' (sql_statement_shortcut | ALL STATEMENTS?))*
        | (system_privilege | ALL PRIVILEGES) (',' (system_privilege | ALL PRIVILEGES))*
    )
    ;

auditing_by_clause
    : BY audit_user (',' audit_user)*
    ;

audit_user
    : regular_id
    ;

audit_schema_object_clause
    : (sql_operation (',' sql_operation)* | ALL) auditing_on_clause
    ;

sql_operation
    : ALTER
    | AUDIT
    | COMMENT
    | DELETE
    | EXECUTE
    | FLASHBACK
    | GRANT
    | INDEX
    | INSERT
    | LOCK
    | READ
    | RENAME
    | SELECT
    | UPDATE
    ;

auditing_on_clause
    : ON (
        object_name
        | DIRECTORY regular_id
        | MINING MODEL model_name
        | {this.isVersion12()}? SQL TRANSLATION PROFILE profile_name
        | DEFAULT
    )
    ;

model_name
    : (id_expression '.')? id_expression
    ;

object_name
    : (id_expression '.')? id_expression
    ;

profile_name
    : (id_expression '.')? id_expression
    ;

sql_statement_shortcut
    : ALTER SYSTEM
    | CLUSTER
    | CONTEXT
    | DATABASE LINK
    | DIMENSION
    | DIRECTORY
    | INDEX
    | MATERIALIZED VIEW
    | NOT EXISTS
    | OUTLINE
    | {this.isVersion12()}? PLUGGABLE DATABASE
    | PROCEDURE
    | PROFILE
    | PUBLIC DATABASE LINK
    | PUBLIC SYNONYM
    | ROLE
    | ROLLBACK SEGMENT
    | SEQUENCE
    | SESSION
    | SYNONYM
    | SYSTEM AUDIT
    | SYSTEM GRANT
    | TABLE
    | TABLESPACE
    | TRIGGER
    | TYPE
    | USER
    | VIEW
    | ALTER SEQUENCE
    | ALTER TABLE
    | COMMENT TABLE
    | DELETE TABLE
    | EXECUTE PROCEDURE
    | GRANT DIRECTORY
    | GRANT PROCEDURE
    | GRANT SEQUENCE
    | GRANT TABLE
    | GRANT TYPE
    | INSERT TABLE
    | LOCK TABLE
    | SELECT SEQUENCE
    | SELECT TABLE
    | UPDATE TABLE
    ;

drop_index
    : DROP INDEX index_name
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DISASSOCIATE-STATISTICS.html
disassociate_statistics
    : DISASSOCIATE STATISTICS FROM (
        COLUMNS (schema_name '.')? tb = id_expression '.' c = id_expression (
            ',' (schema_name '.')? tb = id_expression '.' c = id_expression
        )*
        | FUNCTIONS (schema_name '.')? fn = id_expression (
            ',' (schema_name '.')? fn = id_expression
        )*
        | PACKAGES (schema_name '.')? pkg = id_expression (
            ',' (schema_name '.')? pkg = id_expression
        )*
        | TYPES (schema_name '.')? t = id_expression (',' (schema_name '.')? t = id_expression)*
        | INDEXES (schema_name '.')? ix = id_expression (',' (schema_name '.')? ix = id_expression)*
        | INDEXTYPES (schema_name '.')? it = id_expression (
            ',' (schema_name '.')? it = id_expression
        )*
    ) FORCE?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-INDEXTYPE.html
drop_indextype
    : DROP INDEXTYPE (schema_name '.')? it = id_expression FORCE?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-INMEMORY-JOIN-GROUP.html
drop_inmemory_join_group
    : DROP INMEMORY JOIN GROUP (schema_name '.')? jg = id_expression
    ;

flashback_table
    : FLASHBACK TABLE tableview_name (',' tableview_name)* TO (
        ((SCN | TIMESTAMP) expression | RESTORE POINT restore_point) ((ENABLE | DISABLE) TRIGGERS)?
        | BEFORE DROP (RENAME TO tableview_name)?
    )
    ;

restore_point
    : identifier ('.' id_expression)*
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/PURGE.html
purge_statement
    : PURGE (
        (TABLE | INDEX) id_expression
        | TABLESPACE SET? ts = id_expression (USER u = id_expression)?
        | RECYCLEBIN
        | DBA_RECYCLEBIN
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/NOAUDIT-Traditional-Auditing.html
noaudit_statement
    : NOAUDIT (
        audit_operation_clause auditing_by_clause?
        | audit_schema_object_clause
        | NETWORK
        | DIRECT_PATH LOAD auditing_by_clause?
    ) (WHENEVER NOT? SUCCESSFUL)? container_clause?
    ;

rename_object
    : RENAME object_name TO object_name
    ;

grant_statement
    : GRANT (','? (role_name | system_privilege | object_privilege paren_column_list?))+ (
        ON grant_object_name
    )? TO (grantee_name | PUBLIC) (',' (grantee_name | PUBLIC))* (WITH (ADMIN | DELEGATE) OPTION)? (
        WITH HIERARCHY OPTION
    )? (WITH GRANT OPTION)? container_clause?
    ;

container_clause
    : CONTAINER EQUALS_OP (CURRENT | ALL)
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/REVOKE.html
revoke_statement
    : REVOKE (
        (revoke_system_privilege | revoke_object_privileges) container_clause?
        | revoke_roles_from_programs
    )
    ;

revoke_system_privilege
    : (system_privilege | role_name | ALL PRIVILEGES) FROM revokee_clause
    ;

revokee_clause
    : (id_expression | PUBLIC) (',' (id_expression | PUBLIC))*
    ;

revoke_object_privileges
    : (object_privilege | ALL PRIVILEGES?) (',' (object_privilege | ALL PRIVILEGES?))* on_object_clause FROM revokee_clause (
        CASCADE CONSTRAINTS
        | FORCE
    )?
    ;

on_object_clause
    : ON (
        (schema_name '.')? o = id_expression
        | USER id_expression (',' id_expression)*
        | DIRECTORY directory_name
        | EDITION edition_name
        | MINING MODEL (schema_name '.')? mmn = id_expression
        | JAVA (SOURCE | RESOURCE) (schema_name '.')? o2 = id_expression
        | SQL TRANSLATION PROFILE (schema_name '.')? p = id_expression
    )
    ;

revoke_roles_from_programs
    : (role_name (',' role_name)* | ALL) FROM program_unit (',' program_unit)*
    ;

program_unit
    : (FUNCTION | PROCEDURE | PACKAGE) (schema_name '.')? id_expression
    ;

create_dimension
    : CREATE DIMENSION identifier level_clause+ (
        hierarchy_clause
        | attribute_clause
        | extended_attribute_clause
    )+
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-DIRECTORY.html
create_directory
    : CREATE (OR REPLACE)? DIRECTORY directory_name (SHARING '=' (METADATA | NONE))? AS directory_path
    ;

directory_name
    : regular_id
    ;

directory_path
    : CHAR_STRING
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-INMEMORY-JOIN-GROUP.html
create_inmemory_join_group
    : CREATE INMEMORY JOIN GROUP (schema_name '.')? jg = id_expression '(' (schema_name '.')? t = id_expression '(' c = id_expression ')' (
        ',' (schema_name '.')? t = id_expression '(' c = id_expression ')'
    )+ ')'
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-HIERARCHY.html
drop_hierarchy
    : DROP HIERARCHY (schema_name '.')? hn = id_expression
    ;

// https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/alter_library.htm#LNPLS99946
// https://docs.oracle.com/database/121/LNPLS/alter_library.htm#LNPLS99946
alter_library
    : ALTER LIBRARY library_name (
        COMPILE library_debug? compiler_parameters_clause* (REUSE SETTINGS)?
        | library_editionable
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-JAVA.html
drop_java
    : DROP JAVA (SOURCE | CLASS | RESOURCE) (schema_name '.')? id_expression
    ;

drop_library
    : DROP LIBRARY library_name
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-JAVA.html
create_java
    : CREATE (OR REPLACE)? (AND (RESOLVE | COMPILE))? NOFORCE? JAVA (
        (SOURCE | RESOURCE) NAMED (schema_name '.')? pn = id_expression
        | CLASS (SCHEMA id_expression)?
    ) (SHARING '=' (METADATA | NONE))? invoker_rights_clause? (
        RESOLVER '(' ('(' CHAR_STRING ','? (sn = id_expression | '-') ')')+ ')'
    )? (
        USING (
            BFILE '(' d = id_expression ',' filename ')'
            | (CLOB | BLOB | BFILE) subquery
            | CHAR_STRING
        )
        | AS CHAR_STRING
    )
    ;

create_library
    : CREATE (OR REPLACE)? (EDITIONABLE | NONEDITIONABLE)? LIBRARY plsql_library_source
    ;

plsql_library_source
    : library_name (IS | AS) quoted_string (IN directory_name)? (AGENT quoted_string)? (
        CREDENTIAL credential_name
    )?
    ;

credential_name
    : (id_expression '.')? id_expression
    ;

library_editionable
    : {this.isVersion12()}? (EDITIONABLE | NONEDITIONABLE)
    ;

library_debug
    : {this.isVersion12()}? DEBUG
    ;

compiler_parameters_clause
    : parameter_name EQUALS_OP parameter_value
    ;

parameter_value
    : regular_id
    | CHAR_STRING
    ;

library_name
    : (regular_id '.')? regular_id
    ;

alter_dimension
    : ALTER DIMENSION identifier (
        (ADD (level_clause | hierarchy_clause | attribute_clause | extended_attribute_clause))+
        | (
            DROP (
                LEVEL identifier (RESTRICT | CASCADE)?
                | HIERARCHY identifier
                | ATTRIBUTE identifier (
                    LEVEL identifier (COLUMN column_name (',' COLUMN column_name)*)?
                )?
            )
        )+
        | COMPILE
    )
    ;

level_clause
    : LEVEL identifier IS (
        table_name '.' column_name
        | '(' table_name '.' column_name (',' table_name '.' column_name)* ')'
    ) (SKIP_ WHEN NULL_)?
    ;

hierarchy_clause
    : HIERARCHY identifier '(' identifier (CHILD OF identifier)+ dimension_join_clause? ')'
    ;

dimension_join_clause
    : (JOIN KEY column_one_or_more_sub_clause REFERENCES identifier)+
    ;

attribute_clause
    : (ATTRIBUTE identifier DETERMINES column_one_or_more_sub_clause)+
    ;

extended_attribute_clause
    : ATTRIBUTE identifier (LEVEL identifier DETERMINES column_one_or_more_sub_clause)+
    ;

column_one_or_more_sub_clause
    : column_name
    | '(' column_name (',' column_name)* ')'
    ;

// https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_4004.htm#SQLRF01104
// https://docs.oracle.com/database/121/SQLRF/statements_4004.htm#SQLRF01104
alter_view
    : ALTER VIEW tableview_name (
        ADD out_of_line_constraint
        | MODIFY CONSTRAINT constraint_name (RELY | NORELY)
        | DROP (
            CONSTRAINT constraint_name
            | PRIMARY KEY
            | UNIQUE '(' column_name (',' column_name)* ')'
        )
        | COMPILE
        | READ (ONLY | WRITE)
        | alter_view_editionable?
    )
    ;

alter_view_editionable
    : {this.isVersion12()}? (EDITIONABLE | NONEDITIONABLE)
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-VIEW.html
create_view
    : CREATE (OR REPLACE)? (NO? FORCE)? editioning_clause? VIEW (schema_name '.')? v = id_expression (
        SHARING '=' (METADATA | EXTENDED? DATA | NONE)
    )? view_options? (DEFAULT COLLATION cn = id_expression)? (BEQUEATH (CURRENT_USER | DEFINER))? AS select_only_statement subquery_restriction_clause
        ? (CONTAINER_MAP | CONTAINERS_DEFAULT)?
    ;

editioning_clause
    : EDITIONING
    | EDITIONABLE EDITIONING?
    | NONEDITIONABLE
    ;

view_options
    : view_alias_constraint
    | object_view_clause
    | xmltype_view_clause
    ;

view_alias_constraint
    : '(' (','? (table_alias inline_constraint* | out_of_line_constraint))+ ')'
    ;

object_view_clause
    : OF (schema_name '.')? tn = id_expression (
        WITH OBJECT (IDENTIFIER | ID) (DEFAULT | '(' REGULAR_ID (',' REGULAR_ID)* ')')
        | UNDER (schema_name '.')? sv = id_expression
    ) ('(' (','? (out_of_line_constraint | REGULAR_ID inline_constraint))+ ')')*
    ;

inline_constraint
    : (CONSTRAINT constraint_name)? (
        NOT? NULL_
        | UNIQUE
        | PRIMARY KEY
        | references_clause
        | check_constraint
    ) constraint_state?
    ;

inline_ref_constraint
    : SCOPE IS tableview_name
    | WITH ROWID
    | (CONSTRAINT constraint_name)? references_clause constraint_state?
    ;

out_of_line_ref_constraint
    : SCOPE FOR '(' ref_col_or_attr = regular_id ')' IS tableview_name
    | REF '(' ref_col_or_attr = regular_id ')' WITH ROWID
    | (CONSTRAINT constraint_name)? FOREIGN KEY '(' (','? ref_col_or_attr = regular_id)+ ')' references_clause constraint_state?
    ;

out_of_line_constraint
    : (
        (CONSTRAINT constraint_name)? (
            UNIQUE '(' column_name (',' column_name)* ')'
            | PRIMARY KEY '(' column_name (',' column_name)* ')'
            | foreign_key_clause
            | CHECK '(' condition ')'
        )
    ) constraint_state?
    ;

constraint_state
    : (
        NOT? DEFERRABLE
        | INITIALLY (IMMEDIATE | DEFERRED)
        | (RELY | NORELY)
        | (ENABLE | DISABLE)
        | (VALIDATE | NOVALIDATE)
        | using_index_clause
    )+
    ;

xmltype_view_clause
    : OF XMLTYPE xml_schema_spec? WITH OBJECT (IDENTIFIER | ID) (
        DEFAULT
        | '(' expression (',' expression)* ')'
    )
    ;

xml_schema_spec
    : (XMLSCHEMA xml_schema_url)? ELEMENT (element | xml_schema_url '#' element) (
        STORE ALL VARRAYS AS (LOBS | TABLES)
    )? (allow_or_disallow NONSCHEMA)? (allow_or_disallow ANYSCHEMA)?
    ;

xml_schema_url
    : DELIMITED_ID
    ;

element
    : DELIMITED_ID
    ;

alter_tablespace
    : ALTER TABLESPACE tablespace (
        DEFAULT table_compression? storage_clause?
        | MINIMUM EXTENT size_clause
        | RESIZE size_clause
        | COALESCE
        | SHRINK SPACE_KEYWORD (KEEP size_clause)?
        | RENAME TO new_tablespace_name
        | begin_or_end BACKUP
        | datafile_tempfile_clauses
        | tablespace_logging_clauses
        | tablespace_group_clause
        | tablespace_state_clauses
        | autoextend_clause
        | flashback_mode_clause
        | tablespace_retention_clause
    )
    ;

datafile_tempfile_clauses
    : ADD (datafile_specification | tempfile_specification)
    | DROP (DATAFILE | TEMPFILE) (filename | UNSIGNED_INTEGER) (KEEP size_clause)?
    | SHRINK TEMPFILE (filename | UNSIGNED_INTEGER) (KEEP size_clause)?
    | RENAME DATAFILE filename (',' filename)* TO filename (',' filename)*
    | (DATAFILE | TEMPFILE) (online_or_offline)
    ;

tablespace_logging_clauses
    : logging_clause
    | NO? FORCE LOGGING
    ;

tablespace_group_clause
    : TABLESPACE GROUP (tablespace_group_name | CHAR_STRING)
    ;

tablespace_group_name
    : regular_id
    ;

tablespace_state_clauses
    : ONLINE
    | OFFLINE (NORMAL | TEMPORARY | IMMEDIATE)?
    | READ (ONLY | WRITE)
    | PERMANENT
    | TEMPORARY
    ;

flashback_mode_clause
    : FLASHBACK (ON | OFF)
    ;

new_tablespace_name
    : tablespace
    ;

create_tablespace
    : CREATE (BIGFILE | SMALLFILE)? (
        permanent_tablespace_clause
        | temporary_tablespace_clause
        | undo_tablespace_clause
    )
    ;

permanent_tablespace_clause
    : TABLESPACE id_expression datafile_specification? (
        MINIMUM EXTENT size_clause
        | BLOCKSIZE size_clause
        | logging_clause
        | FORCE LOGGING
        | (ONLINE | OFFLINE)
        | ENCRYPTION tablespace_encryption_spec
        | DEFAULT //TODO table_compression? storage_clause?
        | extent_management_clause
        | segment_management_clause
        | flashback_mode_clause
    )*
    ;

tablespace_encryption_spec
    : USING encrypt_algorithm = CHAR_STRING
    ;

logging_clause
    : LOGGING
    | NOLOGGING
    | FILESYSTEM_LIKE_LOGGING
    ;

extent_management_clause
    : EXTENT MANAGEMENT LOCAL (AUTOALLOCATE | UNIFORM (SIZE size_clause)?)?
    ;

segment_management_clause
    : SEGMENT SPACE_KEYWORD MANAGEMENT (AUTO | MANUAL)
    ;

temporary_tablespace_clause
    : TEMPORARY TABLESPACE tablespace_name = id_expression tempfile_specification? tablespace_group_clause? extent_management_clause?
    ;

undo_tablespace_clause
    : UNDO TABLESPACE tablespace_name = id_expression datafile_specification? extent_management_clause? tablespace_retention_clause?
    ;

tablespace_retention_clause
    : RETENTION (GUARANTEE | NOGUARANTEE)
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-TABLESPACE-SET.html
create_tablespace_set
    : CREATE TABLESPACE SET tss = id_expression (IN SHARDSPACE ss = id_expression)? (
        USING TEMPLATE '(' (DATAFILE file_specification (',' file_specification)*)? permanent_tablespace_attrs+ ')'
    )?
    ;

permanent_tablespace_attrs
    : MINIMUM EXTENT size_clause
    | BLOCKSIZE numeric K_LETTER?
    | logging_clause
    | FORCE LOGGING
    | tablespace_encryption_clause
    | default_tablespace_params
    | ONLINE
    | OFFLINE
    | extent_management_clause
    | segment_management_clause
    | flashback_mode_clause
    | lost_write_protection
    ;

tablespace_encryption_clause
    : ENCRYPTION (tablespace_encryption_spec? ENCRYPT | DECRYPT)
    ;

default_tablespace_params
    : DEFAULT default_table_compression? default_index_compression? inmmemory_clause? ilm_clause? storage_clause?
    ;

default_table_compression
    : TABLE (COMPRESS FOR (OLTP | QUERY low_high | ARCHIVE low_high) | NOCOMPRESS)
    ;

low_high
    : LOW
    | HIGH
    ;

default_index_compression
    : INDEX (COMPRESS ADVANCED low_high | NOCOMPRESS)
    ;

inmmemory_clause
    : INMEMORY inmemory_attributes? (
        TEXT (
            column_name (',' column_name)*
            | column_name USING policy_name (',' column_name USING policy_name)*
        )
    )?
    | NO INMEMORY
    ;

// asm_filename is just a charater string.  Would need to parse the string
// to find diskgroup...
datafile_specification
    : DATAFILE (','? datafile_tempfile_spec)
    ;

tempfile_specification
    : TEMPFILE (','? datafile_tempfile_spec)
    ;

datafile_tempfile_spec
    : CHAR_STRING? (SIZE size_clause)? REUSE? autoextend_clause?
    ;

redo_log_file_spec
    : (filename | '(' filename (',' filename)* ')') (SIZE size_clause)? (BLOCKSIZE size_clause)? REUSE?
    ;

autoextend_clause
    : AUTOEXTEND (OFF | ON (NEXT size_clause)? maxsize_clause?)
    ;

maxsize_clause
    : MAXSIZE (UNLIMITED | size_clause)
    ;

build_clause
    : BUILD (IMMEDIATE | DEFERRED)
    ;

parallel_clause
    : NOPARALLEL
    | PARALLEL parallel_count = UNSIGNED_INTEGER?
    ;

alter_materialized_view
    : ALTER MATERIALIZED VIEW tableview_name (
        physical_attributes_clause
        | modify_mv_column_clause
        | table_compression
        | lob_storage_clause (',' lob_storage_clause)*
        | modify_lob_storage_clause (',' modify_lob_storage_clause)*
        //TODO | alter_table_partitioning
        | parallel_clause
        | logging_clause
        | allocate_extent_clause
        | deallocate_unused_clause
        | shrink_clause
        | (cache_or_nocache)
    )? alter_iot_clauses? (USING INDEX physical_attributes_clause)? alter_mv_option1? (
        enable_or_disable QUERY REWRITE
        | COMPILE
        | CONSIDER FRESH
    )?
    ;

alter_mv_option1
    : alter_mv_refresh
    //TODO  | MODIFY scoped_table_ref_constraint
    ;

alter_mv_refresh
    : REFRESH (
        FAST
        | COMPLETE
        | FORCE
        | ON (DEMAND | COMMIT)
        | START WITH expression
        | NEXT expression
        | WITH PRIMARY KEY
        | USING DEFAULT? MASTER ROLLBACK SEGMENT rollback_segment?
        | USING (ENFORCED | TRUSTED) CONSTRAINTS
    )+
    ;

rollback_segment
    : regular_id
    ;

modify_mv_column_clause
    : MODIFY '(' column_name (ENCRYPT encryption_spec | DECRYPT)? ')'
    ;

alter_materialized_view_log
    : ALTER MATERIALIZED VIEW LOG FORCE? ON tableview_name (
        physical_attributes_clause
        | add_mv_log_column_clause
        //TODO | alter_table_partitioning
        | parallel_clause
        | logging_clause
        | allocate_extent_clause
        | shrink_clause
        | move_mv_log_clause
        | cache_or_nocache
    )? mv_log_augmentation? mv_log_purge_clause?
    ;

add_mv_log_column_clause
    : ADD '(' column_name ')'
    ;

move_mv_log_clause
    : MOVE segment_attributes_clause parallel_clause?
    ;

mv_log_augmentation
    : ADD (
        (OBJECT ID | PRIMARY KEY | ROWID | SEQUENCE) ('(' column_name (',' column_name)* ')')?
        | '(' column_name (',' column_name)* ')'
    ) new_values_clause?
    ;

// Should bound this to just date/time expr
datetime_expr
    : expression
    ;

// Should bound this to just interval expr
interval_expr
    : expression
    ;

synchronous_or_asynchronous
    : SYNCHRONOUS
    | ASYNCHRONOUS
    ;

including_or_excluding
    : INCLUDING
    | EXCLUDING
    ;

create_materialized_view_log
    : CREATE MATERIALIZED VIEW LOG ON tableview_name (
        (
            physical_attributes_clause
            | TABLESPACE tablespace_name = id_expression
            | logging_clause
            | (CACHE | NOCACHE)
        )+
    )? parallel_clause?
    // table_partitioning_clauses TODO
    (
        WITH (','? ( OBJECT ID | PRIMARY KEY | ROWID | SEQUENCE | COMMIT SCN))* (
            '(' ( ','? regular_id)+ ')' new_values_clause?
        )? mv_log_purge_clause?
    )*
    ;

new_values_clause
    : (INCLUDING | EXCLUDING) NEW VALUES
    ;

mv_log_purge_clause
    : PURGE (
        IMMEDIATE (SYNCHRONOUS | ASYNCHRONOUS)?
        // |START WITH CLAUSES TODO
    )
    ;

create_materialized_zonemap
    : CREATE MATERIALIZED ZONEMAP zonemap_name (LEFT_PAREN column_list RIGHT_PAREN)? zonemap_attributes? zonemap_refresh_clause? (
        (ENABLE | DISABLE) PRUNING
    )? (create_zonemap_on_table | create_zonemap_as_subquery)
    ;

alter_materialized_zonemap
    : ALTER MATERIALIZED ZONEMAP zonemap_name (
        zonemap_attributes
        | zonemap_refresh_clause
        | (ENABLE | DISABLE) PRUNING
        | COMPILE
        | REBUILD
        | UNUSABLE
    )
    ;

drop_materialized_zonemap
    : DROP MATERIALIZED ZONEMAP zonemap_name
    ;

zonemap_refresh_clause
    : REFRESH (FAST | COMPILE | FORCE)? (
        ON (DEMAND | COMMIT | LOAD | DATA MOVEMENT | LOAD DATA MOVEMENT)
    )?
    ;

zonemap_attributes
    : (
        PCTFREE numeric
        | PCTUSED numeric
        | SCALE numeric
        | TABLESPACE tablespace
        | (CACHE | NOCACHE)
    )+
    ;

zonemap_name
    : identifier ('.' id_expression)?
    ;

operator_name
    : identifier ('.' id_expression)?
    ;

operator_function_name
    : identifier ('.' id_expression)*
    ;

create_zonemap_on_table
    : ON tableview_name LEFT_PAREN column_list RIGHT_PAREN
    ;

create_zonemap_as_subquery
    : AS subquery
    ;

alter_operator
    : ALTER OPERATOR operator_name (add_binding_clause | drop_binding_clause | COMPILE)
    ;

drop_operator
    : DROP OPERATOR operator_name FORCE?
    ;

create_operator
    : CREATE (OR REPLACE)? OPERATOR operator_name BINDING binding_clause (COMMA binding_clause)* (
        SHARING '=' (METADATA | NONE)
    )?
    ;

binding_clause
    : LEFT_PAREN datatype (COMMA datatype)* RIGHT_PAREN RETURN LEFT_PAREN? datatype RIGHT_PAREN? implementation_clause? using_function_clause
    ;

add_binding_clause
    : ADD BINDING binding_clause
    ;

implementation_clause
    : ANCILLARY TO primary_operator_list
    | operator_context_clause
    ;

primary_operator_list
    : primary_operator_item (COMMA primary_operator_item)*
    ;

primary_operator_item
    : schema_object_name LEFT_PAREN datatype (COMMA datatype)* RIGHT_PAREN
    ;

operator_context_clause
    : WITH INDEX CONTEXT COMMA SCAN CONTEXT implementation_type_name (COMPUTE ANCILLARY DATA)? (
        WITH COLUMN CONTEXT
    )?
    ;

using_function_clause
    : USING operator_function_name
    ;

drop_binding_clause
    : DROP BINDING LEFT_PAREN datatype (COMMA datatype)* RIGHT_PAREN FORCE?
    ;

create_materialized_view
    : CREATE MATERIALIZED VIEW tableview_name (OF type_name)? (
        '(' (scoped_table_ref_constraint | mv_column_alias) (
            ',' (scoped_table_ref_constraint | mv_column_alias)
        )* ')'
    )? (
        ON PREBUILT TABLE ( (WITH | WITHOUT) REDUCED PRECISION)?
        | physical_properties? (CACHE | NOCACHE)? parallel_clause? build_clause?
    ) (
        USING INDEX ((physical_attributes_clause | TABLESPACE mv_tablespace = id_expression)+)*
        | USING NO INDEX
    )? create_mv_refresh? (FOR UPDATE)? ((DISABLE | ENABLE) QUERY REWRITE)? AS select_only_statement
    ;

scoped_table_ref_constraint
    : SCOPE FOR '(' ref_column_or_attribute = identifier ')' IS (schema_name '.')? scope_table_name_or_c_alias = identifier
    ;

mv_column_alias
    : (identifier | quoted_string) (ENCRYPT encryption_spec)?
    ;

create_mv_refresh
    : (
        NEVER REFRESH
        | REFRESH (
            (FAST | COMPLETE | FORCE)
            | ON (DEMAND | COMMIT)
            | (START WITH | NEXT) //date goes here TODO
            | WITH (PRIMARY KEY | ROWID)
            | USING (
                DEFAULT (MASTER | LOCAL)? ROLLBACK SEGMENT
                | (MASTER | LOCAL)? ROLLBACK SEGMENT rb_segment = REGULAR_ID
            )
            | USING (ENFORCED | TRUSTED) CONSTRAINTS
        )+
    )
    ;

drop_materialized_view
    : DROP MATERIALIZED VIEW tableview_name (PRESERVE TABLE)?
    ;

create_context
    : CREATE (OR REPLACE)? CONTEXT oracle_namespace USING (schema_object_name '.')? package_name (
        INITIALIZED (EXTERNALLY | GLOBALLY)
        | ACCESSED GLOBALLY
    )?
    ;

oracle_namespace
    : id_expression
    ;

//https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_5001.htm#SQLRF01201
create_cluster
    : CREATE CLUSTER cluster_name '(' column_name datatype SORT? (',' column_name datatype SORT?)* ')' (
        physical_attributes_clause
        | SIZE size_clause
        | TABLESPACE tablespace
        | INDEX
        | (SINGLE TABLE)? HASHKEYS UNSIGNED_INTEGER (HASH IS expression)?
    )* parallel_clause? (ROWDEPENDENCIES | NOROWDEPENDENCIES)? (CACHE | NOCACHE)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-PROFILE.html
create_profile
    : CREATE MANDATORY? PROFILE p = id_expression LIMIT (resource_parameters | password_parameters)+ container_clause?
    ;

resource_parameters
    : (
        SESSIONS_PER_USER
        | CPU_PER_SESSION
        | CPU_PER_CALL
        | CONNECT_TIME
        | IDLE_TIME
        | LOGICAL_READS_PER_SESSION
        | LOGICAL_READS_PER_CALL
        | COMPOSITE_LIMIT
    ) (UNSIGNED_INTEGER | UNLIMITED | DEFAULT)
    | PRIVATE_SGA (size_clause | UNLIMITED | DEFAULT)
    ;

password_parameters
    : (
        FAILED_LOGIN_ATTEMPTS
        | PASSWORD_LIFE_TIME
        | PASSWORD_REUSE_TIME
        | PASSWORD_REUSE_MAX
        | PASSWORD_LOCK_TIME
        | PASSWORD_GRACE_TIME
        | INACTIVE_ACCOUNT_TIME
    ) (expression | UNLIMITED | DEFAULT)
    | PASSWORD_VERIFY_FUNCTION (function_name | NULL_ | DEFAULT)
    | PASSWORD_ROLLOVER_TIME (expression | DEFAULT)
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-LOCKDOWN-PROFILE.html
create_lockdown_profile
    : CREATE LOCKDOWN PROFILE id_expression (static_base_profile | dynamic_base_profile)?
    ;

static_base_profile
    : FROM bp = id_expression
    ;

dynamic_base_profile
    : INCLUDING bp = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-OUTLINE.html
create_outline
    : CREATE (OR REPLACE)? (PUBLIC | PRIVATE)? OUTLINE (o = id_expression)? (
        FROM (PUBLIC | PRIVATE)? so = id_expression
    )? (FOR CATEGORY c = id_expression)? (ON statement)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-RESTORE-POINT.html
create_restore_point
    : CREATE CLEAN? RESTORE POINT rp = id_expression (FOR PLUGGABLE DATABASE pdb = id_expression)? (
        AS OF (TIMESTAMP | SCN) expression
    )? (PRESERVE | GUARANTEE FLASHBACK DATABASE)?
    ;

create_role
    : CREATE ROLE role_name role_identified_clause? container_clause?
    ;

create_table
    : CREATE (
        (GLOBAL | PRIVATE) TEMPORARY
        | SHARDED
        | DUPLICATED
        | IMMUTABLE? BLOCKCHAIN
        | IMMUTABLE
    )? TABLE (schema_name '.')? table_name (SHARING '=' (METADATA | EXTENDED? DATA | NONE))? (
        relational_table
        | xmltype_table
        | object_table
    ) memoptimize_read_write_clause? (PARENT tableview_name)? (USAGE QUEUE)?
    ;

xmltype_table
    : OF XMLTYPE ('(' object_properties ')')? (XMLTYPE xmltype_storage)? xmlschema_spec? xmltype_virtual_columns? (
        ON COMMIT (DELETE | PRESERVE) ROWS
    )? oid_clause? oid_index_clause? physical_properties? table_properties
    ;

xmltype_virtual_columns
    : VIRTUAL COLUMNS '(' column_name AS '(' expression ')' (',' column_name AS '(' expression ')')* ')'
    ;

xmltype_column_properties
    : XMLTYPE COLUMN? column_name xmltype_storage? xmlschema_spec?
    ;

xmltype_storage
    : STORE AS (
        OBJECT RELATIONAL
        | (SECUREFILE | BASICFILE)? (CLOB | BINARY XML) (
            lob_segname ('(' lob_parameters ')')?
            | '(' lob_parameters ')'
        )?
    )
    | STORE VARRAYS AS (LOBS | TABLES)
    ;

xmlschema_spec
    : (XMLSCHEMA DELIMITED_ID)? ELEMENT DELIMITED_ID (allow_or_disallow NONSCHEMA)? (
        allow_or_disallow ANYSCHEMA
    )?
    ;

object_table
    : OF (schema_name '.')? object_type object_table_substitution? (
        '(' object_properties (',' object_properties)* ')'
    )? (ON COMMIT (DELETE | PRESERVE) ROWS)? oid_clause? oid_index_clause? physical_properties? table_properties
    ;

object_type
    : regular_id
    ;

oid_index_clause
    : OIDINDEX index_name? '(' (physical_attributes_clause | TABLESPACE tablespace)+ ')'
    ;

oid_clause
    : OBJECT IDENTIFIER IS (SYSTEM GENERATED | PRIMARY KEY)
    ;

object_properties
    : (column_name | attribute_name) (DEFAULT expression)? (
        inline_constraint (',' inline_constraint)*
        | inline_ref_constraint
    )?
    | out_of_line_constraint
    | out_of_line_ref_constraint
    | supplemental_logging_props
    ;

object_table_substitution
    : NOT? SUBSTITUTABLE AT ALL LEVELS
    ;

relational_table
    : ('(' relational_property (',' relational_property)* ')')? immutable_table_clauses blockchain_table_clauses? (
        DEFAULT COLLATION collation_name
    )? (ON COMMIT (DROP | PRESERVE) DEFINITION)? (ON COMMIT (DELETE | PRESERVE) ROWS)? physical_properties? table_properties
    ;

immutable_table_clauses
    : immutable_table_no_drop_clause? immutable_table_no_delete_clause?
    ;

immutable_table_no_drop_clause
    : NO DROP (UNTIL numeric DAYS IDLE)?
    ;

immutable_table_no_delete_clause
    : NO DELETE (LOCKED? | UNTIL numeric DAYS AFTER INSERT LOCKED?)
    ;

blockchain_table_clauses
    : blockchain_drop_table_clause blockchain_row_retention_clause blockchain_hash_and_data_format_clause
    ;

blockchain_drop_table_clause
    : NO DROP (UNTIL numeric DAYS IDLE)?
    ;

blockchain_row_retention_clause
    : NO DELETE (LOCKED? | UNTIL numeric DAYS AFTER INSERT LOCKED?)
    ;

blockchain_hash_and_data_format_clause
    : HASHING USING SHA2_512_Q VERSION V1_Q
    ;

collation_name
    : identifier
    ;

table_properties
    : column_properties? read_only_clause? indexing_clause? table_partitioning_clauses? attribute_clustering_clause? (
        CACHE
        | NOCACHE
    )? result_cache_clause? parallel_clause? (ROWDEPENDENCIES | NOROWDEPENDENCIES)? enable_disable_clause* row_movement_clause?
        logical_replication_clause? flashback_archive_clause? physical_properties? (ROW ARCHIVAL)? (
        AS select_only_statement
        | FOR EXCHANGE WITH TABLE (schema_name '.')? table_name
    )?
    ;

read_only_clause
    : READ (ONLY | WRITE)
    ;

indexing_clause
    : INDEXING (ON | OFF)
    ;

attribute_clustering_clause
    : CLUSTERING clustering_join? cluster_clause (yes_no? ON LOAD)? (yes_no? ON DATA MOVEMENT)? zonemap_clause?
    ;

clustering_join
    : (schema_name '.')? table_name clustering_join_item (',' clustering_join_item)*
    ;

clustering_join_item
    : JOIN (schema_name '.')? table_name ON '(' equijoin_condition ')'
    ;

equijoin_condition
    : expression
    ;

cluster_clause
    : BY (LINEAR | INTERLEAVED)? ORDER clustering_columns
    ;

clustering_columns
    : clustering_column_group
    | '(' clustering_column_group (',' clustering_column_group)* ')'
    ;

clustering_column_group
    : '(' column_name (',' column_name)* ')'
    ;

yes_no
    : YES
    | NO
    ;

zonemap_clause
    : WITH MATERIALIZED ZONEMAP ('(' zonemap_name ')')?
    | WITHOUT MATERIALIZED ZONEMAP
    ;

logical_replication_clause
    : DISABLE LOGICAL REPLICATION
    | ENABLE LOGICAL REPLICATION ((ALL | ALLOW NOVALIDATE) KEYS)?
    ;

table_name
    : identifier
    ;

relational_property
    : column_definition
    | virtual_column_definition
    | period_definition
    | out_of_line_constraint
    | out_of_line_ref_constraint
    | supplemental_logging_props
    ;

table_partitioning_clauses
    : range_partitions
    | list_partitions
    | hash_partitions
    | composite_range_partitions
    | composite_list_partitions
    | composite_hash_partitions
    | reference_partitioning
    | system_partitioning
    ;

range_partitions
    : PARTITION BY RANGE '(' column_name (',' column_name)* ')' (
        INTERVAL '(' expression ')' (STORE IN '(' tablespace (',' tablespace)* ')')?
    )? '(' PARTITION partition_name? range_values_clause table_partition_description (
        ',' PARTITION partition_name? range_values_clause table_partition_description
    )* ')'
    ;

list_partitions
    : PARTITION BY LIST '(' column_name ')' '(' PARTITION partition_name? list_values_clause table_partition_description (
        ',' PARTITION partition_name? list_values_clause table_partition_description
    )* ')'
    ;

hash_partitions
    : PARTITION BY HASH '(' column_name (',' column_name)* ')' (
        individual_hash_partitions
        | hash_partitions_by_quantity
    )
    ;

individual_hash_partitions
    : '(' PARTITION partition_name? partitioning_storage_clause? (
        ',' PARTITION partition_name? partitioning_storage_clause?
    )* ')'
    ;

hash_partitions_by_quantity
    : PARTITIONS hash_partition_quantity (STORE IN '(' tablespace (',' tablespace)* ')')? (
        table_compression
        | key_compression
    )? (OVERFLOW STORE IN '(' tablespace (',' tablespace)* ')')?
    ;

hash_partition_quantity
    : UNSIGNED_INTEGER
    ;

composite_range_partitions
    : PARTITION BY RANGE '(' column_name (',' column_name)* ')' (
        INTERVAL '(' expression ')' (STORE IN '(' tablespace (',' tablespace)* ')')?
    )? (subpartition_by_range | subpartition_by_list | subpartition_by_hash) '(' range_partition_desc (
        ',' range_partition_desc
    )* ')'
    ;

composite_list_partitions
    : PARTITION BY LIST '(' column_name ')' (
        subpartition_by_range
        | subpartition_by_list
        | subpartition_by_hash
    ) '(' list_partition_desc (',' list_partition_desc)* ')'
    ;

composite_hash_partitions
    : PARTITION BY HASH '(' (',' column_name)+ ')' (
        subpartition_by_range
        | subpartition_by_list
        | subpartition_by_hash
    ) (individual_hash_partitions | hash_partitions_by_quantity)
    ;

reference_partitioning
    : PARTITION BY REFERENCE '(' regular_id ')' (
        '(' reference_partition_desc (',' reference_partition_desc)* ')'
    )?
    ;

reference_partition_desc
    : PARTITION partition_name? table_partition_description
    ;

system_partitioning
    : PARTITION BY SYSTEM (
        PARTITIONS UNSIGNED_INTEGER
        | reference_partition_desc (',' reference_partition_desc)*
    )?
    ;

range_partition_desc
    : PARTITION partition_name? range_values_clause table_partition_description (
        (
            '(' (
                range_subpartition_desc (',' range_subpartition_desc)*
                | list_subpartition_desc (',' list_subpartition_desc)*
                | individual_hash_subparts (',' individual_hash_subparts)*
            ) ')'
            | hash_subparts_by_quantity
        )
    )?
    ;

list_partition_desc
    : PARTITION partition_name? list_values_clause table_partition_description (
        (
            '(' (
                range_subpartition_desc (',' range_subpartition_desc)*
                | list_subpartition_desc (',' list_subpartition_desc)*
                | individual_hash_subparts (',' individual_hash_subparts)*
            ) ')'
            | hash_subparts_by_quantity
        )
    )?
    ;

subpartition_template
    : SUBPARTITION TEMPLATE (
        (
            '(' (
                range_subpartition_desc (',' range_subpartition_desc)*
                | list_subpartition_desc (',' list_subpartition_desc)*
                | individual_hash_subparts (',' individual_hash_subparts)*
            ) ')'
            | hash_subpartition_quantity
        )
    )
    ;

hash_subpartition_quantity
    : UNSIGNED_INTEGER
    ;

subpartition_by_range
    : SUBPARTITION BY RANGE '(' column_name (',' column_name)* ')' subpartition_template?
    ;

subpartition_by_list
    : SUBPARTITION BY LIST '(' column_name ')' subpartition_template?
    ;

subpartition_by_hash
    : SUBPARTITION BY HASH '(' column_name (',' column_name)* ')' (
        SUBPARTITIONS UNSIGNED_INTEGER (STORE IN '(' tablespace (',' tablespace)* ')')?
        | subpartition_template
    )?
    ;

subpartition_name
    : partition_name
    ;

range_subpartition_desc
    : SUBPARTITION subpartition_name? range_values_clause partitioning_storage_clause?
    ;

list_subpartition_desc
    : SUBPARTITION subpartition_name? list_values_clause partitioning_storage_clause?
    ;

individual_hash_subparts
    : SUBPARTITION subpartition_name? partitioning_storage_clause?
    ;

hash_subparts_by_quantity
    : SUBPARTITIONS UNSIGNED_INTEGER (STORE IN '(' tablespace (',' tablespace)* ')')?
    ;

range_values_clause
    : VALUES LESS THAN '(' literal (',' literal)* ')'
    ;

list_values_clause
    : VALUES '(' (literal (',' literal)* | TIMESTAMP literal (',' TIMESTAMP literal)* | DEFAULT) ')'
    ;

table_partition_description
    : deferred_segment_creation? segment_attributes_clause? (table_compression | key_compression)? (
        OVERFLOW segment_attributes_clause?
    )? (lob_storage_clause | varray_col_properties | nested_table_col_properties)*
    ;

partitioning_storage_clause
    : (
        TABLESPACE tablespace
        | OVERFLOW (TABLESPACE tablespace)?
        | table_compression
        | key_compression
        | lob_partitioning_storage
        | VARRAY varray_item STORE AS (BASICFILE | SECUREFILE)? LOB lob_segname
    )+
    ;

lob_partitioning_storage
    : LOB '(' lob_item ')' STORE AS (BASICFILE | SECUREFILE)? (
        lob_segname ('(' TABLESPACE tablespace ')')?
        | '(' TABLESPACE tablespace ')'
    )
    ;

datatype_null_enable
    : column_name datatype SORT? (DEFAULT expression)? (
        ENCRYPT (USING CHAR_STRING)? (IDENTIFIED BY REGULAR_ID)? CHAR_STRING? (NO? SALT)?
    )? (NOT NULL_)? (ENABLE | DISABLE)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/size_clause.html
// Technically, this should only allow 'K' | 'M' | 'G' | 'T' | 'P' | 'E'
// but having issues with examples/numbers01.sql line 11 "sysdate -1m"
size_clause
    : UNSIGNED_INTEGER (K_LETTER | M_LETTER | G_LETTER | T_LETTER | P_LETTER | E_LETTER)?
    ;

table_compression
    : COMPRESS (BASIC | FOR ( OLTP | (QUERY | ARCHIVE) (LOW | HIGH)?))?
    | NOCOMPRESS
    ;

// avoid to match an empty string in
inmemory_table_clause
    : inmemory_column_clause+
    | (INMEMORY inmemory_attributes? | NO INMEMORY) inmemory_column_clause*
    ;

// avoid to match an empty string in
inmemory_attributes
    : inmemory_memcompress inmemory_priority? inmemory_distribute? inmemory_duplicate?
    | inmemory_priority inmemory_distribute? inmemory_duplicate?
    | inmemory_distribute inmemory_duplicate?
    | inmemory_duplicate
    ;

inmemory_memcompress
    : MEMCOMPRESS FOR (DML | (QUERY | CAPACITY) (LOW | HIGH)?)
    | NO MEMCOMPRESS
    ;

inmemory_priority
    : PRIORITY (NONE | LOW | MEDIUM | HIGH | CRITICAL)
    ;

inmemory_distribute
    : DISTRIBUTE (AUTO | BY (ROWID RANGE | PARTITION | SUBPARTITION))? (
        FOR SERVICE (DEFAULT | ALL | identifier | NONE)
    )?
    ;

inmemory_duplicate
    : DUPLICATE ALL?
    | NO DUPLICATE
    ;

inmemory_column_clause
    : (INMEMORY inmemory_memcompress? | NO INMEMORY) '(' column_list ')'
    ;

physical_attributes_clause
    : (
        PCTFREE pctfree = UNSIGNED_INTEGER
        | PCTUSED pctused = UNSIGNED_INTEGER
        | INITRANS inittrans = UNSIGNED_INTEGER
        | MAXTRANS maxtrans = UNSIGNED_INTEGER
        | COMPUTE STATISTICS
        | storage_clause
        | compute_clauses
    )+
    ;

storage_clause
    : STORAGE '(' (
        INITIAL initial_size = size_clause
        | NEXT next_size = size_clause
        | MINEXTENTS minextents = (UNSIGNED_INTEGER | UNLIMITED)
        | MAXEXTENTS minextents = (UNSIGNED_INTEGER | UNLIMITED)
        | PCTINCREASE pctincrease = UNSIGNED_INTEGER
        | FREELISTS freelists = UNSIGNED_INTEGER
        | FREELIST GROUPS freelist_groups = UNSIGNED_INTEGER
        | OPTIMAL (size_clause | NULL_)
        | BUFFER_POOL (KEEP | RECYCLE | DEFAULT)
        | FLASH_CACHE (KEEP | NONE | DEFAULT)
        | CELL_FLASH_CACHE (KEEP | NONE | DEFAULT)
        | ENCRYPT
    )+ ')'
    ;

deferred_segment_creation
    : SEGMENT CREATION (IMMEDIATE | DEFERRED)
    ;

segment_attributes_clause
    : (
        physical_attributes_clause
        | TABLESPACE (tablespace_name = id_expression | SET? identifier)
        | table_compression
        | logging_clause
    )+
    ;

physical_properties
    : deferred_segment_creation? segment_attributes_clause table_compression? inmemory_table_clause? ilm_clause?
    | deferred_segment_creation? (
        ORGANIZATION (
            HEAP segment_attributes_clause? heap_org_table_clause
            | INDEX segment_attributes_clause? index_org_table_clause
            | EXTERNAL external_table_clause
        )
        | EXTERNAL PARTITION ATTRIBUTES external_table_clause (REJECT LIMIT)?
    )
    | CLUSTER cluster_name '(' column_name (',' column_name)* ')'
    ;

ilm_clause
    : ILM (
        ADD POLICY ilm_policy_clause
        | (DELETE | ENABLE | DISABLE) POLICY ilm_policy_clause
        | DELETE_ALL
        | ENABLE_ALL
        | DISABLE_ALL
    )
    ;

ilm_policy_clause
    : ilm_compression_policy
    | ilm_tiering_policy
    | ilm_inmemory_policy
    ;

ilm_compression_policy
    : table_compression segment_group ilm_after_on
    | ((ROW | COLUMN) STORE COMPRESS (ADVANCED | FOR QUERY)) ROW AFTER ilm_time_period OF NO MODIFICATION
    ;

ilm_tiering_policy
    : TIER TO tablespace (
        segment_group? (ON function_name)?
        | READ ONLY segment_group? ilm_after_on
    )
    ;

ilm_after_on
    : AFTER ilm_time_period OF (NO (ACCESS | MODIFICATION) | CREATION)
    | ON function_name
    ;

segment_group
    : SEGMENT
    | GROUP
    ;

ilm_inmemory_policy
    : (SET INMEMORY inmemory_attributes? | MODIFY INMEMORY inmemory_memcompress | NO INMEMORY) SEGMENT? ilm_after_on
    ;

ilm_time_period
    : numeric (DAY | DAYS | MONTH | MONTHS | YEAR | YEARS)
    ;

heap_org_table_clause
    : table_compression? inmemory_table_clause? ilm_clause?
    ;

external_table_clause
    : '(' (TYPE access_driver_type)? external_table_data_props ')' (
        REJECT LIMIT (numeric | UNLIMITED)
    )? inmemory_table_clause?
    ;

access_driver_type
    : ORACLE_LOADER
    | ORACLE_DATAPUMP
    | ORACLE_HDFS
    | ORACLE_HIVE
    ;

external_table_data_props
    : (DEFAULT DIRECTORY directory_name)? (
        ACCESS PARAMETERS (
            '(' CHAR_STRING ')'
            | '(' opaque_format_spec ')'
            | USING CLOB select_only_statement
        )
    )? (LOCATION '(' directory_name COLON CHAR_STRING (',' directory_name COLON CHAR_STRING)* ')')?
    ;

opaque_format_spec
    : //TODO https://docs.oracle.com/en/database/oracle/oracle-database/21/sutil/oracle-external-tables.html
    ;

row_movement_clause
    : (ENABLE | DISABLE)? ROW MOVEMENT
    ;

flashback_archive_clause
    : FLASHBACK ARCHIVE fa = id_expression?
    | NO FLASHBACK ARCHIVE
    ;

log_grp
    : UNSIGNED_INTEGER
    ;

supplemental_table_logging
    : ADD SUPPLEMENTAL LOG (supplemental_log_grp_clause | supplemental_id_key_clause) (
        ',' SUPPLEMENTAL LOG (supplemental_log_grp_clause | supplemental_id_key_clause)
    )*
    | DROP SUPPLEMENTAL LOG (supplemental_id_key_clause | GROUP log_grp) (
        ',' SUPPLEMENTAL LOG (supplemental_id_key_clause | GROUP log_grp)
    )*
    ;

supplemental_log_grp_clause
    : GROUP log_grp '(' regular_id (NO LOG)? (',' regular_id (NO LOG)?)* ')' ALWAYS?
    ;

supplemental_id_key_clause
    : DATA '(' (','? ( ALL | PRIMARY KEY | UNIQUE | FOREIGN KEY))+ ')' COLUMNS
    ;

allocate_extent_clause
    : ALLOCATE EXTENT (
        '(' (
            SIZE size_clause
            | DATAFILE datafile = CHAR_STRING
            | INSTANCE inst_num = UNSIGNED_INTEGER
        )+ ')'
    )?
    ;

deallocate_unused_clause
    : DEALLOCATE UNUSED (KEEP size_clause)?
    ;

shrink_clause
    : SHRINK SPACE_KEYWORD COMPACT? CASCADE?
    ;

records_per_block_clause
    : (MINIMIZE | NOMINIMIZE)? RECORDS_PER_BLOCK
    ;

upgrade_table_clause
    : UPGRADE (NOT? INCLUDING DATA) column_properties
    ;

truncate_table
    : TRUNCATE TABLE tableview_name PURGE?
    ;

drop_table
    : DROP TABLE tableview_name PURGE?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-TABLESPACE.html
drop_tablespace
    : DROP TABLESPACE ts = id_expression ((DROP | KEEP) QUOTA?)? including_contents_clause?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-TABLESPACE-SET.html
drop_tablespace_set
    : DROP TABLESPACE SET tss = id_expression including_contents_clause?
    ;

including_contents_clause
    : INCLUDING CONTENTS ((AND | KEEP) DATAFILES)? (CASCADE CONSTRAINTS)?
    ;

drop_view
    : DROP VIEW tableview_name (CASCADE CONSTRAINT)?
    ;

comment_on_column
    : COMMENT ON COLUMN column_name IS quoted_string
    ;

enable_or_disable
    : ENABLE
    | DISABLE
    ;

allow_or_disallow
    : ALLOW
    | DISALLOW
    ;

// Synonym DDL Clauses

alter_synonym
    : ALTER PUBLIC? SYNONYM (schema_name '.')? synonym_name (
        EDITIONABLE
        | NONEDITIONABLE
        | COMPILE
    )
    ;

create_synonym
    // Synonym's schema cannot be specified for public synonyms
    : CREATE (OR REPLACE)? PUBLIC SYNONYM synonym_name FOR (schema_name PERIOD)? schema_object_name (
        AT_SIGN link_name
    )?
    | CREATE (OR REPLACE)? SYNONYM (schema_name PERIOD)? synonym_name FOR (schema_name PERIOD)? schema_object_name (
        AT_SIGN (schema_name PERIOD)? link_name
    )?
    ;

drop_synonym
    : DROP PUBLIC? SYNONYM (schema_name '.')? synonym_name FORCE?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-SPFILE.html
create_spfile
    : CREATE SPFILE ('=' spfile_name)? FROM (PFILE ('=' pfile_name)? (AS COPY)? | MEMORY)
    ;

spfile_name
    : CHAR_STRING
    ;

pfile_name
    : CHAR_STRING
    ;

comment_on_table
    : COMMENT ON TABLE tableview_name IS quoted_string
    ;

comment_on_materialized
    : COMMENT ON MATERIALIZED VIEW tableview_name IS quoted_string
    ;

alter_analytic_view
    : ALTER ANALYTIC VIEW (schema_name '.')? av = id_expression (
        RENAME TO id_expression
        | COMPILE
        | alter_add_cache_clause
        | alter_drop_cache_clause
    )
    ;

alter_add_cache_clause
    : ADD CACHE MEASURE GROUP '(' (ALL | measure_list)? ')' LEVELS '(' levels_item (
        ',' levels_item
    )* ')'
    ;

levels_item
    : ((d = id_expression '.')? h = id_expression '.')? l = id_expression
    ;

measure_list
    : id_expression (',' id_expression)*
    ;

alter_drop_cache_clause
    : DROP CACHE MEASURE GROUP '(' (ALL | measure_list)? ')' LEVELS '(' levels_item (
        ',' levels_item
    )* ')'
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-ATTRIBUTE-DIMENSION.html
alter_attribute_dimension
    : ALTER ATTRIBUTE DIMENSION (schema_name '.')? ad = id_expression (
        RENAME TO nad = id_expression
        | COMPILE
    )
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-AUDIT-POLICY-Unified-Auditing.html
alter_audit_policy
    : ALTER AUDIT POLICY p = id_expression ADD? (
        privilege_audit_clause? action_audit_clause? role_audit_clause?
        | (ONLY TOPLEVEL)?
    ) DROP? (privilege_audit_clause? action_audit_clause? role_audit_clause? | (ONLY TOPLEVEL)?) (
        CONDITION (DROP | CHAR_STRING EVALUATE PER (STATEMENT | SESSION | INSTANCE))
    )?
    ;

alter_cluster
    : ALTER CLUSTER cluster_name (
        physical_attributes_clause
        | SIZE size_clause
        | allocate_extent_clause
        | deallocate_unused_clause
        | cache_or_nocache
    )+ parallel_clause?
    ;

drop_analytic_view
    : DROP ANALYTIC VIEW (schema_name '.')? av = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-ATTRIBUTE-DIMENSION.html
drop_attribute_dimension
    : DROP ATTRIBUTE DIMENSION (schema_name '.')? ad = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-AUDIT-POLICY-Unified-Auditing.html
drop_audit_policy
    : DROP AUDIT POLICY p = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-FLASHBACK-ARCHIVE.html
drop_flashback_archive
    : DROP FLASHBACK ARCHIVE fa = id_expression
    ;

drop_cluster
    : DROP CLUSTER cluster_name (INCLUDING TABLES (CASCADE CONSTRAINTS)?)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-CONTEXT.html
drop_context
    : DROP CONTEXT ns = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-DIRECTORY.html
drop_directory
    : DROP DIRECTORY dn = id_expression
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-DISKGROUP.html
drop_diskgroup
    : DROP DISKGROUP dgn = id_expression ((FORCE? INCLUDING | EXCLUDING) CONTENTS)?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-EDITION.html
drop_edition
    : DROP EDITION e = id_expression CASCADE?
    ;

truncate_cluster
    : TRUNCATE CLUSTER cluster_name ((DROP | REUSE) STORAGE)?
    ;

cache_or_nocache
    : CACHE
    | NOCACHE
    ;

database_name
    : id_expression
    ;

alter_database
    : ALTER database_clause (
        startup_clauses
        | recovery_clauses
        | database_file_clauses
        | logfile_clauses
        | controlfile_clauses
        | standby_database_clauses
        | default_settings_clause
        | instance_clauses
        | security_clause
        | prepare_clause
        | drop_mirror_clause
        | lost_write_protection
        | cdb_fleet_clauses
        | property_clauses
        | replay_upgrade_clauses
    )
    ;

database_clause
    : PLUGGABLE? DATABASE database_name?
    ;

startup_clauses
    : MOUNT ((STANDBY | CLONE) DATABASE)?
    | OPEN (READ WRITE)? resetlogs_or_noresetlogs? upgrade_or_downgrade?
    | OPEN READ ONLY
    ;

resetlogs_or_noresetlogs
    : RESETLOGS
    | NORESETLOGS
    ;

upgrade_or_downgrade
    : UPGRADE
    | DOWNGRADE
    ;

recovery_clauses
    : general_recovery
    | managed_standby_recovery
    | begin_or_end BACKUP
    ;

begin_or_end
    : BEGIN
    | END
    ;

general_recovery
    : RECOVER AUTOMATIC? (FROM CHAR_STRING)? (
        (full_database_recovery | partial_database_recovery | LOGFILE CHAR_STRING)? (
            (TEST | ALLOW UNSIGNED_INTEGER CORRUPTION | parallel_clause)+
        )?
        | CONTINUE DEFAULT?
        | CANCEL
    )
    ;

//Need to come back to
full_database_recovery
    : STANDBY? DATABASE (
        (
            UNTIL (CANCEL | TIME CHAR_STRING | CHANGE UNSIGNED_INTEGER | CONSISTENT)
            | USING BACKUP CONTROLFILE
            | SNAPSHOT TIME CHAR_STRING
        )+
    )?
    ;

partial_database_recovery
    : TABLESPACE tablespace (',' tablespace)*
    | DATAFILE CHAR_STRING
    | filenumber (',' CHAR_STRING | filenumber)*
    | partial_database_recovery_10g
    ;

partial_database_recovery_10g
    : {this.isVersion10()}? STANDBY (
        TABLESPACE tablespace (',' tablespace)*
        | DATAFILE CHAR_STRING
        | filenumber (',' CHAR_STRING | filenumber)*
    ) UNTIL (CONSISTENT WITH)? CONTROLFILE
    ;

managed_standby_recovery
    : RECOVER (
        MANAGED STANDBY DATABASE (
            (
                USING CURRENT LOGFILE
                | DISCONNECT (FROM SESSION)?
                | NODELAY
                | UNTIL CHANGE UNSIGNED_INTEGER
                | UNTIL CONSISTENT
                | parallel_clause
            )+
            | FINISH
            | CANCEL
        )?
        | TO LOGICAL STANDBY (db_name | KEEP IDENTITY)
    )
    ;

db_name
    : regular_id
    ;

database_file_clauses
    : RENAME FILE filename (',' filename)* TO filename
    | create_datafile_clause
    | alter_datafile_clause
    | alter_tempfile_clause
    | move_datafile_clause
    ;

create_datafile_clause
    : CREATE DATAFILE (filename | filenumber) (',' (filename | filenumber))* (
        AS (
            //TODO (','? file_specification)+ |
            NEW
        )
    )?
    ;

alter_datafile_clause
    : DATAFILE (filename | filenumber) (',' (filename | filenumber))* (
        ONLINE
        | OFFLINE (FOR DROP)?
        | RESIZE size_clause
        | autoextend_clause
        | END BACKUP
    )
    ;

alter_tempfile_clause
    : TEMPFILE (filename | filenumber) (',' (filename | filenumber))* (
        RESIZE size_clause
        | autoextend_clause
        | DROP (INCLUDING DATAFILES)
        | ONLINE
        | OFFLINE
    )
    ;

move_datafile_clause
    : MOVE DATAFILE (filename | filenumber) (',' (filename | filenumber))* (TO filename)? REUSE? KEEP?
    ;

logfile_clauses
    : (ARCHIVELOG MANUAL? | NOARCHIVELOG)
    | NO? FORCE LOGGING
    | SET STANDBY NOLOGGING FOR (DATA AVAILABILITY | LOAD PERFORMANCE)
    | RENAME FILE filename (',' filename)* TO filename
    | CLEAR UNARCHIVED? LOGFILE logfile_descriptor (',' logfile_descriptor)* (
        UNRECOVERABLE DATAFILE
    )?
    | add_logfile_clauses
    | drop_logfile_clauses
    | switch_logfile_clause
    | supplemental_db_logging
    ;

add_logfile_clauses
    : ADD STANDBY? LOGFILE (
        (INSTANCE CHAR_STRING | THREAD UNSIGNED_INTEGER)? group_redo_logfile+
        | MEMBER filename REUSE? (',' filename REUSE?)* TO logfile_descriptor (
            ',' logfile_descriptor
        )*
    )
    ;

group_redo_logfile
    : (GROUP UNSIGNED_INTEGER)? redo_log_file_spec
    ;

drop_logfile_clauses
    : DROP STANDBY? LOGFILE (
        logfile_descriptor (',' logfile_descriptor)*
        | MEMBER filename (',' filename)*
    )
    ;

switch_logfile_clause
    : SWITCH ALL LOGFILES TO BLOCKSIZE UNSIGNED_INTEGER
    ;

supplemental_db_logging
    : add_or_drop SUPPLEMENTAL LOG (DATA | supplemental_id_key_clause | supplemental_plsql_clause)
    ;

add_or_drop
    : ADD
    | DROP
    ;

supplemental_plsql_clause
    : DATA FOR PROCEDURAL REPLICATION
    ;

logfile_descriptor
    : GROUP UNSIGNED_INTEGER
    | '(' filename (',' filename)* ')'
    | filename
    ;

controlfile_clauses
    : CREATE (LOGICAL | PHYSICAL)? STANDBY CONTROLFILE AS filename REUSE?
    | BACKUP CONTROLFILE TO (filename REUSE? | trace_file_clause)
    ;

trace_file_clause
    : TRACE (AS filename REUSE?)? (RESETLOGS | NORESETLOGS)?
    ;

standby_database_clauses
    : (
        activate_standby_db_clause
        | maximize_standby_db_clause
        | register_logfile_clause
        | commit_switchover_clause
        | start_standby_clause
        | stop_standby_clause
        | convert_database_clause
    ) parallel_clause?
    ;

activate_standby_db_clause
    : ACTIVATE (PHYSICAL | LOGICAL)? STANDBY DATABASE (FINISH APPLY)?
    ;

maximize_standby_db_clause
    : SET STANDBY DATABASE TO MAXIMIZE (PROTECTION | AVAILABILITY | PERFORMANCE)
    ;

register_logfile_clause
    : REGISTER (OR REPLACE)? (PHYSICAL | LOGICAL) LOGFILE //TODO (','? file_specification)+
    //TODO   (FOR logminer_session_name)?
    ;

commit_switchover_clause
    : (PREPARE | COMMIT) TO SWITCHOVER (
        (
            TO (
                ((PHYSICAL | LOGICAL)? PRIMARY | PHYSICAL? STANDBY) (
                    (WITH | WITHOUT)? SESSION SHUTDOWN (WAIT | NOWAIT)
                )?
                | LOGICAL STANDBY
            )
            | LOGICAL STANDBY
        )
        | CANCEL
    )?
    ;

start_standby_clause
    : START LOGICAL STANDBY APPLY IMMEDIATE? NODELAY? (
        NEW PRIMARY regular_id
        | INITIAL scn_value = UNSIGNED_INTEGER?
        | SKIP_ FAILED TRANSACTION
        | FINISH
    )?
    ;

stop_standby_clause
    : (STOP | ABORT) LOGICAL STANDBY APPLY
    ;

convert_database_clause
    : CONVERT TO (PHYSICAL | SNAPSHOT) STANDBY
    ;

default_settings_clause
    : DEFAULT EDITION EQUALS_OP edition_name
    | SET DEFAULT (BIGFILE | SMALLFILE) TABLESPACE
    | DEFAULT TABLESPACE tablespace
    | DEFAULT TEMPORARY TABLESPACE (tablespace | tablespace_group_name)
    | RENAME GLOBAL_NAME TO database ('.' domain)+
    | ENABLE BLOCK CHANGE TRACKING (USING FILE filename REUSE?)?
    | DISABLE BLOCK CHANGE TRACKING
    | flashback_mode_clause
    | set_time_zone_clause
    ;

set_time_zone_clause
    : SET TIMEZONE EQUALS_OP CHAR_STRING
    ;

instance_clauses
    : enable_or_disable INSTANCE CHAR_STRING
    ;

security_clause
    : GUARD (ALL | STANDBY | NONE)
    ;

domain
    : regular_id
    ;

database
    : regular_id
    ;

edition_name
    : regular_id
    ;

filenumber
    : UNSIGNED_INTEGER
    ;

filename
    : CHAR_STRING
    ;

prepare_clause
    : PREPARE MIRROR COPY c = id_expression (WITH (UNPROTECTED | MIRROR | HIGH) REDUNDANCY)? (
        FOR DATABASE id_expression
    )?
    ;

drop_mirror_clause
    : DROP MIRROR COPY mn = id_expression
    ;

lost_write_protection
    : (ENABLE | DISABLE | REMOVE | SUSPEND) LOST WRITE PROTECTION
    ;

cdb_fleet_clauses
    : lead_cdb_clause
    | lead_cdb_uri_clause
    ;

lead_cdb_clause
    : SET LEAD_CDB '=' (TRUE | FALSE)
    ;

lead_cdb_uri_clause
    : SET LEAD_CDB_URI '=' CHAR_STRING
    ;

property_clauses
    : PROPERTY (SET | REMOVE) DEFAULT_CREDENTIAL '=' qcn = id_expression
    ;

replay_upgrade_clauses
    : UPGRADE SYNC (ON | OFF)
    ;

alter_database_link
    : ALTER SHARED? PUBLIC? DATABASE LINK link_name (
        CONNECT TO user_object_name IDENTIFIED BY password_value link_authentication?
        | link_authentication
    )
    ;

password_value
    : id_expression
    | numeric
    | VALUES CHAR_STRING
    ;

link_authentication
    : AUTHENTICATED BY user_object_name IDENTIFIED BY password_value
    ;

// added by zrh
create_database
    : CREATE DATABASE database_name (
        USER (SYS | SYSTEM) IDENTIFIED BY password_value
        | CONTROLFILE REUSE
        | (MAXDATAFILES | MAXINSTANCES) UNSIGNED_INTEGER
        | NATIONAL? CHARACTER SET char_set_name
        | SET DEFAULT (BIGFILE | SMALLFILE) TABLESPACE
        | database_logging_clauses
        | tablespace_clauses
        | set_time_zone_clause
        | (BIGFILE | SMALLFILE)? USER_DATA TABLESPACE tablespace_group_name DATAFILE datafile_tempfile_spec (
            ',' datafile_tempfile_spec
        )*
        | enable_pluggable_database
    )+
    ;

database_logging_clauses
    : LOGFILE database_logging_sub_clause (',' database_logging_sub_clause)*
    | (MAXLOGFILES | MAXLOGMEMBERS | MAXLOGHISTORY) UNSIGNED_INTEGER
    | ARCHIVELOG
    | NOARCHIVELOG
    | FORCE LOGGING
    ;

database_logging_sub_clause
    : (GROUP UNSIGNED_INTEGER)? file_specification
    ;

tablespace_clauses
    : EXTENT MANAGEMENT LOCAL
    | SYSAUX? DATAFILE file_specification (',' file_specification)*
    | default_tablespace
    | default_temp_tablespace
    | undo_tablespace
    ;

enable_pluggable_database
    : ENABLE PLUGGABLE DATABASE (
        SEED file_name_convert? (SYSTEM tablespace_datafile_clauses)? (
            SYSAUX tablespace_datafile_clauses
        )?
    )? undo_mode_clause?
    ;

file_name_convert
    : FILE_NAME_CONVERT EQUALS_OP (
        '(' filename_convert_sub_clause (',' filename_convert_sub_clause)* ')'
        | NONE
    )
    ;

filename_convert_sub_clause
    : CHAR_STRING (',' CHAR_STRING)?
    ;

tablespace_datafile_clauses
    : DATAFILES (SIZE size_clause | autoextend_clause)+
    ;

undo_mode_clause
    : LOCAL UNDO (ON | OFF)
    ;

default_tablespace
    : DEFAULT TABLESPACE tablespace (DATAFILE datafile_tempfile_spec)? extent_management_clause?
    ;

default_temp_tablespace
    : (BIGFILE | SMALLFILE)? DEFAULT (
        TEMPORARY TABLESPACE
        | LOCAL TEMPORARY TABLESPACE FOR (ALL | LEAF)
    ) tablespace (TEMPFILE file_specification (',' file_specification)*)? extent_management_clause?
    ;

undo_tablespace
    : (BIGFILE | SMALLFILE)? UNDO TABLESPACE tablespace (
        DATAFILE file_specification (',' file_specification)*
    )?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-DATABASE.html
drop_database
    : DROP DATABASE (INCLUDING BACKUPS)? NOPROMPT?
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-DATABASE-LINK.html
create_database_link
    : CREATE SHARED? PUBLIC? DATABASE LINK dblink (
        CONNECT TO (
            CURRENT_USER
            | user_object_name IDENTIFIED BY password_value link_authentication?
        )
        | link_authentication
    )* (USING CHAR_STRING)?
    ;

dblink
    : database_name ('.' d = id_expression)* ('@' cq = id_expression)?
    ;

drop_database_link
    : DROP PUBLIC? DATABASE LINK dblink
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-TABLESPACE-SET.html
alter_tablespace_set
    : ALTER TABLESPACE SET tss = id_expression alter_tablespace_attrs
    ;

alter_tablespace_attrs
    : default_tablespace_params
    | MINIMUM EXTENT size_clause
    | RESIZE size_clause
    | COALESCE
    | SHRINK SPACE_KEYWORD (KEEP size_clause)?
    | RENAME TO nts = id_expression
    | (BEGIN | END) BACKUP
    | datafile_tempfile_clauses
    | tablespace_logging_clauses
    | tablespace_group_clause
    | tablespace_state_clauses
    | autoextend_clause
    | flashback_mode_clause
    | tablespace_retention_clause
    | alter_tablespace_encryption
    | lost_write_protection
    ;

alter_tablespace_encryption
    : ENCRYPTION (
        OFFLINE (tablespace_encryption_spec? ENCRYPT | DECRYPT)
        | ONLINE (tablespace_encryption_spec? (ENCRYPT | REKEY) | DECRYPT) ts_file_name_convert?
        | FINISH (ENCRYPT | REKEY | DECRYPT) ts_file_name_convert?
    )
    ;

ts_file_name_convert
    : FILE_NAME_CONVERT '=' '(' CHAR_STRING ',' CHAR_STRING (',' CHAR_STRING ',' CHAR_STRING)* ')' KEEP?
    ;

alter_role
    : ALTER ROLE role_name role_identified_clause container_clause?
    ;

role_identified_clause
    : NOT IDENTIFIED
    | IDENTIFIED (
        BY identifier
        | USING identifier ('.' id_expression)?
        | EXTERNALLY
        | GLOBALLY (AS CHAR_STRING)?
    )
    ;

alter_table
    : ALTER TABLE tableview_name memoptimize_read_write_clause* (
        | alter_table_properties
        | constraint_clauses
        | column_clauses
        | alter_table_partitioning
        //TODO      | alter_external_table
        | move_table_clause
    ) ((enable_disable_clause | enable_or_disable (TABLE LOCK | ALL TRIGGERS))+)?
    ;

memoptimize_read_write_clause
    : NO? MEMOPTIMIZE FOR (READ | WRITE)
    ;

alter_table_properties
    : alter_table_properties_1
    | RENAME TO tableview_name
    | shrink_clause
    | READ ONLY
    | READ WRITE
    | REKEY CHAR_STRING
    ;

alter_table_partitioning
    : add_table_partition
    | drop_table_partition
    | merge_table_partition
    | modify_table_partition
    | split_table_partition
    | truncate_table_partition
    | exchange_table_partition
    | coalesce_table_partition
    | alter_interval_partition
    ;

add_table_partition
    : ADD (
        range_partition_desc
        | list_partition_desc
        | PARTITION partition_name? (TABLESPACE tablespace)? key_compression? UNUSABLE?
    )
    ;

drop_table_partition
    : DROP (partition_extended_names | subpartition_extended_names) (
        update_index_clauses parallel_clause?
    )?
    ;

merge_table_partition
    : MERGE PARTITION partition_name AND partition_name INTO PARTITION partition_name
    ;

modify_table_partition
    : MODIFY (
        PARTITION partition_name ((ADD | DROP) list_values_clause)? (ADD range_subpartition_desc)? (
            REBUILD? UNUSABLE LOCAL INDEXES
        )? shrink_clause?
        | range_partitions
    )
    ;

split_table_partition
    : SPLIT PARTITION partition_name INTO '(' (
        range_partition_desc (',' range_partition_desc)*
        | list_partition_desc (',' list_partition_desc)*
    ) ')'
    ;

truncate_table_partition
    : TRUNCATE (partition_extended_names | subpartition_extended_names) (
        (DROP ALL? | REUSE)? STORAGE
    )? CASCADE? (update_index_clauses parallel_clause?)?
    ;

exchange_table_partition
    : EXCHANGE PARTITION partition_name WITH TABLE tableview_name ((INCLUDING | EXCLUDING) INDEXES)? (
        (WITH | WITHOUT) VALIDATION
    )?
    ;

coalesce_table_partition
    : COALESCE PARTITION parallel_clause? (allow_or_disallow CLUSTERING)?
    ;

alter_interval_partition
    : SET INTERVAL '(' (constant | expression)? ')'
    ;

partition_extended_names
    : (PARTITION | PARTITIONS) (
        partition_name (',' partition_name)*
        | '(' partition_name (',' partition_name)* ')'
        | FOR '('? partition_key_value (',' partition_key_value)* ')'?
    )
    ;

subpartition_extended_names
    : (SUBPARTITION | SUBPARTITIONS) (
        partition_name (UPDATE INDEXES)?
        | '(' partition_name (',' partition_name)* ')'
        | FOR '('? subpartition_key_value (',' subpartition_key_value)* ')'?
    )
    ;

alter_table_properties_1
    : (
        physical_attributes_clause
        | logging_clause
        | table_compression
        | inmemory_table_clause
        | supplemental_table_logging
        | allocate_extent_clause
        | deallocate_unused_clause
        | (CACHE | NOCACHE)
        | RESULT_CACHE '(' MODE (DEFAULT | FORCE) ')'
        | upgrade_table_clause
        | records_per_block_clause
        | parallel_clause
        | row_movement_clause
        | flashback_archive_clause
    )+ alter_iot_clauses?
    ;

alter_iot_clauses
    : index_org_table_clause
    | alter_overflow_clause
    | alter_mapping_table_clause
    | COALESCE
    ;

alter_mapping_table_clause
    : MAPPING TABLE (allocate_extent_clause | deallocate_unused_clause)
    ;

alter_overflow_clause
    : add_overflow_clause
    | OVERFLOW (
        segment_attributes_clause
        | allocate_extent_clause
        | shrink_clause
        | deallocate_unused_clause
    )+
    ;

add_overflow_clause
    : ADD OVERFLOW segment_attributes_clause? (
        '(' PARTITION segment_attributes_clause? (',' PARTITION segment_attributes_clause?)* ')'
    )?
    ;

update_index_clauses
    : update_global_index_clause
    | update_all_indexes_clause
    ;

update_global_index_clause
    : (UPDATE | INVALIDATE) GLOBAL INDEXES
    ;

update_all_indexes_clause
    : UPDATE INDEXES ('(' update_all_indexes_index_clause ')')?
    ;

update_all_indexes_index_clause
    : index_name '(' (update_index_partition | update_index_subpartition) ')' (
        ',' update_all_indexes_clause
    )*
    ;

update_index_partition
    : index_partition_description index_subpartition_clause? (',' update_index_partition)*
    ;

update_index_subpartition
    : SUBPARTITION subpartition_name? (TABLESPACE tablespace)? (',' update_index_subpartition)*
    ;

enable_disable_clause
    : (ENABLE | DISABLE) (VALIDATE | NOVALIDATE)? (
        UNIQUE '(' column_name (',' column_name)* ')'
        | PRIMARY KEY
        | CONSTRAINT constraint_name
    ) using_index_clause? exceptions_clause? CASCADE? ((KEEP | DROP) INDEX)?
    ;

using_index_clause
    : USING INDEX (index_name | '(' create_index ')' | index_attributes)?
    ;

index_attributes
    : (
        physical_attributes_clause
        | logging_clause
        | TABLESPACE (tablespace | DEFAULT)
        | key_compression
        | sort_or_nosort
        | REVERSE
        | visible_or_invisible
        | parallel_clause
    )+
    ;

sort_or_nosort
    : SORT
    | NOSORT
    ;

exceptions_clause
    : EXCEPTIONS INTO tableview_name
    ;

move_table_clause
    : MOVE ONLINE? segment_attributes_clause? table_compression? index_org_table_clause? (
        lob_storage_clause
        | varray_col_properties
    )* parallel_clause?
    ;

index_org_table_clause
    : (mapping_table_clause | PCTTHRESHOLD UNSIGNED_INTEGER | key_compression)+ index_org_overflow_clause?
    | index_org_overflow_clause // rule move_table_clause contains an optional block with at least one alternative that can match an empty string
    ;

mapping_table_clause
    : MAPPING TABLE
    | NOMAPPING
    ;

key_compression
    : NOCOMPRESS
    | COMPRESS UNSIGNED_INTEGER
    ;

index_org_overflow_clause
    : (INCLUDING column_name)? OVERFLOW segment_attributes_clause?
    ;

column_clauses
    : add_modify_drop_column_clauses
    | rename_column_clause
    | modify_collection_retrieval
    | modify_lob_storage_clause
    ;

modify_collection_retrieval
    : MODIFY NESTED TABLE collection_item RETURN AS (LOCATOR | VALUE)
    ;

collection_item
    : tableview_name
    ;

rename_column_clause
    : RENAME COLUMN old_column_name TO new_column_name
    ;

old_column_name
    : column_name
    ;

new_column_name
    : column_name
    ;

add_modify_drop_column_clauses
    : (constraint_clauses | add_column_clause | modify_column_clauses | drop_column_clause)+
    ;

drop_column_clause
    : SET UNUSED (COLUMN column_name | ('(' column_name (',' column_name)* ')')) (
        CASCADE CONSTRAINTS
        | INVALIDATE
    )*
    | DROP (COLUMN column_name | '(' column_name (',' column_name)* ')') (
        CASCADE CONSTRAINTS
        | INVALIDATE
    )* (CHECKPOINT UNSIGNED_INTEGER)?
    | DROP (UNUSED COLUMNS | COLUMNS CONTINUE) (CHECKPOINT UNSIGNED_INTEGER)
    ;

modify_column_clauses
    : MODIFY (
        '(' modify_col_properties (',' modify_col_properties)* ')'
        | '(' modify_col_visibility (',' modify_col_visibility)* ')'
        | modify_col_properties
        | modify_col_visibility
        | modify_col_substitutable
    )
    ;

modify_col_properties
    : column_name datatype? (DEFAULT expression)? (ENCRYPT encryption_spec | DECRYPT)? inline_constraint* lob_storage_clause?
    //TODO alter_xmlschema_clause
    ;

modify_col_visibility
    : column_name (VISIBLE | INVISIBLE)
    ;

modify_col_substitutable
    : COLUMN column_name NOT? SUBSTITUTABLE AT ALL LEVELS FORCE?
    ;

add_column_clause
    : ADD (
        '(' (column_definition | virtual_column_definition) (
            ',' (column_definition | virtual_column_definition)
        )* ')'
        | ( column_definition | virtual_column_definition)
    ) column_properties?
    //TODO       (','? out_of_line_part_storage )
    ;

alter_varray_col_properties
    : MODIFY VARRAY varray_item '(' modify_lob_parameters ')'
    ;

varray_col_properties
    : VARRAY varray_item (
        substitutable_column_clause? varray_storage_clause
        | substitutable_column_clause
    )
    ;

varray_storage_clause
    : STORE AS (SECUREFILE | BASICFILE)? LOB (
        lob_segname? '(' lob_storage_parameters ')'
        | lob_segname
    )
    ;

lob_segname
    : regular_id
    ;

lob_item
    : regular_id
    | quoted_string
    | DELIMITED_ID
    ;

lob_storage_parameters
    : TABLESPACE tablespace_name = id_expression
    | (lob_parameters storage_clause?)
    | storage_clause
    ;

lob_storage_clause
    : LOB (
        '(' lob_item (',' lob_item)* ')' STORE AS (
            (SECUREFILE | BASICFILE)
            | '(' lob_storage_parameters* ')'
        )+
        | '(' lob_item ')' STORE AS (
            (SECUREFILE | BASICFILE)
            | lob_segname
            | '(' lob_storage_parameters* ')'
        )+
    )
    ;

modify_lob_storage_clause
    : MODIFY LOB '(' lob_item ')' '(' modify_lob_parameters ')'
    ;

modify_lob_parameters
    : (
        storage_clause
        | (PCTVERSION | FREEPOOLS) UNSIGNED_INTEGER
        | REBUILD FREEPOOLS
        | lob_retention_clause
        | lob_deduplicate_clause
        | lob_compression_clause
        | ENCRYPT encryption_spec
        | DECRYPT
        | CACHE
        | (CACHE | NOCACHE | CACHE READS) logging_clause?
        | allocate_extent_clause
        | shrink_clause
        | deallocate_unused_clause
    )+
    ;

lob_parameters
    : (
        (ENABLE | DISABLE) STORAGE IN ROW
        | CHUNK UNSIGNED_INTEGER
        | PCTVERSION UNSIGNED_INTEGER
        | FREEPOOLS UNSIGNED_INTEGER
        | lob_retention_clause
        | lob_deduplicate_clause
        | lob_compression_clause
        | ENCRYPT encryption_spec
        | DECRYPT
        | (CACHE | NOCACHE | CACHE READS) logging_clause?
    )+
    ;

lob_deduplicate_clause
    : DEDUPLICATE
    | KEEP_DUPLICATES
    ;

lob_compression_clause
    : NOCOMPRESS
    | COMPRESS (HIGH | MEDIUM | LOW)?
    ;

lob_retention_clause
    : RETENTION (MAX | MIN UNSIGNED_INTEGER | AUTO | NONE)?
    ;

encryption_spec
    : (USING CHAR_STRING)? (IDENTIFIED BY REGULAR_ID)? CHAR_STRING? (NO? SALT)?
    ;

tablespace
    : id_expression
    ;

varray_item
    : (id_expression '.')? (id_expression '.')? id_expression
    ;

column_properties
    : (
        object_type_col_properties
        | nested_table_col_properties
        | (varray_col_properties | lob_storage_clause) (
            '(' lob_partition_storage (',' lob_partition_storage)* ')'
        )? //TODO '(' ( ','? lob_partition_storage)+ ')'
        | xmltype_column_properties
    )+
    ;

lob_partition_storage
    : LOB (
        '(' lob_item (',' lob_item) ')' STORE AS (
            (SECUREFILE | BASICFILE)
            | '(' lob_storage_parameters ')'
        )+
        | '(' lob_item ')' STORE AS (
            (SECUREFILE | BASICFILE)
            | lob_segname
            | '(' lob_storage_parameters ')'
        )+
    )
    ;

period_definition
    : {this.isVersion12()}? PERIOD FOR column_name ('(' start_time_column ',' end_time_column ')')?
    ;

start_time_column
    : column_name
    ;

end_time_column
    : column_name
    ;

column_definition
    : column_name ((datatype | regular_id) (COLLATE column_collation_name)?)? SORT? (
        VISIBLE
        | INVISIBLE
    )? (DEFAULT (ON NULL_)? expression | identity_clause)? (ENCRYPT encryption_spec)? (
        inline_constraint+
        | inline_ref_constraint
    )?
    ;

column_collation_name
    : id_expression
    ;

identity_clause
    : GENERATED (ALWAYS | BY DEFAULT (ON NULL_)?)? AS IDENTITY identity_options_parentheses?
    ;

//https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-TABLE.html#GUID-F9CE0CC3-13AE-4744-A43C-EAC7A71AAAB6
// NOTE to identity options
// according to the SQL Reference, identity_options be nested in parentheses.
// But statements without parentheses can also be executed successfully on a oracle database.
// See this issue for more details: https://github.com/antlr/grammars-v4/issues/3183
identity_options_parentheses
    : identity_options+
    | '(' identity_options+ ')'
    ;

identity_options
    : START WITH (numeric | LIMIT VALUE)
    | INCREMENT BY numeric
    | MAXVALUE numeric
    | NOMAXVALUE
    | MINVALUE numeric
    | NOMINVALUE
    | CYCLE
    | NOCYCLE
    | CACHE numeric
    | NOCACHE
    | ORDER
    | NOORDER
    ;

virtual_column_definition
    : column_name (datatype COLLATE column_collation_name)? (VISIBLE | INVISIBLE)? autogenerated_sequence_definition? VIRTUAL?
        evaluation_edition_clause? (UNUSABLE BEFORE (CURRENT EDITION | EDITION edition_name))? (
        UNUSABLE BEGINNING WITH ((CURRENT | NULL_) EDITION | EDITION edition_name)
    )? inline_constraint*
    ;

autogenerated_sequence_definition
    : GENERATED (ALWAYS | BY DEFAULT (ON NULL_)?)? AS IDENTITY (
        '(' (sequence_start_clause | sequence_spec)* ')'
    )?
    ;

evaluation_edition_clause
    : EVALUATE USING ((CURRENT | NULL_) EDITION | EDITION edition_name)
    ;

out_of_line_part_storage
    : PARTITION partition_name
    ;

nested_table_col_properties
    : NESTED TABLE (nested_item | COLUMN_VALUE) substitutable_column_clause? (LOCAL | GLOBAL)? STORE AS tableview_name (
        '(' ('(' object_properties ')' | physical_properties | column_properties)+ ')'
    )? (RETURN AS? (LOCATOR | VALUE))?
    ;

nested_item
    : regular_id
    ;

substitutable_column_clause
    : ELEMENT? IS OF TYPE? '(' type_name ')'
    | NOT? SUBSTITUTABLE AT ALL LEVELS
    ;

partition_name
    : regular_id
    | DELIMITED_ID
    ;

supplemental_logging_props
    : SUPPLEMENTAL LOG (supplemental_log_grp_clause | supplemental_id_key_clause)
    ;

column_or_attribute
    : regular_id
    ;

object_type_col_properties
    : COLUMN column = regular_id substitutable_column_clause
    ;

constraint_clauses
    : ADD '(' (out_of_line_constraint* | out_of_line_ref_constraint) ')'
    | ADD (out_of_line_constraint* | out_of_line_ref_constraint)
    | MODIFY (
        CONSTRAINT constraint_name
        | PRIMARY KEY
        | UNIQUE '(' column_name (',' column_name)* ')'
    ) constraint_state CASCADE?
    | RENAME CONSTRAINT old_constraint_name TO new_constraint_name
    | drop_constraint_clause+
    ;

old_constraint_name
    : constraint_name
    ;

new_constraint_name
    : constraint_name
    ;

drop_constraint_clause
    : DROP (
        PRIMARY KEY
        | UNIQUE '(' column_name (',' column_name)* ')'
        | CONSTRAINT constraint_name
    ) CASCADE? ((KEY | DROP) INDEX)? ONLINE?
    ;

add_constraint
    : ADD (CONSTRAINT constraint_name)? add_constraint_clause (
        ',' (CONSTRAINT constraint_name)? add_constraint_clause
    )+
    ;

add_constraint_clause
    : primary_key_clause
    | foreign_key_clause
    | unique_key_clause
    | check_constraint
    ;

check_constraint
    : CHECK '(' condition ')' DISABLE?
    ;

drop_constraint
    : DROP CONSTRAINT constraint_name
    ;

enable_constraint
    : ENABLE CONSTRAINT constraint_name
    ;

disable_constraint
    : DISABLE CONSTRAINT constraint_name
    ;

foreign_key_clause
    : FOREIGN KEY paren_column_list references_clause on_delete_clause?
    ;

references_clause
    : REFERENCES tableview_name paren_column_list? (ON DELETE (CASCADE | SET NULL_))?
    ;

on_delete_clause
    : ON DELETE (CASCADE | SET NULL_)
    ;

unique_key_clause
    : UNIQUE paren_column_list using_index_clause?
    ;

primary_key_clause
    : PRIMARY KEY paren_column_list using_index_clause?
    ;

// Anonymous PL/SQL code block

anonymous_block
    : (DECLARE seq_of_declare_specs)? BEGIN seq_of_statements (EXCEPTION exception_handler+)? END
    ;

// Common DDL Clauses

invoker_rights_clause
    : AUTHID (CURRENT_USER | DEFINER)
    ;

call_spec
    : LANGUAGE (java_spec | c_spec)
    ;

// Call Spec Specific Clauses

java_spec
    : JAVA NAME CHAR_STRING
    ;

c_spec
    : C_LETTER (NAME CHAR_STRING)? LIBRARY identifier c_agent_in_clause? (WITH CONTEXT)? c_parameters_clause?
    ;

c_agent_in_clause
    : AGENT IN '(' expressions ')'
    ;

c_parameters_clause
    : PARAMETERS '(' (expressions | '.' '.' '.') ')'
    ;

parameter
    : parameter_name (IN | OUT | INOUT | NOCOPY)* type_spec? default_value_part?
    ;

default_value_part
    : (ASSIGN_OP | DEFAULT) expression
    ;

// Elements Declarations

seq_of_declare_specs
    : declare_spec+
    ;

declare_spec
    : pragma_declaration
    | exception_declaration
    | procedure_spec
    | function_spec
    | variable_declaration
    | subtype_declaration
    | cursor_declaration
    | type_declaration
    | procedure_body
    | function_body
    ;

// incorporates constant_declaration
variable_declaration
    : identifier CONSTANT? type_spec (NOT NULL_)? default_value_part? ';'
    ;

subtype_declaration
    : SUBTYPE identifier IS type_spec (RANGE expression '..' expression)? (NOT NULL_)? ';'
    ;

// cursor_declaration incorportates curscursor_body and cursor_spec

cursor_declaration
    : CURSOR identifier ('(' parameter_spec (',' parameter_spec)* ')')? (RETURN type_spec)? (
        IS select_statement
    )? ';'
    ;

parameter_spec
    : parameter_name (IN? type_spec)? default_value_part?
    ;

exception_declaration
    : identifier EXCEPTION ';'
    ;

pragma_declaration
    : PRAGMA (
        SERIALLY_REUSABLE
        | AUTONOMOUS_TRANSACTION
        | EXCEPTION_INIT '(' exception_name ',' numeric_negative ')'
        | INLINE '(' id1 = identifier ',' expression ')'
        | RESTRICT_REFERENCES '(' (identifier | DEFAULT) (',' identifier)+ ')'
    ) ';'
    ;

// Record Declaration Specific Clauses

// incorporates ref_cursor_type_definition

record_type_def
    : RECORD '(' field_spec (',' field_spec)* ')'
    ;

field_spec
    : column_name type_spec? (NOT NULL_)? default_value_part?
    ;

ref_cursor_type_def
    : REF CURSOR (RETURN type_spec)?
    ;

type_declaration
    : TYPE identifier IS (table_type_def | varray_type_def | record_type_def | ref_cursor_type_def) ';'
    ;

table_type_def
    : TABLE OF type_spec table_indexed_by_part? (NOT NULL_)?
    ;

table_indexed_by_part
    : (idx1 = INDEXED | idx2 = INDEX) BY type_spec
    ;

//https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/collection-variable.html#GUID-89A1863C-65A1-40CF-9392-86E9FDC21BE9
varray_type_def
    : (VARRAY | VARYING? ARRAY) '(' expression ')' OF type_spec (NOT NULL_)?
    ;

// Statements

seq_of_statements
    : (statement (';' | EOF) | label_declaration)+
    ;

label_declaration
    : ltp1 = '<' '<' label_name '>' '>'
    ;

statement
    : body
    | block
    | assignment_statement
    | continue_statement
    | exit_statement
    | goto_statement
    | if_statement
    | loop_statement
    | forall_statement
    | null_statement
    | raise_statement
    | return_statement
    | case_statement
    | sql_statement
    | call_statement
    | pipe_row_statement
    ;

swallow_to_semi
    : ~';'+
    ;

assignment_statement
    : (general_element | bind_variable) ASSIGN_OP expression
    ;

continue_statement
    : CONTINUE label_name? (WHEN condition)?
    ;

exit_statement
    : EXIT label_name? (WHEN condition)?
    ;

goto_statement
    : GOTO label_name
    ;

if_statement
    : IF condition THEN seq_of_statements elsif_part* else_part? END IF
    ;

elsif_part
    : ELSIF condition THEN seq_of_statements
    ;

else_part
    : ELSE seq_of_statements
    ;

loop_statement
    : label_declaration? (WHILE condition | FOR cursor_loop_param)? LOOP seq_of_statements END LOOP label_name?
    ;

// Loop Specific Clause

cursor_loop_param
    : index_name IN REVERSE? lower_bound range_separator = '..' upper_bound
    | record_name IN (cursor_name ('(' expressions? ')')? | '(' select_statement ')')
    ;

//https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/FORALL-statement.html#GUID-C45B8241-F9DF-4C93-8577-C840A25963DB
forall_statement
    : FORALL index_name IN bounds_clause (SAVE EXCEPTIONS)? data_manipulation_language_statements
    ;

bounds_clause
    : lower_bound '..' upper_bound
    | INDICES OF collection_name between_bound?
    | VALUES OF index_name
    ;

between_bound
    : BETWEEN lower_bound AND upper_bound
    ;

lower_bound
    : concatenation
    ;

upper_bound
    : concatenation
    ;

null_statement
    : NULL_
    ;

raise_statement
    : RAISE exception_name?
    ;

return_statement
    : RETURN expression?
    ;

call_statement
    : CALL? routine_name function_argument? ('.' routine_name function_argument?)* (
        INTO bind_variable
    )?
    ;

pipe_row_statement
    : PIPE ROW '(' expression ')'
    ;

body
    : BEGIN seq_of_statements (EXCEPTION exception_handler+)? END label_name?
    ;

// Body Specific Clause

exception_handler
    : WHEN exception_name (OR exception_name)* THEN seq_of_statements
    ;

trigger_block
    : (DECLARE declare_spec*)? body
    ;

tps_body
    : seq_of_statements (EXCEPTION exception_handler+)?
    ;

block
    : (DECLARE declare_spec*)? body
    ;

// SQL Statements

sql_statement
    : execute_immediate
    | data_manipulation_language_statements
    | cursor_manipulation_statements
    | transaction_control_statements
    ;

execute_immediate
    : EXECUTE IMMEDIATE expression (
        into_clause using_clause?
        | using_clause dynamic_returning_clause?
        | dynamic_returning_clause
    )?
    ;

// Execute Immediate Specific Clause

dynamic_returning_clause
    : (RETURNING | RETURN) into_clause
    ;

// DML Statements

data_manipulation_language_statements
    : merge_statement
    | lock_table_statement
    | select_statement
    | update_statement
    | delete_statement
    | insert_statement
    | explain_statement
    ;

// Cursor Manipulation Statements

cursor_manipulation_statements
    : close_statement
    | open_statement
    | fetch_statement
    | open_for_statement
    ;

close_statement
    : CLOSE cursor_name
    ;

open_statement
    : OPEN cursor_name ('(' expressions? ')')?
    ;

fetch_statement
    : FETCH cursor_name (
        it1 = INTO variable_or_collection (',' variable_or_collection)*
        | BULK COLLECT INTO variable_or_collection (',' variable_or_collection)* (
            LIMIT (numeric | variable_or_collection)
        )?
    )
    ;

variable_or_collection
    : variable_name
    | collection_expression
    ;

open_for_statement
    : OPEN variable_name FOR (select_statement | expression) using_clause?
    ;

// Transaction Control SQL Statements

transaction_control_statements
    : set_transaction_command
    | set_constraint_command
    | commit_statement
    | rollback_statement
    | savepoint_statement
    ;

set_transaction_command
    : SET TRANSACTION (
        READ (ONLY | WRITE)
        | ISOLATION LEVEL (SERIALIZABLE | READ COMMITTED)
        | USE ROLLBACK SEGMENT rollback_segment_name
    )? (NAME quoted_string)?
    ;

set_constraint_command
    : SET (CONSTRAINT | CONSTRAINTS) (ALL | constraint_name (',' constraint_name)*) (
        IMMEDIATE
        | DEFERRED
    )
    ;

// https://docs.oracle.com/cd/E18283_01/server.112/e17118/statements_4010.htm#SQLRF01110
// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/COMMIT.html
commit_statement
    : COMMIT WORK? write_clause? (
        COMMENT CHAR_STRING write_clause?
        | FORCE (CHAR_STRING (',' numeric)? | CORRUPT_XID CHAR_STRING | CORRUPT_XID_ALL)
    )?
    ;

write_clause
    : WRITE (WAIT | NOWAIT)? (IMMEDIATE | BATCH)?
    ;

rollback_statement
    : ROLLBACK WORK? (TO SAVEPOINT? savepoint_name | FORCE quoted_string)?
    ;

savepoint_statement
    : SAVEPOINT savepoint_name
    ;

// Dml

/* TODO
//SHOULD BE OVERRIDEN!
compilation_unit
    : seq_of_statements* EOF
    ;

//SHOULD BE OVERRIDEN!
seq_of_statements
    : select_statement
    | update_statement
    | delete_statement
    | insert_statement
    | lock_table_statement
    | merge_statement
    | explain_statement
//    | case_statement[true]
    ;
*/

explain_statement
    : EXPLAIN PLAN (SET STATEMENT_ID '=' quoted_string)? (INTO tableview_name)? FOR (
        select_statement
        | update_statement
        | delete_statement
        | insert_statement
        | merge_statement
    )
    ;

select_only_statement
    : subquery_factoring_clause? subquery
    ;

select_statement
    : select_only_statement (for_update_clause | order_by_clause | offset_clause | fetch_clause)*
    ;

// Select Specific Clauses

subquery_factoring_clause
    : WITH factoring_element (',' factoring_element)*
    ;

factoring_element
    : query_name paren_column_list? AS '(' subquery order_by_clause? ')' search_clause? cycle_clause?
    ;

search_clause
    : SEARCH (DEPTH | BREADTH) FIRST BY column_name ASC? DESC? (NULLS FIRST)? (NULLS LAST)? (
        ',' column_name ASC? DESC? (NULLS FIRST)? (NULLS LAST)?
    )* SET column_name
    ;

cycle_clause
    : CYCLE column_list SET column_name TO expression DEFAULT expression
    ;

subquery
    : subquery_basic_elements subquery_operation_part*
    ;

subquery_basic_elements
    : query_block
    | '(' subquery ')'
    ;

subquery_operation_part
    : (UNION ALL? | INTERSECT | MINUS) subquery_basic_elements
    ;

query_block
    : SELECT (DISTINCT | UNIQUE | ALL)? selected_list into_clause? from_clause where_clause? hierarchical_query_clause? group_by_clause? model_clause?
        order_by_clause? fetch_clause?
    ;

selected_list
    : '*'
    | select_list_elements (',' select_list_elements)*
    ;

from_clause
    : FROM table_ref_list
    ;

select_list_elements
    : tableview_name '.' ASTERISK
    | expression column_alias?
    ;

table_ref_list
    : table_ref (',' table_ref)*
    ;

// NOTE to PIVOT clause
// according the SQL reference this should not be possible
// according to he reality it is. Here we probably apply pivot/unpivot onto whole join clause
// eventhough it is not enclosed in parenthesis. See pivot examples 09,10,11

table_ref
    : table_ref_aux join_clause* (pivot_clause | unpivot_clause)?
    ;

table_ref_aux
    : table_ref_aux_internal flashback_query_clause* (/*{isTableAlias()}?*/ table_alias)?
    ;

table_ref_aux_internal
    : dml_table_expression_clause (pivot_clause | unpivot_clause)?                # table_ref_aux_internal_one
    | '(' table_ref subquery_operation_part* ')' (pivot_clause | unpivot_clause)? # table_ref_aux_internal_two
    | ONLY '(' dml_table_expression_clause ')'                                    # table_ref_aux_internal_three
    ;

join_clause
    : query_partition_clause? (CROSS | NATURAL)? (INNER | outer_join_type)? JOIN table_ref_aux query_partition_clause? (
        join_on_part
        | join_using_part
    )*
    ;

join_on_part
    : ON condition
    ;

join_using_part
    : USING paren_column_list
    ;

outer_join_type
    : (FULL | LEFT | RIGHT) OUTER?
    ;

query_partition_clause
    : PARTITION BY (('(' (subquery | expressions)? ')') | expressions)
    ;

flashback_query_clause
    : VERSIONS BETWEEN (SCN | TIMESTAMP) expression
    | AS OF (SCN | TIMESTAMP | SNAPSHOT) expression
    ;

pivot_clause
    : PIVOT XML? '(' pivot_element (',' pivot_element)* pivot_for_clause pivot_in_clause ')'
    ;

pivot_element
    : aggregate_function_name '(' expression ')' column_alias?
    ;

pivot_for_clause
    : FOR (column_name | paren_column_list)
    ;

pivot_in_clause
    : IN '(' (subquery | ANY (',' ANY)* | pivot_in_clause_element (',' pivot_in_clause_element)*) ')'
    ;

pivot_in_clause_element
    : pivot_in_clause_elements column_alias?
    ;

pivot_in_clause_elements
    : expression
    | '(' expressions? ')'
    ;

unpivot_clause
    : UNPIVOT ((INCLUDE | EXCLUDE) NULLS)? '(' (column_name | paren_column_list) pivot_for_clause unpivot_in_clause ')'
    ;

unpivot_in_clause
    : IN '(' unpivot_in_elements (',' unpivot_in_elements)* ')'
    ;

unpivot_in_elements
    : (column_name | paren_column_list) (AS (constant | '(' constant (',' constant)* ')'))?
    ;

hierarchical_query_clause
    : CONNECT BY NOCYCLE? condition start_part?
    | start_part CONNECT BY NOCYCLE? condition
    ;

start_part
    : START WITH condition
    ;

group_by_clause
    : GROUP BY group_by_elements (',' group_by_elements)* having_clause?
    | having_clause (GROUP BY group_by_elements (',' group_by_elements)*)?
    ;

group_by_elements
    : grouping_sets_clause
    | rollup_cube_clause
    | expression
    ;

rollup_cube_clause
    : (ROLLUP | CUBE) '(' grouping_sets_elements (',' grouping_sets_elements)* ')'
    ;

grouping_sets_clause
    : GROUPING SETS '(' grouping_sets_elements (',' grouping_sets_elements)* ')'
    ;

grouping_sets_elements
    : rollup_cube_clause
    | '(' expressions? ')'
    | expression
    ;

having_clause
    : HAVING condition
    ;

model_clause
    : MODEL cell_reference_options* return_rows_clause? reference_model* main_model
    ;

cell_reference_options
    : (IGNORE | KEEP) NAV
    | UNIQUE (DIMENSION | SINGLE REFERENCE)
    ;

return_rows_clause
    : RETURN (UPDATED | ALL) ROWS
    ;

reference_model
    : REFERENCE reference_model_name ON '(' subquery ')' model_column_clauses cell_reference_options*
    ;

main_model
    : (MAIN main_model_name)? model_column_clauses cell_reference_options* model_rules_clause
    ;

model_column_clauses
    : model_column_partition_part? DIMENSION BY model_column_list MEASURES model_column_list
    ;

model_column_partition_part
    : PARTITION BY model_column_list
    ;

model_column_list
    : '(' model_column (',' model_column)* ')'
    ;

model_column
    : (expression | query_block) column_alias?
    ;

model_rules_clause
    : model_rules_part? '(' (model_rules_element (',' model_rules_element)*)? ')'
    ;

model_rules_part
    : RULES (UPDATE | UPSERT ALL?)? ((AUTOMATIC | SEQUENTIAL) ORDER)? model_iterate_clause?
    ;

model_rules_element
    : (UPDATE | UPSERT ALL?)? cell_assignment order_by_clause? '=' expression
    ;

cell_assignment
    : model_expression
    ;

model_iterate_clause
    : ITERATE '(' expression ')' until_part?
    ;

until_part
    : UNTIL '(' condition ')'
    ;

order_by_clause
    : ORDER SIBLINGS? BY order_by_elements (',' order_by_elements)*
    ;

order_by_elements
    : expression (ASC | DESC)? (NULLS (FIRST | LAST))?
    ;

offset_clause
    : OFFSET expression (ROW | ROWS)
    ;

fetch_clause
    : FETCH (FIRST | NEXT) (expression PERCENT_KEYWORD?)? (ROW | ROWS) (ONLY | WITH TIES)
    ;

for_update_clause
    : FOR UPDATE for_update_of_part? for_update_options?
    ;

for_update_of_part
    : OF column_list
    ;

for_update_options
    : SKIP_ LOCKED
    | NOWAIT
    | WAIT expression
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
update_statement
    : UPDATE general_table_ref update_set_clause where_clause? static_returning_clause? error_logging_clause?
    ;
*/

update_statement
    : UPDATE general_table_ref update_set_clause
    ;

// Update Specific Clauses

update_set_clause
    : SET (
        column_based_update_set_clause (',' column_based_update_set_clause)*
        | VALUE '(' identifier ')' '=' expression
    )
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
column_based_update_set_clause
    : column_name '=' expression
    | paren_column_list '=' subquery
    ;
*/

column_based_update_set_clause
    : column_name '=' expression
    ;

delete_statement
    : DELETE FROM? general_table_ref where_clause? static_returning_clause? error_logging_clause?
    ;

insert_statement
    : INSERT (single_table_insert | multi_table_insert)
    ;

// Insert Specific Clauses

single_table_insert
    : insert_into_clause (values_clause static_returning_clause? | select_statement) error_logging_clause?
    ;

multi_table_insert
    : (ALL multi_table_element+ | conditional_insert_clause) select_statement
    ;

multi_table_element
    : insert_into_clause values_clause? error_logging_clause?
    ;

conditional_insert_clause
    : (ALL | FIRST)? conditional_insert_when_part+ conditional_insert_else_part?
    ;

conditional_insert_when_part
    : WHEN condition THEN multi_table_element+
    ;

conditional_insert_else_part
    : ELSE multi_table_element+
    ;

insert_into_clause
    : INTO general_table_ref paren_column_list?
    ;

values_clause
    : VALUES (REGULAR_ID | '(' expressions ')' | collection_expression)
    ;

merge_statement
    : MERGE INTO tableview_name table_alias? USING selected_tableview ON '(' condition ')' (
        merge_update_clause merge_insert_clause?
        | merge_insert_clause merge_update_clause?
    )? error_logging_clause?
    ;

// Merge Specific Clauses

merge_update_clause
    : WHEN MATCHED THEN UPDATE SET merge_element (',' merge_element)* where_clause? merge_update_delete_part?
    ;

merge_element
    : column_name '=' expression
    ;

merge_update_delete_part
    : DELETE where_clause
    ;

merge_insert_clause
    : WHEN NOT MATCHED THEN INSERT paren_column_list? values_clause where_clause?
    ;

selected_tableview
    : (tableview_name | '(' select_statement ')') table_alias?
    ;

lock_table_statement
    : LOCK TABLE lock_table_element (',' lock_table_element)* IN lock_mode MODE wait_nowait_part?
    ;

wait_nowait_part
    : WAIT expression
    | NOWAIT
    ;

// Lock Specific Clauses

lock_table_element
    : tableview_name partition_extension_clause?
    ;

lock_mode
    : ROW SHARE
    | ROW EXCLUSIVE
    | SHARE UPDATE?
    | SHARE ROW EXCLUSIVE
    | EXCLUSIVE
    ;

// Common DDL Clauses

/* the rule below is changed to improve parse performance of Oracle redo log queries
general_table_ref
    : (dml_table_expression_clause | ONLY '(' dml_table_expression_clause ')') table_alias?
    ;
*/

general_table_ref
    : dml_table_expression_clause
    ;

static_returning_clause
    : (RETURNING | RETURN) expressions into_clause
    ;

error_logging_clause
    : LOG ERRORS error_logging_into_part? expression? error_logging_reject_part?
    ;

error_logging_into_part
    : INTO tableview_name
    ;

error_logging_reject_part
    : REJECT LIMIT (UNLIMITED | expression)
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
dml_table_expression_clause
    : table_collection_expression
    | '(' select_statement subquery_restriction_clause? ')'
    | tableview_name sample_clause?
    | json_table_clause (AS identifier)?
    ;
*/

dml_table_expression_clause
    : tableview_name
    ;

table_collection_expression
    : (TABLE | THE) ('(' subquery ')' | '(' expression ')' outer_join_sign?)
    ;

subquery_restriction_clause
    : WITH (READ ONLY | CHECK OPTION (CONSTRAINT constraint_name)?)
    ;

sample_clause
    : SAMPLE BLOCK? '(' expression (',' expression)? ')' seed_part?
    ;

seed_part
    : SEED '(' expression ')'
    ;

// Expression & Condition

condition
    : expression
    | json_condition
    ;

json_condition
    : column_name IS NOT? JSON (FORMAT JSON)? (STRICT | LAX)? ((WITH | WITHOUT) UNIQUE KEYS)?
    | JSON_EQUAL '(' expressions ')'
    ;

expressions
    : expression (',' expression)*
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
expression
    : cursor_expression
    | logical_expression
    ;
*/

expression
    : logical_expression
    ;

cursor_expression
    : CURSOR '(' subquery ')'
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
logical_expression
    : unary_logical_expression
    | logical_expression AND logical_expression
    | logical_expression OR logical_expression
    ;
*/

logical_expression
    : unary_logical_expression
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
unary_logical_expression
    : NOT? multiset_expression unary_logical_operation?
    ;
*/

unary_logical_expression
    : multiset_expression
    ;

unary_logical_operation
    : IS NOT? logical_operation
    ;

logical_operation
    : (
        NULL_
        | NAN
        | PRESENT
        | INFINITE
        | A_LETTER SET
        | EMPTY_
        | OF TYPE? '(' ONLY? type_spec (',' type_spec)* ')'
    )
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
multiset_expression
    : relational_expression (multiset_type = (MEMBER | SUBMULTISET) OF? concatenation)?
    ;
*/

multiset_expression
    : relational_expression
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
relational_expression
    : relational_expression relational_operator relational_expression
    | compound_expression
    ;
*/

relational_expression
    : compound_expression
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
compound_expression
    : concatenation (
        NOT? (
            IN in_elements
            | BETWEEN between_elements
            | like_type = (LIKE | LIKEC | LIKE2 | LIKE4) concatenation (ESCAPE concatenation)?
        )
    )?
    ;
*/

compound_expression
    : concatenation
    ;

relational_operator
    : '='
    | (NOT_EQUAL_OP | '<' '>' | '!' '=' | '^' '=')
    | ('<' | '>') '='?
    ;

in_elements
    : '(' subquery ')'
    | '(' concatenation (',' concatenation)* ')'
    | constant
    | bind_variable
    | general_element
    ;

between_elements
    : concatenation AND concatenation
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
concatenation
    : model_expression (AT (LOCAL | TIME ZONE concatenation) | interval_expression)? (
        ON OVERFLOW (TRUNCATE | ERROR)
    )?
    | concatenation op = DOUBLE_ASTERISK concatenation
    | concatenation op = (ASTERISK | SOLIDUS | MOD) concatenation
    | concatenation op = (PLUS_SIGN | MINUS_SIGN) concatenation
    | concatenation BAR BAR concatenation
    ;
*/

concatenation
    : model_expression
    ;

interval_expression
    : DAY ('(' concatenation ')')? TO SECOND ('(' concatenation ')')?
    | YEAR ('(' concatenation ')')? TO MONTH
    | concatenation (SECOND | DAY | MONTH | YEAR)
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
model_expression
    : unary_expression ('[' model_expression_element ']')?
    ;
*/

model_expression
    : unary_expression
    ;

model_expression_element
    : (ANY | expression) (',' (ANY | expression))*
    | single_column_for_loop (',' single_column_for_loop)*
    | multi_column_for_loop
    ;

single_column_for_loop
    : FOR column_name (
        IN '(' expressions? ')'
        | (LIKE expression)? FROM fromExpr = expression TO toExpr = expression action_type = (
            INCREMENT
            | DECREMENT
        ) action_expr = expression
    )
    ;

multi_column_for_loop
    : FOR paren_column_list IN '(' (subquery | '(' expressions? ')') ')'
    ;

// the rule below is changed to improve parse performance of Oracle redo log queries
//unary_expression
//    : ('-' | '+') unary_expression
//    | PRIOR unary_expression
//    | CONNECT_BY_ROOT unary_expression
//    | /*TODO {input.LT(1).getText().equalsIgnoreCase("new") && !input.LT(2).getText().equals(".")}?*/ NEW unary_expression
//    | DISTINCT unary_expression
//    | ALL unary_expression
//    | /*TODO{(input.LA(1) == CASE || input.LA(2) == CASE)}?*/ case_statement /*[false]*/
//    | quantified_expression
//    | standard_function
//    | atom
//    | implicit_cursor_expression
//    ;

unary_expression
    : standard_function
    | atom
    ;

// https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-optimization-and-tuning.html#GUID-DAF46F06-EF3F-4B1A-A518-5238B80C69FA
implicit_cursor_expression
    : SQL PERCENT_BULK_EXCEPTIONS ('.' COUNT | '(' expression ')' '.' (ERROR_INDEX | ERROR_CODE))
    ;

collection_expression
    : collation_name '(' expression ')' ('.' general_element_part)*
    ;

case_statement /*TODO [boolean isStatementParameter]
TODO scope    {
    boolean isStatement;
}
@init    {$case_statement::isStatement = $isStatementParameter;}*/
    : searched_case_statement
    | simple_case_statement
    ;

// CASE

simple_case_statement
    : label_name? ck1 = CASE expression simple_case_when_part+ case_else_part? END CASE? label_name?
    ;

simple_case_when_part
    : WHEN expression THEN (/*TODO{$case_statement::isStatement}?*/ seq_of_statements | expression)
    ;

searched_case_statement
    : label_name? ck1 = CASE searched_case_when_part+ case_else_part? END CASE? label_name?
    ;

searched_case_when_part
    : WHEN expression THEN (/*TODO{$case_statement::isStatement}?*/ seq_of_statements | expression)
    ;

case_else_part
    : ELSE (/*{$case_statement::isStatement}?*/ seq_of_statements | expression)
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
atom
    : bind_variable
    | constant
    | general_element outer_join_sign?
    | '(' subquery ')' subquery_operation_part*
    | '(' expressions ')'
    ;
*/

atom
    : constant
    | general_element
    ;

quantified_expression
    : (SOME | EXISTS | ALL | ANY) ('(' select_only_statement ')' | '(' expression (',' expression)*')')
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
string_function
    : SUBSTR '(' expression ',' expression (',' expression)? ')'
    | TO_CHAR '(' (table_element | standard_function | expression) (',' quoted_string)? (
        ',' quoted_string
    )? ')'
    | DECODE '(' expressions ')'
    | CHR '(' concatenation USING NCHAR_CS ')'
    | NVL '(' expression ',' expression ')'
    | TRIM '(' ((LEADING | TRAILING | BOTH)? expression? FROM)? concatenation ')'
    | TO_DATE '(' (table_element | standard_function | expression) (
        DEFAULT concatenation ON CONVERSION ERROR
    )? (',' quoted_string (',' quoted_string)?)? ')'
    ;
*/

string_function
    : TO_DATE '(' quoted_string ',' quoted_string ')'
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
standard_function
    : string_function
    | numeric_function_wrapper
    | json_function
    | other_function
    ;
*/

standard_function
    : string_function
    | other_function
    ;

//see as https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/JSON_ARRAY.html#GUID-46CDB3AF-5795-455B-85A8-764528CEC43B
json_function
    : JSON_ARRAY '(' json_array_element (',' json_array_element)* json_on_null_clause? json_return_clause? STRICT? ')'
    | JSON_ARRAYAGG '(' expression (FORMAT JSON)? order_by_clause? json_on_null_clause? json_return_clause? STRICT? ')'
    | JSON_OBJECT '(' json_object_content ')'
    | JSON_OBJECTAGG '(' KEY? expression VALUE expression ((NULL_ | ABSENT) ON NULL_)? (
        RETURNING (VARCHAR2 ('(' UNSIGNED_INTEGER ( BYTE | CHAR)? ')')? | CLOB | BLOB)
    )? STRICT? (WITH UNIQUE KEYS)? ')'
    | JSON_QUERY '(' expression (FORMAT JSON)? ',' CHAR_STRING json_query_returning_clause json_query_wrapper_clause? json_query_on_error_clause?
        json_query_on_empty_clause? ')'
    | JSON_SERIALIZE '(' CHAR_STRING (RETURNING json_query_return_type)? PRETTY? ASCII? TRUNCATE? (
        (NULL_ | ERROR | EMPTY_ (ARRAY | OBJECT)) ON ERROR
    )? ')'
    | JSON_TRANSFORM '(' expression ',' json_transform_op (',' json_transform_op)* ')'
    | JSON_VALUE '(' expression (FORMAT JSON)? (
        ',' CHAR_STRING? json_value_return_clause? ((ERROR | NULL_ | DEFAULT literal)? ON ERROR)? (
            (ERROR | NULL_ | DEFAULT literal)? ON EMPTY_
        )? json_value_on_mismatch_clause? ')'
    )?
    ;

json_object_content
    : (json_object_entry (',' json_object_entry)* | '*') json_on_null_clause? json_return_clause? STRICT? (
        WITH UNIQUE KEYS
    )?
    ;

json_object_entry
    : KEY? expression (VALUE | IS)? expression
    | expression ':' expression (FORMAT JSON)?
    | identifier
    ;

json_table_clause
    : JSON_TABLE '(' expression (FORMAT JSON)? (',' CHAR_STRING)? ((ERROR | NULL_) ON ERROR)? (
        (EMPTY_ | NULL_) ON EMPTY_
    )? json_column_clause? ')'
    ;

json_array_element
    : (expression | CHAR_STRING | NULL_ | UNSIGNED_INTEGER | json_function) (FORMAT JSON)?
    ;

json_on_null_clause
    : (NULL_ | ABSENT) ON NULL_
    ;

json_return_clause
    : RETURNING (VARCHAR2 ('(' UNSIGNED_INTEGER ( BYTE | CHAR)? ')')? | CLOB | BLOB)
    ;

json_transform_op
    : REMOVE CHAR_STRING ((IGNORE | ERROR)? ON MISSING)?
    | INSERT CHAR_STRING '=' CHAR_STRING ((REPLACE | IGNORE | ERROR) ON EXISTING)? (
        (NULL_ | IGNORE | ERROR | REMOVE)? ON NULL_
    )?
    | REPLACE CHAR_STRING '=' CHAR_STRING ((CREATE | IGNORE | ERROR) ON MISSING)? (
        (NULL_ | IGNORE | ERROR)? ON NULL_
    )?
    | expression (FORMAT JSON)?
    | APPEND CHAR_STRING '=' CHAR_STRING ((CREATE | IGNORE | ERROR) ON MISSING)? (
        (NULL_ | IGNORE | ERROR)? ON NULL_
    )?
    | SET CHAR_STRING '=' expression (FORMAT JSON)? ((REPLACE | IGNORE | ERROR) ON EXISTING)? (
        (CREATE | IGNORE | ERROR) ON MISSING
    )? ((NULL_ | IGNORE | ERROR)? ON NULL_)?
    ;

json_column_clause
    : COLUMNS '(' json_column_definition (',' json_column_definition)* ')'
    ;

json_column_definition
    : expression json_value_return_type? (EXISTS? PATH CHAR_STRING | TRUNCATE (PATH CHAR_STRING)?)? json_query_on_error_clause?
        json_query_on_empty_clause?
    | expression json_query_return_type? TRUNCATE? FORMAT JSON json_query_wrapper_clause? PATH CHAR_STRING
    | NESTED PATH? expression ('[' ASTERISK ']')? json_column_clause
    | expression FOR ORDINALITY
    ;

json_query_returning_clause
    : (RETURNING json_query_return_type)? PRETTY? ASCII?
    ;

json_query_return_type
    : VARCHAR2 ('(' UNSIGNED_INTEGER ( BYTE | CHAR)? ')')?
    | CLOB
    | BLOB
    ;

json_query_wrapper_clause
    : (WITHOUT ARRAY? WRAPPER)
    | (WITH (UNCONDITIONAL | CONDITIONAL)? ARRAY? WRAPPER)
    ;

json_query_on_error_clause
    : (ERROR | NULL_ | EMPTY_ | EMPTY_ ARRAY | EMPTY_ OBJECT)? ON ERROR
    ;

json_query_on_empty_clause
    : (ERROR | NULL_ | EMPTY_ | EMPTY_ ARRAY | EMPTY_ OBJECT)? ON EMPTY_
    ;

json_value_return_clause
    : RETURNING json_value_return_type? ASCII?
    ;

json_value_return_type
    : VARCHAR2 ('(' UNSIGNED_INTEGER ( BYTE | CHAR)? ')')? TRUNCATE?
    | CLOB
    | DATE
    | NUMBER '(' INTEGER (',' INTEGER)? ')'
    | TIMESTAMP (WITH TIMEZONE)?
    | SDO_GEOMETRY
    | expression (USING CASESENSITIVE MAPPING)?
    ;

json_value_on_mismatch_clause
    : (IGNORE | ERROR | NULL_) ON MISMATCH ('(' MISSING DATA | EXTRA DATA | TYPE ERROR ')')?
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
literal
    : CHAR_STRING
    | string_function
    | numeric
    | MAXVALUE
    ;
*/

literal
    : CHAR_STRING
    | numeric
    | MAXVALUE
    ;

numeric_function_wrapper
    : numeric_function (single_column_for_loop | multi_column_for_loop)?
    ;

numeric_function
    : SUM '(' (DISTINCT | ALL)? expression ')'
    | COUNT '(' (ASTERISK | ((DISTINCT | UNIQUE | ALL)? concatenation)?) ')' over_clause?
    | ROUND '(' expression (',' UNSIGNED_INTEGER)? ')'
    | AVG '(' (DISTINCT | ALL)? expression ')'
    | MAX '(' (DISTINCT | ALL)? expression ')'
    | LEAST '(' expressions ')'
    | GREATEST '(' expressions ')'
    ;

listagg_overflow_clause
    : ON OVERFLOW (ERROR | TRUNCATE) CHAR_STRING? ((WITH | WITHOUT) COUNT)?
    ;

// the rule below is changed to improve parse performance of Oracle redo log queries
//other_function
//    : over_clause_keyword function_argument_analytic over_clause?
//    | /*TODO stantard_function_enabling_using*/ regular_id function_argument_modeling using_clause?
//    | COUNT '(' (ASTERISK | (DISTINCT | UNIQUE | ALL)? concatenation) ')' over_clause?
//    | (CAST | XMLCAST) '(' (MULTISET '(' subquery ')' | concatenation) AS type_spec (
//        DEFAULT concatenation ON CONVERSION ERROR
//    )? (',' quoted_string (',' quoted_string)?)? ')'
//    | COALESCE '(' table_element (',' (numeric | quoted_string))? ')'
//    | COLLECT '(' (DISTINCT | UNIQUE)? concatenation collect_order_by_part? ')'
//    | within_or_over_clause_keyword function_argument within_or_over_part+
//    | LISTAGG '(' (ALL | DISTINCT | UNIQUE)? argument (',' CHAR_STRING)? listagg_overflow_clause? ')' (
//        WITHIN GROUP '(' order_by_clause ')'
//    )? over_clause?
//    | cursor_name (PERCENT_ISOPEN | PERCENT_FOUND | PERCENT_NOTFOUND | PERCENT_ROWCOUNT)
//    | DECOMPOSE '(' concatenation (CANONICAL | COMPATIBILITY)? ')'
//    | EXTRACT '(' regular_id FROM concatenation ')'
//    | (FIRST_VALUE | LAST_VALUE) function_argument_analytic respect_or_ignore_nulls? over_clause
//    | standard_prediction_function_keyword '(' expressions cost_matrix_clause? using_clause? ')'
//    | (TO_BINARY_DOUBLE | TO_BINARY_FLOAT | TO_NUMBER | TO_TIMESTAMP | TO_TIMESTAMP_TZ) '(' concatenation (
//        DEFAULT concatenation ON CONVERSION ERROR
//    )? (',' quoted_string (',' quoted_string)?)? ')'
//    | (TO_DSINTERVAL | TO_YMINTERVAL) '(' concatenation (DEFAULT concatenation ON CONVERSION ERROR)? ')'
//    | TRANSLATE '(' expression (USING (CHAR_CS | NCHAR_CS))? (',' expression)* ')'
//    | TREAT '(' expression AS REF? type_spec ')'
//    | TRIM '(' ((LEADING | TRAILING | BOTH)? quoted_string? FROM)? concatenation ')'
//    | VALIDATE_CONVERSION '(' concatenation AS type_spec (',' quoted_string (',' quoted_string)?)? ')'
//    | XMLAGG '(' expression order_by_clause? ')' ('.' general_element_part)*
//    | (XMLCOLATTVAL | XMLFOREST) '(' xml_multiuse_expression_element (
//        ',' xml_multiuse_expression_element
//    )* ')' ('.' general_element_part)*
//    | XMLELEMENT '(' (ENTITYESCAPING | NOENTITYESCAPING)? (NAME | EVALNAME)? expression (
//        /*TODO{input.LT(2).getText().equalsIgnoreCase("xmlattributes")}?*/ ',' xml_attributes_clause
//    )? (',' expression column_alias?)* ')' ('.' general_element_part)*
//    | XMLEXISTS '(' expression xml_passing_clause? ')'
//    | XMLPARSE '(' (DOCUMENT | CONTENT) concatenation WELLFORMED? ')' ('.' general_element_part)*
//    | XMLPI '(' (NAME identifier | EVALNAME concatenation) (',' concatenation)? ')' (
//        '.' general_element_part
//    )*
//    | XMLQUERY '(' concatenation xml_passing_clause? RETURNING CONTENT (NULL_ ON EMPTY_)? ')' (
//        '.' general_element_part
//    )*
//    | XMLROOT '(' concatenation (',' xmlroot_param_version_part)? (
//        ',' xmlroot_param_standalone_part
//    )? ')' ('.' general_element_part)*
//    | XMLSERIALIZE '(' (DOCUMENT | CONTENT) concatenation (AS type_spec)? xmlserialize_param_enconding_part? xmlserialize_param_version_part?
//        xmlserialize_param_ident_part? ((HIDE | SHOW) DEFAULTS)? ')' ('.' general_element_part)?
//    | TIME CHAR_STRING
//    | xmltable
//    ;

other_function
    : TO_TIMESTAMP '(' quoted_string ')'
    ;

over_clause_keyword
    : AVG
    | CORR
    | LAG
    | LAG_DIFF
    | LAG_DIFF_PERCENT
    | LEAD
    | MAX
    | MEDIAN
    | MIN
    | NTILE
    | RATIO_TO_REPORT
    | ROW_NUMBER
    | SUM
    | VARIANCE
    | REGR_
    | STDDEV
    | VAR_
    | COVAR_
    ;

within_or_over_clause_keyword
    : CUME_DIST
    | DENSE_RANK
    | PERCENT_RANK
    | PERCENTILE_CONT
    | PERCENTILE_DISC
    | RANK
    ;

standard_prediction_function_keyword
    : PREDICTION
    | PREDICTION_BOUNDS
    | PREDICTION_COST
    | PREDICTION_DETAILS
    | PREDICTION_PROBABILITY
    | PREDICTION_SET
    ;

over_clause
    : OVER '(' (
        query_partition_clause? (order_by_clause windowing_clause?)?
        | HIERARCHY th = id_expression OFFSET numeric (ACROSS ANCESTOR AT LEVEL id_expression)?
    ) ')'
    ;

windowing_clause
    : windowing_type (BETWEEN windowing_elements AND windowing_elements | windowing_elements)
    ;

windowing_type
    : ROWS
    | RANGE
    ;

windowing_elements
    : UNBOUNDED PRECEDING
    | CURRENT ROW
    | concatenation (PRECEDING | FOLLOWING)
    ;

using_clause
    : USING (ASTERISK | using_element (',' using_element)*)
    ;

using_element
    : (IN OUT? | OUT)? select_list_elements
    ;

collect_order_by_part
    : ORDER BY concatenation
    ;

within_or_over_part
    : WITHIN GROUP '(' order_by_clause ')'
    | over_clause
    ;

cost_matrix_clause
    : COST (
        MODEL AUTO?
        | '(' cost_class_name (',' cost_class_name)* ')' VALUES '(' expressions? ')'
    )
    ;

xml_passing_clause
    : PASSING (BY VALUE)? expression column_alias? (',' expression column_alias?)*
    ;

xml_attributes_clause
    : XMLATTRIBUTES '(' (ENTITYESCAPING | NOENTITYESCAPING)? (SCHEMACHECK | NOSCHEMACHECK)? xml_multiuse_expression_element (
        ',' xml_multiuse_expression_element
    )* ')'
    ;

xml_namespaces_clause
    : XMLNAMESPACES '(' (concatenation column_alias)? (',' concatenation column_alias)* xml_general_default_part? ')'
    ;

xml_table_column
    : xml_column_name (FOR ORDINALITY | type_spec (PATH concatenation)? xml_general_default_part?)
    ;

xml_general_default_part
    : DEFAULT concatenation
    ;

xml_multiuse_expression_element
    : expression (AS (id_expression | EVALNAME concatenation))?
    ;

xmlroot_param_version_part
    : VERSION (NO VALUE | expression)
    ;

xmlroot_param_standalone_part
    : STANDALONE (YES | NO VALUE?)
    ;

xmlserialize_param_enconding_part
    : ENCODING concatenation
    ;

xmlserialize_param_version_part
    : VERSION concatenation
    ;

xmlserialize_param_ident_part
    : NO INDENT
    | INDENT (SIZE '=' concatenation)?
    ;

// SqlPlus

sql_plus_command_no_semicolon
    : set_command
    ;

sql_plus_command
    : EXIT
    | PROMPT_MESSAGE
    | SHOW (ERR | ERRORS)
    | whenever_command
    | timing_command
    | start_command
    ;

start_command
    : START_CMD id_expression PERIOD (SQL | FILE_EXT)
    ;

whenever_command
    : WHENEVER (SQLERROR | OSERROR) (
        EXIT (SUCCESS | FAILURE | WARNING | variable_name | numeric) (COMMIT | ROLLBACK)?
        | CONTINUE (COMMIT | ROLLBACK | NONE)?
    )
    ;

set_command
    : SET regular_id (CHAR_STRING | ON | OFF | /*EXACT_NUM_LIT*/ numeric | regular_id)
    ;

timing_command
    : TIMING (START timing_text = id_expression* | SHOW | STOP)?
    ;

// Common

partition_extension_clause
    : (SUBPARTITION | PARTITION) FOR? '(' expressions? ')'
    ;

column_alias
    : AS? (identifier | quoted_string)
    | AS
    ;

table_alias
    : identifier
    | quoted_string
    ;

where_clause
    : WHERE (CURRENT OF cursor_name | expression | quantitative_where_stmt)
    ;

quantitative_where_stmt
    : expression relational_operator (SOME | ALL | ANY) '(' expression (',' expression)* ')'
    ;

into_clause
    : (BULK COLLECT)? INTO (general_element | bind_variable) (
        ',' (general_element | bind_variable)
    )*
    ;

// Common Named Elements

xml_column_name
    : identifier
    | quoted_string
    ;

cost_class_name
    : identifier
    ;

attribute_name
    : identifier
    ;

savepoint_name
    : identifier
    ;

rollback_segment_name
    : identifier
    ;

table_var_name
    : identifier
    ;

schema_name
    : identifier
    ;

routine_name
    : identifier ('.' id_expression)* ('@' link_name)?
    ;

package_name
    : identifier
    ;

implementation_type_name
    : identifier ('.' id_expression)?
    ;

parameter_name
    : identifier
    ;

reference_model_name
    : identifier
    ;

main_model_name
    : identifier
    ;

container_tableview_name
    : identifier ('.' id_expression)?
    ;

aggregate_function_name
    : identifier ('.' id_expression)*
    ;

query_name
    : identifier
    ;

grantee_name
    : id_expression identified_by?
    ;

role_name
    : id_expression
    | CONNECT
    ;

constraint_name
    : identifier ('.' id_expression)* ('@' link_name)?
    ;

label_name
    : id_expression
    ;

type_name
    : id_expression ('.' id_expression)*
    ;

sequence_name
    : id_expression ('.' id_expression)*
    ;

exception_name
    : identifier ('.' id_expression)*
    ;

function_name
    : identifier ('.' id_expression)?
    ;

procedure_name
    : identifier ('.' id_expression)?
    ;

trigger_name
    : identifier ('.' id_expression)?
    ;

variable_name
    : (INTRODUCER char_set_name)? id_expression ('.' id_expression)?
    | bind_variable
    ;

index_name
    : identifier ('.' id_expression)?
    ;

cursor_name
    : general_element
    | bind_variable
    ;

record_name
    : identifier
    | bind_variable
    ;

collection_name
    : identifier ('.' id_expression)?
    ;

link_name
    : identifier
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
column_name
    : identifier ('.' id_expression)*
    ;
*/

column_name
    : identifier
    ;

// the rule below is changed to improve parse performance of Oracle redo log queries
//tableview_name
//    : identifier ('.' id_expression)? (
//        AT_SIGN link_name (PERIOD link_name)*
//        | /*TODO{!(input.LA(2) == BY)}?*/ partition_extension_clause
//    )?
//    | xmltable outer_join_sign?
//    ;

tableview_name
    : identifier ('.' id_expression)
    ;

xmltable
    : XMLTABLE '(' (xml_namespaces_clause ',')? concatenation xml_passing_clause? (
        COLUMNS xml_table_column (',' xml_table_column)*
    )? ')' ('.' general_element_part)?
    ;

char_set_name
    : id_expression ('.' id_expression)*
    ;

synonym_name
    : identifier
    ;

// Represents a valid DB object name in DDL commands which are valid for several DB (or schema) objects.
// For instance, create synonym ... for , or rename  to .
// Both are valid for sequences, tables, views, etc.
schema_object_name
    : id_expression
    ;

dir_object_name
    : id_expression
    ;

user_object_name
    : id_expression
    ;

grant_object_name
    : tableview_name
    | USER user_object_name (',' user_object_name)*
    | DIRECTORY dir_object_name
    | EDITION schema_object_name
    | MINING MODEL schema_object_name
    | JAVA (SOURCE | RESOURCE) schema_object_name
    | SQL TRANSLATION PROFILE schema_object_name
    ;

column_list
    : column_name (',' column_name)*
    ;

paren_column_list
    : LEFT_PAREN column_list RIGHT_PAREN
    ;

// PL/SQL Specs

// NOTE: In reality this applies to aggregate functions only
keep_clause
    : KEEP '(' DENSE_RANK (FIRST | LAST) order_by_clause ')' over_clause?
    ;

function_argument
    : '(' (argument (',' argument)*)? ')' keep_clause?
    ;

function_argument_analytic
    : '(' (argument respect_or_ignore_nulls? (',' argument respect_or_ignore_nulls?)*)? ')' keep_clause?
    ;

function_argument_modeling
    : '(' column_name (',' (numeric | NULL_) (',' (numeric | NULL_))?)? USING (
        tableview_name '.' ASTERISK
        | ASTERISK
        | expression column_alias? (',' expression column_alias?)*
    ) ')' keep_clause?
    ;

respect_or_ignore_nulls
    : (RESPECT | IGNORE) NULLS
    ;

/* the rule below is changed to improve parse performance of Oracle redo log queries
argument
    : (identifier '=' '>')? expression
    ;
*/

argument
    : expression
    ;

type_spec
    : datatype
    | REF? type_name (PERCENT_ROWTYPE | PERCENT_TYPE)?
    ;

datatype
    : native_datatype_element precision_part? (WITH LOCAL? TIME ZONE | CHARACTER SET char_set_name)?
    | INTERVAL (YEAR | DAY) ('(' expression ')')? TO (MONTH | SECOND) ('(' expression ')')?
    ;

precision_part
    : '(' (numeric | ASTERISK) (',' (numeric | numeric_negative))? (CHAR | BYTE)? ')'
    ;

native_datatype_element
    : BINARY_INTEGER
    | PLS_INTEGER
    | NATURAL
    | BINARY_FLOAT
    | BINARY_DOUBLE
    | NATURALN
    | POSITIVE
    | POSITIVEN
    | SIGNTYPE
    | SIMPLE_INTEGER
    | NVARCHAR2
    | DEC
    | INTEGER
    | INT
    | NUMERIC
    | SMALLINT
    | NUMBER
    | DECIMAL
    | DOUBLE PRECISION?
    | FLOAT
    | REAL
    | NCHAR
    | LONG RAW?
    | CHAR
    | CHARACTER
    | VARCHAR2
    | VARCHAR
    | STRING
    | RAW
    | BOOLEAN
    | DATE
    | ROWID
    | UROWID
    | YEAR
    | MONTH
    | DAY
    | HOUR
    | MINUTE
    | SECOND
    | TIMEZONE_HOUR
    | TIMEZONE_MINUTE
    | TIMEZONE_REGION
    | TIMEZONE_ABBR
    | TIMESTAMP
    | TIMESTAMP_UNCONSTRAINED
    | TIMESTAMP_TZ_UNCONSTRAINED
    | TIMESTAMP_LTZ_UNCONSTRAINED
    | YMINTERVAL_UNCONSTRAINED
    | DSINTERVAL_UNCONSTRAINED
    | BFILE
    | BLOB
    | CLOB
    | NCLOB
    | MLSLABEL
    | XMLTYPE
    ;

bind_variable
    : (BINDVAR | ':' UNSIGNED_INTEGER)
    // Pro*C/C++ indicator variables
    (INDICATOR? (BINDVAR | ':' UNSIGNED_INTEGER))? ('.' general_element_part)*
    ;

general_element
    : general_element_part ('.' general_element_part)*
    ;

general_element_part
    : (INTRODUCER char_set_name)? id_expression ('@' link_name)? function_argument*
    ;

table_element
    : (INTRODUCER char_set_name)? id_expression ('.' id_expression)*
    ;

object_privilege
    : ALL PRIVILEGES?
    | ALTER
    | DEBUG
    | DELETE
    | EXECUTE
    | FLASHBACK ARCHIVE
    | INDEX
    | INHERIT PRIVILEGES
    | INSERT
    | KEEP SEQUENCE
    | MERGE VIEW
    | ON COMMIT REFRESH
    | QUERY REWRITE
    | READ
    | REFERENCES
    | SELECT
    | TRANSLATE SQL
    | UNDER
    | UPDATE
    | USE
    | WRITE
    ;

//Ordered by type rather than alphabetically
system_privilege
    : ALL PRIVILEGES
    | ADVISOR
    | ADMINISTER ANY? SQL TUNING SET
    | (ALTER | CREATE | DROP) ANY SQL PROFILE
    | ADMINISTER SQL MANAGEMENT OBJECT
    | CREATE ANY? CLUSTER
    | (ALTER | DROP) ANY CLUSTER
    | (CREATE | DROP) ANY CONTEXT
    | EXEMPT REDACTION POLICY
    | ALTER DATABASE
    | (ALTER | CREATE) PUBLIC? DATABASE LINK
    | DROP PUBLIC DATABASE LINK
    | DEBUG CONNECT SESSION
    | DEBUG ANY PROCEDURE
    | ANALYZE ANY DICTIONARY
    | CREATE ANY? DIMENSION
    | (ALTER | DROP) ANY DIMENSION
    | (CREATE | DROP) ANY DIRECTORY
    | (CREATE | DROP) ANY EDITION
    | FLASHBACK (ARCHIVE ADMINISTER | ANY TABLE)
    | (ALTER | CREATE | DROP) ANY INDEX
    | CREATE ANY? INDEXTYPE
    | (ALTER | DROP | EXECUTE) ANY INDEXTYPE
    | CREATE (ANY | EXTERNAL)? JOB
    | EXECUTE ANY (CLASS | PROGRAM)
    | MANAGE SCHEDULER
    | ADMINISTER KEY MANAGEMENT
    | CREATE ANY? LIBRARY
    | (ALTER | DROP | EXECUTE) ANY LIBRARY
    | LOGMINING
    | CREATE ANY? MATERIALIZED VIEW
    | (ALTER | DROP) ANY MATERIALIZED VIEW
    | GLOBAL? QUERY REWRITE
    | ON COMMIT REFRESH
    | CREATE ANY? MINING MODEL
    | (ALTER | DROP | SELECT | COMMENT) ANY MINING MODEL
    | CREATE ANY? CUBE
    | (ALTER | DROP | SELECT | UPDATE) ANY CUBE
    | CREATE ANY? MEASURE FOLDER
    | (DELETE | DROP | INSERT) ANY MEASURE FOLDER
    | CREATE ANY? CUBE DIMENSION
    | (ALTER | DELETE | DROP | INSERT | SELECT | UPDATE) ANY CUBE DIMENSION
    | CREATE ANY? CUBE BUILD PROCESS
    | (DROP | UPDATE) ANY CUBE BUILD PROCESS
    | CREATE ANY? OPERATOR
    | (ALTER | DROP | EXECUTE) ANY OPERATOR
    | (CREATE | ALTER | DROP) ANY OUTLINE
    | CREATE PLUGGABLE DATABASE
    | SET CONTAINER
    | CREATE ANY? PROCEDURE
    | (ALTER | DROP | EXECUTE) ANY PROCEDURE
    | (CREATE | ALTER | DROP) PROFILE
    | CREATE ROLE
    | (ALTER | DROP | GRANT) ANY ROLE
    | (CREATE | ALTER | DROP) ROLLBACK SEGMENT
    | CREATE ANY? SEQUENCE
    | (ALTER | DROP | SELECT) ANY SEQUENCE
    | (ALTER | CREATE | RESTRICTED) SESSION
    | ALTER RESOURCE COST
    | CREATE ANY? SQL TRANSLATION PROFILE
    | (ALTER | DROP | USE) ANY SQL TRANSLATION PROFILE
    | TRANSLATE ANY SQL
    | CREATE ANY? SYNONYM
    | DROP ANY SYNONYM
    | (CREATE | DROP) PUBLIC SYNONYM
    | CREATE ANY? TABLE
    | (ALTER | BACKUP | COMMENT | DELETE | DROP | INSERT | LOCK | READ | SELECT | UPDATE) ANY TABLE
    | (CREATE | ALTER | DROP | MANAGE | UNLIMITED) TABLESPACE
    | CREATE ANY? TRIGGER
    | (ALTER | DROP) ANY TRIGGER
    | ADMINISTER DATABASE TRIGGER
    | CREATE ANY? TYPE
    | (ALTER | DROP | EXECUTE | UNDER) ANY TYPE
    | (CREATE | ALTER | DROP) USER
    | CREATE ANY? VIEW
    | (DROP | UNDER | MERGE) ANY VIEW
    | (ANALYZE | AUDIT) ANY
    | BECOME USER
    | CHANGE NOTIFICATION
    | EXEMPT ACCESS POLICY
    | FORCE ANY? TRANSACTION
    | GRANT ANY OBJECT? PRIVILEGE
    | INHERIT ANY PRIVILEGES
    | KEEP DATE TIME
    | KEEP SYSGUID
    | PURGE DBA_RECYCLEBIN
    | RESUMABLE
    | SELECT ANY (DICTIONARY | TRANSACTION)
    | SYSBACKUP
    | SYSDBA
    | SYSDG
    | SYSKM
    | SYSOPER
    ;

// $>

// $




© 2015 - 2024 Weber Informatics LLC | Privacy Policy