From df3355612c4b66a2427d74c2d970b2d61ab3dbc8 Mon Sep 17 00:00:00 2001
From: hhz <1839462565@qq.com>
Date: Wed, 26 Aug 2026 20:00:50 +0800
Subject: [PATCH 1/3] fix(dm): support EXPLAIN execution plans
- route DM SQL through the DM command executor
- add dedicated DM lexer and parser support
- retrieve execution plans through DmdbConnection.getExplainInfo
- preserve SQL type, metrics, streaming, and error behavior
- cover explicit EXPLAIN, Explain actions, cancellation, and driver isolation
Fixes #2762
---
.../chat2db-community-dm/pom.xml | 23 +-
.../chat2db/plugin/dm/parser/base/DMLexer.g4 | 2524 +++++
.../chat2db/plugin/dm/parser/base/DMParser.g4 | 9730 +++++++++++++++++
.../chat2db/plugin/dm/DMCommandExecutor.java | 139 +
.../ai/chat2db/plugin/dm/DMExplainClient.java | 76 +
.../java/ai/chat2db/plugin/dm/DMMetaData.java | 6 +
.../plugin/dm/builder/DMSqlBuilder.java | 10 +
.../chat2db/plugin/dm/parser/DMDialect.java | 83 +
.../plugin/dm/parser/DMExecutableSql.java | 10 +
.../plugin/dm/parser/DMExecutionVisitor.java | 49 +
.../chat2db/plugin/dm/parser/DMSqlParser.java | 485 +-
.../plugin/dm/parser/base/DMLexerBase.java | 20 +
.../plugin/dm/parser/base/DMParserBase.java | 31 +
.../error/strategy/DMErrorStrategy.java | 29 +
.../dm/parser/listener/DMSelectListener.java | 209 +
.../dm/parser/rule/DMRulePredicate.java | 26 +
.../dm/parser/rule/manager/DMRuleManager.java | 30 +
.../rule/predicate/DMBeginBlockPredicate.java | 32 +
.../predicate/DMCreateFunctionPredicate.java | 92 +
.../predicate/DMCreatePackagePredicate.java | 38 +
.../predicate/DMCreateProcedurePredicate.java | 106 +
.../rule/predicate/DMIfBlockPredicate.java | 50 +
.../parser/visitor/DMCreateTableVisitor.java | 13 +
.../dm/parser/visitor/DMParserVisitor.java | 1075 ++
.../parser/visitor/DMSimpleParserVisitor.java | 464 +
.../parser/visitor/DMValidTableVisitor.java | 1207 ++
.../plugin/dm/DMCommandExecutorTest.java | 638 ++
.../java/dm/jdbc/driver/DmdbConnection.java | 9 +
.../ai/chat2db/spi/DefaultSQLExecutor.java | 25 +
.../ai/chat2db/spi/sql/Chat2DBContext.java | 7 +
30 files changed, 17230 insertions(+), 6 deletions(-)
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMLexer.g4
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMParser.g4
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMCommandExecutor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMExplainClient.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMDialect.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutableSql.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutionVisitor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMLexerBase.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMParserBase.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/error/strategy/DMErrorStrategy.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/listener/DMSelectListener.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/DMRulePredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/manager/DMRuleManager.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMBeginBlockPredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateFunctionPredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreatePackagePredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateProcedurePredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMIfBlockPredicate.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMCreateTableVisitor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMCommandExecutorTest.java
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/dm/jdbc/driver/DmdbConnection.java
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/pom.xml b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/pom.xml
index 4a90701922..03a9e0ad88 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/pom.xml
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/pom.xml
@@ -15,10 +15,6 @@
ai.chat2db
chat2db-community-spi
-
- ai.chat2db
- chat2db-community-oracle
-
org.junit.jupiter
junit-jupiter
@@ -40,5 +36,24 @@
src/main/resources
+
+
+ org.antlr
+ antlr4-maven-plugin
+ ${antlr4.version}
+
+ ${project.basedir}/src/main/antlr4
+ ${project.build.directory}/generated-sources/antlr4
+ true
+
+
+
+
+ antlr4
+
+
+
+
+
\ No newline at end of file
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMLexer.g4 b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMLexer.g4
new file mode 100644
index 0000000000..eeec06f463
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMLexer.g4
@@ -0,0 +1,2524 @@
+/**
+ * Oracle(c) PL/SQL 11g Parser
+ *
+ * Adapted for Dameng (DM) SQL parsing in Chat2DB Community.
+ * Derived from the Oracle PL/SQL grammar; dialect-specific rules such as
+ * EXPLAIN may differ from the upstream Oracle grammar.
+ *
+ * Copyright (c) 2009-2011 Alexandre Porcelli
+ * Copyright (c) 2015-2019 Ivan Kochurkin (KvanTTT, kvanttt@gmail.com, Positive Technologies).
+ * Copyright (c) 2017 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, maxEmptyLinesToKeep 1, reflowComments false, useTab false
+// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine
+// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true
+
+lexer grammar DMLexer;
+
+options {
+ superClass = DMLexerBase;
+ caseInsensitive = true;
+}
+
+@lexer::postinclude {
+#include
+}
+
+ABORT : 'ABORT';
+ABS : 'ABS';
+ABSENT : 'ABSENT';
+ACCESS : 'ACCESS';
+ACCESSED : 'ACCESSED';
+ACCESSIBLE : 'ACCESSIBLE';
+ACCOUNT : 'ACCOUNT';
+ACL : 'ACL';
+ACOS : 'ACOS';
+ACROSS : 'ACROSS';
+ACTION : 'ACTION';
+ACTIONS : 'ACTIONS';
+ACTIVATE : 'ACTIVATE';
+ACTIVE : 'ACTIVE';
+ACTIVE_COMPONENT : 'ACTIVE_COMPONENT';
+ACTIVE_DATA : 'ACTIVE_DATA';
+ACTIVE_FUNCTION : 'ACTIVE_FUNCTION';
+ACTIVE_TAG : 'ACTIVE_TAG';
+ACTIVITY : 'ACTIVITY';
+ADAPTIVE_PLAN : 'ADAPTIVE_PLAN';
+ADD : 'ADD';
+ADD_COLUMN : 'ADD_COLUMN';
+ADD_GROUP : 'ADD_GROUP';
+ADD_MONTHS : 'ADD_MONTHS';
+ADJ_DATE : 'ADJ_DATE';
+ADMIN : 'ADMIN';
+ADMINISTER : 'ADMINISTER';
+ADMINISTRATOR : 'ADMINISTRATOR';
+ADVANCED : 'ADVANCED';
+ADVISE : 'ADVISE';
+ADVISOR : 'ADVISOR';
+AFD_DISKSTRING : 'AFD_DISKSTRING';
+AFTER : 'AFTER';
+AGENT : 'AGENT';
+AGGREGATE : 'AGGREGATE';
+A_LETTER : 'A';
+ALIAS : 'ALIAS';
+ALL : 'ALL';
+ALLOCATE : 'ALLOCATE';
+ALLOW : 'ALLOW';
+ALL_ROWS : 'ALL_ROWS';
+ALTER : 'ALTER';
+ALTERNATE : 'ALTERNATE';
+ALWAYS : 'ALWAYS';
+ANALYTIC : 'ANALYTIC';
+ANALYZE : 'ANALYZE';
+ANCESTOR : 'ANCESTOR';
+ANCILLARY : 'ANCILLARY';
+AND : 'AND';
+AND_EQUAL : 'AND_EQUAL';
+ANOMALY : 'ANOMALY';
+ANSI_REARCH : 'ANSI_REARCH';
+ANTIJOIN : 'ANTIJOIN';
+ANY : 'ANY';
+ANYSCHEMA : 'ANYSCHEMA';
+APPEND : 'APPEND';
+APPENDCHILDXML : 'APPENDCHILDXML';
+APPEND_VALUES : 'APPEND_VALUES';
+APPLICATION : 'APPLICATION';
+APPLY : 'APPLY';
+APPROX_COUNT_DISTINCT : 'APPROX_COUNT_DISTINCT';
+ARCHIVAL : 'ARCHIVAL';
+ARCHIVE : 'ARCHIVE';
+ARCHIVED : 'ARCHIVED';
+ARCHIVELOG : 'ARCHIVELOG';
+ARRAY : 'ARRAY';
+AS : 'AS';
+ASC : 'ASC';
+ASCII : 'ASCII';
+ASCIISTR : 'ASCIISTR';
+ASIN : 'ASIN';
+ASIS : 'ASIS';
+ASSEMBLY : 'ASSEMBLY';
+ASSIGN : 'ASSIGN';
+ASSOCIATE : 'ASSOCIATE';
+ASYNC : 'ASYNC';
+ASYNCHRONOUS : 'ASYNCHRONOUS';
+ATAN2 : 'ATAN2';
+ATAN : 'ATAN';
+AT : 'AT';
+ATTRIBUTE : 'ATTRIBUTE';
+ATTRIBUTES : 'ATTRIBUTES';
+AUDIT : 'AUDIT';
+AUTHENTICATED : 'AUTHENTICATED';
+AUTHENTICATION : 'AUTHENTICATION';
+AUTHID : 'AUTHID';
+AUTHORIZATION : 'AUTHORIZATION';
+AUTOALLOCATE : 'AUTOALLOCATE';
+AUTO : 'AUTO';
+AUTOBACKUP : 'AUTOBACKUP';
+AUTOEXTEND : 'AUTOEXTEND';
+AUTO_LOGIN : 'AUTO_LOGIN';
+AUTOMATIC : 'AUTOMATIC';
+AUTONOMOUS_TRANSACTION : 'AUTONOMOUS_TRANSACTION';
+AUTO_REOPTIMIZE : 'AUTO_REOPTIMIZE';
+AVAILABILITY : 'AVAILABILITY';
+AVRO : 'AVRO';
+BACKGROUND : 'BACKGROUND';
+BACKINGFILE : 'BACKINGFILE';
+BACKUP : 'BACKUP';
+BACKUPS : 'BACKUPS';
+BACKUPSET : 'BACKUPSET';
+BASIC : 'BASIC';
+BASICFILE : 'BASICFILE';
+BATCH : 'BATCH';
+BATCHSIZE : 'BATCHSIZE';
+BATCH_TABLE_ACCESS_BY_ROWID : 'BATCH_TABLE_ACCESS_BY_ROWID';
+BECOME : 'BECOME';
+BEFORE : 'BEFORE';
+BEGIN : 'BEGIN';
+BEGINNING : 'BEGINNING';
+BEGIN_OUTLINE_DATA : 'BEGIN_OUTLINE_DATA';
+BEHALF : 'BEHALF';
+BEQUEATH : 'BEQUEATH';
+BETWEEN : 'BETWEEN';
+BFILE : 'BFILE';
+BFILENAME : 'BFILENAME';
+BIGFILE : 'BIGFILE';
+BINARY : 'BINARY';
+BINARY_DOUBLE : 'BINARY_DOUBLE';
+BINARY_DOUBLE_INFINITY : 'BINARY_DOUBLE_INFINITY';
+BINARY_DOUBLE_NAN : 'BINARY_DOUBLE_NAN';
+BINARY_FLOAT : 'BINARY_FLOAT';
+BINARY_FLOAT_INFINITY : 'BINARY_FLOAT_INFINITY';
+BINARY_FLOAT_NAN : 'BINARY_FLOAT_NAN';
+BINARY_INTEGER : 'BINARY_INTEGER';
+BIND_AWARE : 'BIND_AWARE';
+BINDING : 'BINDING';
+BIN_TO_NUM : 'BIN_TO_NUM';
+BITAND : 'BITAND';
+BITMAP_AND : 'BITMAP_AND';
+BITMAP : 'BITMAP';
+BITMAPS : 'BITMAPS';
+BITMAP_TREE : 'BITMAP_TREE';
+BITS : 'BITS';
+BLOB : 'BLOB';
+BLOCK : 'BLOCK';
+BLOCK_RANGE : 'BLOCK_RANGE';
+BLOCKS : 'BLOCKS';
+BLOCKSIZE : 'BLOCKSIZE';
+BODY : 'BODY';
+BOOLEAN : 'BOOLEAN';
+BOTH : 'BOTH';
+BOUND : 'BOUND';
+BRANCH : 'BRANCH';
+BREADTH : 'BREADTH';
+BROADCAST : 'BROADCAST';
+BSON : 'BSON';
+BUFFER : 'BUFFER';
+BUFFER_CACHE : 'BUFFER_CACHE';
+BUFFER_POOL : 'BUFFER_POOL';
+BUILD : 'BUILD';
+BULK : 'BULK';
+BY : 'BY';
+BYPASS_RECURSIVE_CHECK : 'BYPASS_RECURSIVE_CHECK';
+BYPASS_UJVC : 'BYPASS_UJVC';
+BYTE : 'BYTE';
+CACHE : 'CACHE';
+CACHE_CB : 'CACHE_CB';
+CACHE_INSTANCES : 'CACHE_INSTANCES';
+CACHE_TEMP_TABLE : 'CACHE_TEMP_TABLE';
+CACHING : 'CACHING';
+CALCULATED : 'CALCULATED';
+CALLBACK : 'CALLBACK';
+CALL : 'CALL';
+CANCEL : 'CANCEL';
+CANONICAL : 'CANONICAL';
+CAPACITY : 'CAPACITY';
+CAPTION : 'CAPTION';
+CARDINALITY : 'CARDINALITY';
+CASCADE : 'CASCADE';
+CASE : 'CASE';
+CAST : 'CAST';
+CASESENSITIVE : 'CASE-SENSITIVE';
+CATEGORY : 'CATEGORY';
+CDBDEFAULT : 'CDB$DEFAULT';
+CEIL : 'CEIL';
+CELL_FLASH_CACHE : 'CELL_FLASH_CACHE';
+CERTIFICATE : 'CERTIFICATE';
+CFILE : 'CFILE';
+CHAINED : 'CHAINED';
+CHANGE : 'CHANGE';
+CHANGETRACKING : 'CHANGETRACKING';
+CHANGE_DUPKEY_ERROR_INDEX : 'CHANGE_DUPKEY_ERROR_INDEX';
+CHARACTER : 'CHARACTER';
+CHAR : 'CHAR';
+CHAR_CS : 'CHAR_CS';
+CHARTOROWID : 'CHARTOROWID';
+CHECK_ACL_REWRITE : 'CHECK_ACL_REWRITE';
+CHECK : 'CHECK';
+CHECKPOINT : 'CHECKPOINT';
+CHILD : 'CHILD';
+CHOOSE : 'CHOOSE';
+CHR : 'CHR';
+CHUNK : 'CHUNK';
+CLASS : 'CLASS';
+CLASSIFICATION : 'CLASSIFICATION';
+CLASSIFIER : 'CLASSIFIER';
+CLAUSE : 'CLAUSE';
+CLEAN : 'CLEAN';
+CLEANUP : 'CLEANUP';
+CLEAR : 'CLEAR';
+C_LETTER : 'C';
+CLIENT : 'CLIENT';
+CLOB : 'CLOB';
+CLONE : 'CLONE';
+CLOSE_CACHED_OPEN_CURSORS : 'CLOSE_CACHED_OPEN_CURSORS';
+CLOSE : 'CLOSE';
+CLUSTER_BY_ROWID : 'CLUSTER_BY_ROWID';
+CLUSTER : 'CLUSTER';
+CLUSTER_DETAILS : 'CLUSTER_DETAILS';
+CLUSTER_DISTANCE : 'CLUSTER_DISTANCE';
+CLUSTER_ID : 'CLUSTER_ID';
+CLUSTERING : 'CLUSTERING';
+CLUSTERING_FACTOR : 'CLUSTERING_FACTOR';
+CLUSTER_PROBABILITY : 'CLUSTER_PROBABILITY';
+CLUSTER_SET : 'CLUSTER_SET';
+COALESCE : 'COALESCE';
+COALESCE_SQ : 'COALESCE_SQ';
+COARSE : 'COARSE';
+CO_AUTH_IND : 'CO_AUTH_IND';
+COLD : 'COLD';
+COLLECT : 'COLLECT';
+COLUMNAR : 'COLUMNAR';
+COLUMN_AUTH_INDICATOR : 'COLUMN_AUTH_INDICATOR';
+COLUMN : 'COLUMN';
+COLUMNS : 'COLUMNS';
+COLUMN_STATS : 'COLUMN_STATS';
+COLUMN_VALUE : 'COLUMN_VALUE';
+COMMENT : 'COMMENT';
+COMMIT : 'COMMIT';
+COMMITTED : 'COMMITTED';
+COMMON : 'COMMON';
+COMMON_DATA : 'COMMON_DATA';
+COMPACT : 'COMPACT';
+COMPATIBILITY : 'COMPATIBILITY';
+COMPILE : 'COMPILE';
+COMPLETE : 'COMPLETE';
+COMPLIANCE : 'COMPLIANCE';
+COMPONENT : 'COMPONENT';
+COMPONENTS : 'COMPONENTS';
+COMPOSE : 'COMPOSE';
+COMPOSITE : 'COMPOSITE';
+COMPOSITE_LIMIT : 'COMPOSITE_LIMIT';
+COMPOUND : 'COMPOUND';
+COMPRESS : 'COMPRESS';
+COMPUTE : 'COMPUTE';
+CONCAT : 'CONCAT';
+CON_DBID_TO_ID : 'CON_DBID_TO_ID';
+CONDITIONAL : 'CONDITIONAL';
+CONDITION : 'CONDITION';
+CONFIRM : 'CONFIRM';
+CONFORMING : 'CONFORMING';
+CON_GUID_TO_ID : 'CON_GUID_TO_ID';
+CON_ID : 'CON_ID';
+CON_NAME_TO_ID : 'CON_NAME_TO_ID';
+CONNECT_BY_CB_WHR_ONLY : 'CONNECT_BY_CB_WHR_ONLY';
+CONNECT_BY_COMBINE_SW : 'CONNECT_BY_COMBINE_SW';
+CONNECT_BY_COST_BASED : 'CONNECT_BY_COST_BASED';
+CONNECT_BY_ELIM_DUPS : 'CONNECT_BY_ELIM_DUPS';
+CONNECT_BY_FILTERING : 'CONNECT_BY_FILTERING';
+CONNECT_BY_ISCYCLE : 'CONNECT_BY_ISCYCLE';
+CONNECT_BY_ISLEAF : 'CONNECT_BY_ISLEAF';
+CONNECT_BY_ROOT : 'CONNECT_BY_ROOT';
+CONNECT : 'CONNECT';
+CONNECT_TIME : 'CONNECT_TIME';
+CONSIDER : 'CONSIDER';
+CONSISTENT : 'CONSISTENT';
+CONSTANT : 'CONSTANT';
+CONST : 'CONST';
+CONSTRAINT : 'CONSTRAINT';
+CONSTRAINTS : 'CONSTRAINTS';
+CONSTRUCTOR : 'CONSTRUCTOR';
+CONTAINER : 'CONTAINER';
+CONTAINERS : 'CONTAINERS';
+CONTAINERS_DEFAULT : 'CONTAINERS_DEFAULT';
+CONTAINER_DATA : 'CONTAINER_DATA';
+CONTAINER_MAP : 'CONTAINER_MAP';
+CONTENT : 'CONTENT';
+CONTENTS : 'CONTENTS';
+CONTEXT : 'CONTEXT';
+CONTINUE : 'CONTINUE';
+CONTROLFILE : 'CONTROLFILE';
+CON_UID_TO_ID : 'CON_UID_TO_ID';
+CONVERT : 'CONVERT';
+CONVERSION : 'CONVERSION';
+COOKIE : 'COOKIE';
+COPY : 'COPY';
+CORR_K : 'CORR_K';
+CORR_S : 'CORR_S';
+CORRUPTION : 'CORRUPTION';
+CORRUPT_XID_ALL : 'CORRUPT_XID_ALL';
+CORRUPT_XID : 'CORRUPT_XID';
+COS : 'COS';
+COSH : 'COSH';
+COST : 'COST';
+COST_XML_QUERY_REWRITE : 'COST_XML_QUERY_REWRITE';
+COUNT : 'COUNT';
+COVAR_POP : 'COVAR_POP';
+COVAR_SAMP : 'COVAR_SAMP';
+CPU_COSTING : 'CPU_COSTING';
+CPU_PER_CALL : 'CPU_PER_CALL';
+CPU_PER_SESSION : 'CPU_PER_SESSION';
+CRASH : 'CRASH';
+CREATE : 'CREATE';
+CREATE_FILE_DEST : 'CREATE_FILE_DEST';
+CREATE_STORED_OUTLINES : 'CREATE_STORED_OUTLINES';
+CREATION : 'CREATION';
+CREDENTIAL : 'CREDENTIAL';
+CRITICAL : 'CRITICAL';
+CROSS : 'CROSS';
+CROSSEDITION : 'CROSSEDITION';
+CSCONVERT : 'CSCONVERT';
+CUBE_AJ : 'CUBE_AJ';
+CUBE : 'CUBE';
+CUBE_GB : 'CUBE_GB';
+CUBE_SJ : 'CUBE_SJ';
+CUME_DISTM : 'CUME_DISTM';
+CURRENT : 'CURRENT';
+CURRENT_DATE : 'CURRENT_DATE';
+CURRENT_SCHEMA : 'CURRENT_SCHEMA';
+CURRENT_TIME : 'CURRENT_TIME';
+CURRENT_TIMESTAMP : 'CURRENT_TIMESTAMP';
+CURRENT_USER : 'CURRENT_USER';
+CURRENTV : 'CURRENTV';
+CURSOR : 'CURSOR';
+CURSOR_SHARING_EXACT : 'CURSOR_SHARING_EXACT';
+CURSOR_SPECIFIC_SEGMENT : 'CURSOR_SPECIFIC_SEGMENT';
+CUSTOMDATUM : 'CUSTOMDATUM';
+CV : 'CV';
+CYCLE : 'CYCLE';
+DANGLING : 'DANGLING';
+DATABASE : 'DATABASE';
+DATA : 'DATA';
+DATAFILE : 'DATAFILE';
+DATAFILES : 'DATAFILES';
+DATAGUARDCONFIG : 'DATAGUARDCONFIG';
+DATAMOVEMENT : 'DATAMOVEMENT';
+DATAOBJNO : 'DATAOBJNO';
+DATAOBJ_TO_MAT_PARTITION : 'DATAOBJ_TO_MAT_PARTITION';
+DATAOBJ_TO_PARTITION : 'DATAOBJ_TO_PARTITION';
+DATAPUMP : 'DATAPUMP';
+DATA_SECURITY_REWRITE_LIMIT : 'DATA_SECURITY_REWRITE_LIMIT';
+DATE : 'DATE';
+DATE_MODE : 'DATE_MODE';
+DAY : 'DAY';
+DAYS : 'DAYS';
+DBA : 'DBA';
+DBA_RECYCLEBIN : 'DBA_RECYCLEBIN';
+DBMS_STATS : 'DBMS_STATS';
+DB_ROLE_CHANGE : 'DB_ROLE_CHANGE';
+DBTIMEZONE : 'DBTIMEZONE';
+DB_UNIQUE_NAME : 'DB_UNIQUE_NAME';
+DB_VERSION : 'DB_VERSION';
+DDL : 'DDL';
+DEALLOCATE : 'DEALLOCATE';
+DEBUG : 'DEBUG';
+DEBUGGER : 'DEBUGGER';
+DEC : 'DEC';
+DECIMAL : 'DECIMAL';
+DECLARE : 'DECLARE';
+DECOMPOSE : 'DECOMPOSE';
+DECORRELATE : 'DECORRELATE';
+DECR : 'DECR';
+DECREMENT : 'DECREMENT';
+DECRYPT : 'DECRYPT';
+DEDUPLICATE : 'DEDUPLICATE';
+DEFAULT : 'DEFAULT';
+DEFAULTS : 'DEFAULTS';
+DEFAULT_COLLATION : 'DEFAULT_COLLATION';
+DEFAULT_CREDENTIAL : 'DEFAULT_CREDENTIAL';
+DEFERRABLE : 'DEFERRABLE';
+DEFERRED : 'DEFERRED';
+DEFINED : 'DEFINED';
+DEFINE : 'DEFINE';
+DEFINER : 'DEFINER';
+DEGREE : 'DEGREE';
+DELAY : 'DELAY';
+DELEGATE : 'DELEGATE';
+DELETE_ALL : 'DELETE_ALL';
+DELETE : 'DELETE';
+DELETEXML : 'DELETEXML';
+DEMAND : 'DEMAND';
+DENSE_RANKM : 'DENSE_RANKM';
+DEPENDENT : 'DEPENDENT';
+DEPRECATE : 'DEPRECATE';
+DEPTH : 'DEPTH';
+DEQUEUE : 'DEQUEUE';
+DEREF : 'DEREF';
+DEREF_NO_REWRITE : 'DEREF_NO_REWRITE';
+DESC : 'DESC';
+DESCRIPTION : 'DESCRIPTION';
+DESTROY : 'DESTROY';
+DETACHED : 'DETACHED';
+DETERMINES : 'DETERMINES';
+DETERMINISTIC : 'DETERMINISTIC';
+DICTIONARY : 'DICTIONARY';
+DIMENSION : 'DIMENSION';
+DIMENSIONS : 'DIMENSIONS';
+DIRECT_LOAD : 'DIRECT_LOAD';
+DIRECTORY : 'DIRECTORY';
+DIRECT_PATH : 'DIRECT_PATH';
+DISABLE_ALL : 'DISABLE_ALL';
+DISABLE : 'DISABLE';
+DISABLE_PARALLEL_DML : 'DISABLE_PARALLEL_DML';
+DISABLE_PRESET : 'DISABLE_PRESET';
+DISABLE_RPKE : 'DISABLE_RPKE';
+DISALLOW : 'DISALLOW';
+DISASSOCIATE : 'DISASSOCIATE';
+DISCARD : 'DISCARD';
+DISCONNECT : 'DISCONNECT';
+DISK : 'DISK';
+DISKGROUP : 'DISKGROUP';
+DISKGROUP_PLUS : '\'+ DISKGROUP';
+DISKS : 'DISKS';
+DISMOUNT : 'DISMOUNT';
+DISTINCT : 'DISTINCT';
+DISTINGUISHED : 'DISTINGUISHED';
+DISTRIBUTED : 'DISTRIBUTED';
+DISTRIBUTE : 'DISTRIBUTE';
+DML : 'DML';
+DML_UPDATE : 'DML_UPDATE';
+DOCFIDELITY : 'DOCFIDELITY';
+DOCUMENT : 'DOCUMENT';
+DOLLAR_ELSE : '$ELSE';
+DOLLAR_ELSIF : '$ELSIF';
+DOLLAR_END : '$END';
+DOLLAR_ERROR : '$ERROR';
+DOLLAR_IF : '$IF';
+DOLLAR_THEN : '$THEN';
+DOMAIN_INDEX_FILTER : 'DOMAIN_INDEX_FILTER';
+DOMAIN_INDEX_NO_SORT : 'DOMAIN_INDEX_NO_SORT';
+DOMAIN_INDEX_SORT : 'DOMAIN_INDEX_SORT';
+DOUBLE : 'DOUBLE';
+DOWNGRADE : 'DOWNGRADE';
+DRIVING_SITE : 'DRIVING_SITE';
+DROP_COLUMN : 'DROP_COLUMN';
+DROP : 'DROP';
+DROP_GROUP : 'DROP_GROUP';
+DSINTERVAL_UNCONSTRAINED : 'DSINTERVAL_UNCONSTRAINED';
+DST_UPGRADE_INSERT_CONV : 'DST_UPGRADE_INSERT_CONV';
+DUMP : 'DUMP';
+DUMPSET : 'DUMPSET';
+DUPLICATE : 'DUPLICATE';
+DV : 'DV';
+DYNAMIC : 'DYNAMIC';
+DYNAMIC_SAMPLING : 'DYNAMIC_SAMPLING';
+DYNAMIC_SAMPLING_EST_CDN : 'DYNAMIC_SAMPLING_EST_CDN';
+E_LETTER : 'E';
+EACH : 'EACH';
+EDITIONABLE : 'EDITIONABLE';
+EDITION : 'EDITION';
+EDITIONING : 'EDITIONING';
+EDITIONS : 'EDITIONS';
+ELEMENT : 'ELEMENT';
+ELIM_GROUPBY : 'ELIM_GROUPBY';
+ELIMINATE_JOIN : 'ELIMINATE_JOIN';
+ELIMINATE_OBY : 'ELIMINATE_OBY';
+ELIMINATE_OUTER_JOIN : 'ELIMINATE_OUTER_JOIN';
+ELSE : 'ELSE';
+ELSIF : 'ELSIF';
+EM : 'EM';
+EMPTY_BLOB : 'EMPTY_BLOB';
+EMPTY_CLOB : 'EMPTY_CLOB';
+EMPTY_ : 'EMPTY';
+ENABLE_ALL : 'ENABLE_ALL';
+ENABLE : 'ENABLE';
+ENABLE_PARALLEL_DML : 'ENABLE_PARALLEL_DML';
+ENABLE_PRESET : 'ENABLE_PRESET';
+ENCODING : 'ENCODING';
+ENCRYPT : 'ENCRYPT';
+ENCRYPTION : 'ENCRYPTION';
+END : 'END';
+END_OUTLINE_DATA : 'END_OUTLINE_DATA';
+ENFORCED : 'ENFORCED';
+ENFORCE : 'ENFORCE';
+ENQUEUE : 'ENQUEUE';
+ENTERPRISE : 'ENTERPRISE';
+ENTITYESCAPING : 'ENTITYESCAPING';
+ENTRY : 'ENTRY';
+EQUIPART : 'EQUIPART';
+ERR : 'ERR';
+ERROR_ARGUMENT : 'ERROR_ARGUMENT';
+ERROR : 'ERROR';
+ERROR_ON_OVERLAP_TIME : 'ERROR_ON_OVERLAP_TIME';
+ERRORS : 'ERRORS';
+ERROR_INDEX : 'ERROR_INDEX';
+ERROR_CODE : 'ERROR_CODE';
+ESCAPE : 'ESCAPE';
+ESTIMATE : 'ESTIMATE';
+EVAL : 'EVAL';
+EVALNAME : 'EVALNAME';
+EVALUATE : 'EVALUATE';
+EVALUATION : 'EVALUATION';
+EVENTS : 'EVENTS';
+EVERY : 'EVERY';
+EXCEPT : 'EXCEPT';
+EXCEPTION : 'EXCEPTION';
+EXCEPTION_INIT : 'EXCEPTION_INIT';
+EXCEPTIONS : 'EXCEPTIONS';
+EXCHANGE : 'EXCHANGE';
+EXCLUDE : 'EXCLUDE';
+EXCLUDING : 'EXCLUDING';
+EXCLUSIVE : 'EXCLUSIVE';
+EXECUTE : 'EXECUTE';
+EXEMPT : 'EXEMPT';
+EXISTING : 'EXISTING';
+EXISTS : 'EXISTS';
+EXISTSNODE : 'EXISTSNODE';
+EXIT : 'EXIT';
+EXPAND_GSET_TO_UNION : 'EXPAND_GSET_TO_UNION';
+EXPAND_TABLE : 'EXPAND_TABLE';
+EXP : 'EXP';
+EXPIRE : 'EXPIRE';
+EXPLAIN : 'EXPLAIN';
+EXPLOSION : 'EXPLOSION';
+EXPORT : 'EXPORT';
+EXPR_CORR_CHECK : 'EXPR_CORR_CHECK';
+EXPRESS : 'EXPRESS';
+EXTENDS : 'EXTENDS';
+EXTENT : 'EXTENT';
+EXTENTS : 'EXTENTS';
+EXTERNAL : 'EXTERNAL';
+EXTERNALLY : 'EXTERNALLY';
+EXTRACTCLOBXML : 'EXTRACTCLOBXML';
+EXTRACT : 'EXTRACT';
+EXTRACTVALUE : 'EXTRACTVALUE';
+EXTRA : 'EXTRA';
+FACILITY : 'FACILITY';
+FACT : 'FACT';
+FACTOR : 'FACTOR';
+FACTORIZE_JOIN : 'FACTORIZE_JOIN';
+FAILED : 'FAILED';
+FAILED_LOGIN_ATTEMPTS : 'FAILED_LOGIN_ATTEMPTS';
+FAILGROUP : 'FAILGROUP';
+FAILOVER : 'FAILOVER';
+FAILURE : 'FAILURE';
+FALSE : 'FALSE';
+FAMILY : 'FAMILY';
+FAR : 'FAR';
+FAST : 'FAST';
+FASTSTART : 'FASTSTART';
+FBTSCAN : 'FBTSCAN';
+FEATURE : 'FEATURE';
+FEATURE_DETAILS : 'FEATURE_DETAILS';
+FEATURE_ID : 'FEATURE_ID';
+FEATURE_SET : 'FEATURE_SET';
+FEATURE_VALUE : 'FEATURE_VALUE';
+FETCH : 'FETCH';
+FILE : 'FILE';
+FILE_NAME_CONVERT : 'FILE_NAME_CONVERT';
+FILEGROUP : 'FILEGROUP';
+FILESTORE : 'FILESTORE';
+FILESYSTEM_LIKE_LOGGING : 'FILESYSTEM_LIKE_LOGGING';
+FILTER : 'FILTER';
+FINAL : 'FINAL';
+FINE : 'FINE';
+FINISH : 'FINISH';
+FIRST : 'FIRST';
+FIRSTM : 'FIRSTM';
+FIRST_ROWS : 'FIRST_ROWS';
+FIRST_VALUE : 'FIRST_VALUE';
+FIXED_VIEW_DATA : 'FIXED_VIEW_DATA';
+FLAGGER : 'FLAGGER';
+FLASHBACK : 'FLASHBACK';
+FLASH_CACHE : 'FLASH_CACHE';
+FLOAT : 'FLOAT';
+FLOB : 'FLOB';
+FLEX : 'FLEX';
+FLOOR : 'FLOOR';
+FLUSH : 'FLUSH';
+FOLDER : 'FOLDER';
+FOLLOWING : 'FOLLOWING';
+FOLLOWS : 'FOLLOWS';
+FORALL : 'FORALL';
+FORCE : 'FORCE';
+FORCE_XML_QUERY_REWRITE : 'FORCE_XML_QUERY_REWRITE';
+FOREIGN : 'FOREIGN';
+FOREVER : 'FOREVER';
+FOR : 'FOR';
+FORMAT : 'FORMAT';
+FORWARD : 'FORWARD';
+FRAGMENT_NUMBER : 'FRAGMENT_NUMBER';
+FREELIST : 'FREELIST';
+FREELISTS : 'FREELISTS';
+FREEPOOLS : 'FREEPOOLS';
+FRESH : 'FRESH';
+FROM : 'FROM';
+FROM_TZ : 'FROM_TZ';
+FULL : 'FULL';
+FULL_OUTER_JOIN_TO_OUTER : 'FULL_OUTER_JOIN_TO_OUTER';
+FUNCTION : 'FUNCTION';
+FUNCTIONS : 'FUNCTIONS';
+FTP : 'FTP';
+G_LETTER : 'G';
+GATHER_OPTIMIZER_STATISTICS : 'GATHER_OPTIMIZER_STATISTICS';
+GATHER_PLAN_STATISTICS : 'GATHER_PLAN_STATISTICS';
+GBY_CONC_ROLLUP : 'GBY_CONC_ROLLUP';
+GBY_PUSHDOWN : 'GBY_PUSHDOWN';
+GENERATED : 'GENERATED';
+GET : 'GET';
+GLOBAL : 'GLOBAL';
+GLOBALLY : 'GLOBALLY';
+GLOBAL_NAME : 'GLOBAL_NAME';
+GLOBAL_TOPIC_ENABLED : 'GLOBAL_TOPIC_ENABLED';
+GOTO : 'GOTO';
+GRANT : 'GRANT';
+GROUP_BY : 'GROUP_BY';
+GROUP : 'GROUP';
+GROUP_ID : 'GROUP_ID';
+GROUPING : 'GROUPING';
+GROUPING_ID : 'GROUPING_ID';
+GROUPS : 'GROUPS';
+GUARANTEED : 'GUARANTEED';
+GUARANTEE : 'GUARANTEE';
+GUARD : 'GUARD';
+HALF_YEARS : 'HALF_YEARS';
+HASH_AJ : 'HASH_AJ';
+HASH : 'HASH';
+HASHKEYS : 'HASHKEYS';
+HASH_SJ : 'HASH_SJ';
+HAVING : 'HAVING';
+HEADER : 'HEADER';
+HEAP : 'HEAP';
+HELP : 'HELP';
+HEXTORAW : 'HEXTORAW';
+HEXTOREF : 'HEXTOREF';
+HIDDEN_KEYWORD : 'HIDDEN';
+HIDE : 'HIDE';
+HIER_ORDER : 'HIER_ORDER';
+HIERARCHICAL : 'HIERARCHICAL';
+HIERARCHIES : 'HIERARCHIES';
+HIERARCHY : 'HIERARCHY';
+HIGH : 'HIGH';
+HINTSET_BEGIN : 'HINTSET_BEGIN';
+HINTSET_END : 'HINTSET_END';
+HOT : 'HOT';
+HOUR : 'HOUR';
+HOURS : 'HOURS';
+HTTP : 'HTTP';
+HWM_BROKERED : 'HWM_BROKERED';
+HYBRID : 'HYBRID';
+H_LETTER : 'H';
+IDENTIFIED : 'IDENTIFIED';
+IDENTIFIER : 'IDENTIFIER';
+IDENTITY : 'IDENTITY';
+IDGENERATORS : 'IDGENERATORS';
+ID : 'ID';
+IDLE_TIME : 'IDLE_TIME';
+IF : 'IF';
+IGNORE : 'IGNORE';
+IGNORE_OPTIM_EMBEDDED_HINTS : 'IGNORE_OPTIM_EMBEDDED_HINTS';
+IGNORE_ROW_ON_DUPKEY_INDEX : 'IGNORE_ROW_ON_DUPKEY_INDEX';
+IGNORE_WHERE_CLAUSE : 'IGNORE_WHERE_CLAUSE';
+ILM : 'ILM';
+IMMEDIATE : 'IMMEDIATE';
+IMPACT : 'IMPACT';
+IMPORT : 'IMPORT';
+INACTIVE : 'INACTIVE';
+INACTIVE_ACCOUNT_TIME : 'INACTIVE_ACCOUNT_TIME';
+INCLUDE : 'INCLUDE';
+INCLUDE_VERSION : 'INCLUDE_VERSION';
+INCLUDING : 'INCLUDING';
+INCREMENTAL : 'INCREMENTAL';
+INCREMENT : 'INCREMENT';
+INCR : 'INCR';
+INDENT : 'INDENT';
+INDEX_ASC : 'INDEX_ASC';
+INDEX_COMBINE : 'INDEX_COMBINE';
+INDEX_DESC : 'INDEX_DESC';
+INDEXED : 'INDEXED';
+INDEXES : 'INDEXES';
+INDEX_FFS : 'INDEX_FFS';
+INDEX_FILTER : 'INDEX_FILTER';
+INDEX : 'INDEX';
+INDEXING : 'INDEXING';
+INDEX_JOIN : 'INDEX_JOIN';
+INDEX_ROWS : 'INDEX_ROWS';
+INDEX_RRS : 'INDEX_RRS';
+INDEX_RS_ASC : 'INDEX_RS_ASC';
+INDEX_RS_DESC : 'INDEX_RS_DESC';
+INDEX_RS : 'INDEX_RS';
+INDEX_SCAN : 'INDEX_SCAN';
+INDEX_SKIP_SCAN : 'INDEX_SKIP_SCAN';
+INDEX_SS_ASC : 'INDEX_SS_ASC';
+INDEX_SS_DESC : 'INDEX_SS_DESC';
+INDEX_SS : 'INDEX_SS';
+INDEX_STATS : 'INDEX_STATS';
+INDEXTYPE : 'INDEXTYPE';
+INDEXTYPES : 'INDEXTYPES';
+INDICATOR : 'INDICATOR';
+INDICES : 'INDICES';
+INFINITE : 'INFINITE';
+INFORMATIONAL : 'INFORMATIONAL';
+INHERIT : 'INHERIT';
+IN : 'IN';
+INITCAP : 'INITCAP';
+INITIAL : 'INITIAL';
+INITIALIZED : 'INITIALIZED';
+INITIALLY : 'INITIALLY';
+INITRANS : 'INITRANS';
+INLINE : 'INLINE';
+INLINE_XMLTYPE_NT : 'INLINE_XMLTYPE_NT';
+INMEMORY : 'INMEMORY';
+IN_MEMORY_METADATA : 'IN_MEMORY_METADATA';
+INMEMORY_PRUNING : 'INMEMORY_PRUNING';
+INNER : 'INNER';
+INOUT : 'INOUT';
+INPLACE : 'INPLACE';
+INSERTCHILDXMLAFTER : 'INSERTCHILDXMLAFTER';
+INSERTCHILDXMLBEFORE : 'INSERTCHILDXMLBEFORE';
+INSERTCHILDXML : 'INSERTCHILDXML';
+INSERT : 'INSERT';
+INSERTXMLAFTER : 'INSERTXMLAFTER';
+INSERTXMLBEFORE : 'INSERTXMLBEFORE';
+INSTANCE : 'INSTANCE';
+INSTANCES : 'INSTANCES';
+INSTANTIABLE : 'INSTANTIABLE';
+INSTANTLY : 'INSTANTLY';
+INSTEAD : 'INSTEAD';
+INSTR2 : 'INSTR2';
+INSTR4 : 'INSTR4';
+INSTRB : 'INSTRB';
+INSTRC : 'INSTRC';
+INSTR : 'INSTR';
+INTEGER : 'INTEGER';
+INTERLEAVED : 'INTERLEAVED';
+INTERMEDIATE : 'INTERMEDIATE';
+INTERNAL_CONVERT : 'INTERNAL_CONVERT';
+INTERNAL_USE : 'INTERNAL_USE';
+INTERPRETED : 'INTERPRETED';
+INTERSECT : 'INTERSECT';
+INTERVAL : 'INTERVAL';
+INT : 'INT';
+INTO : 'INTO';
+INVALIDATE : 'INVALIDATE';
+INVALIDATION : 'INVALIDATION';
+INVISIBLE : 'INVISIBLE';
+IN_XQUERY : 'IN_XQUERY';
+IS : 'IS';
+IS_LEAF : 'IS_LEAF';
+ISOLATION : 'ISOLATION';
+ISOLATION_LEVEL : 'ISOLATION_LEVEL';
+ITERATE : 'ITERATE';
+ITERATION_NUMBER : 'ITERATION_NUMBER';
+JAVA : 'JAVA';
+JOB : 'JOB';
+JOIN : 'JOIN';
+JSON_ARRAYAGG : 'JSON_ARRAYAGG';
+JSON_ARRAY : 'JSON_ARRAY';
+JSON_EQUAL : 'JSON_EQUAL';
+JSON_EXISTS2 : 'JSON_EXISTS2';
+JSON_EXISTS : 'JSON_EXISTS';
+JSONGET : 'JSONGET';
+JSON : 'JSON';
+JSON_OBJECTAGG : 'JSON_OBJECTAGG';
+JSON_OBJECT : 'JSON_OBJECT';
+JSONPARSE : 'JSONPARSE';
+JSON_QUERY : 'JSON_QUERY';
+JSON_SERIALIZE : 'JSON_SERIALIZE';
+JSON_TABLE : 'JSON_TABLE';
+JSON_TEXTCONTAINS2 : 'JSON_TEXTCONTAINS2';
+JSON_TEXTCONTAINS : 'JSON_TEXTCONTAINS';
+JSON_TRANSFORM : 'JSON_TRANSFORM';
+JSON_VALUE : 'JSON_VALUE';
+K_LETTER : 'K';
+KEEP_DUPLICATES : 'KEEP_DUPLICATES';
+KEEP : 'KEEP';
+KERBEROS : 'KERBEROS';
+KEY : 'KEY';
+KEY_LENGTH : 'KEY_LENGTH';
+KEYSIZE : 'KEYSIZE';
+KEYS : 'KEYS';
+KEYSTORE : 'KEYSTORE';
+KILL : 'KILL';
+LABEL : 'LABEL';
+LANGUAGE : 'LANGUAGE';
+LAST_DAY : 'LAST_DAY';
+LAST : 'LAST';
+LAST_VALUE : 'LAST_VALUE';
+LATERAL : 'LATERAL';
+LAX : 'LAX';
+LAYER : 'LAYER';
+LDAP_REGISTRATION_ENABLED : 'LDAP_REGISTRATION_ENABLED';
+LDAP_REGISTRATION : 'LDAP_REGISTRATION';
+LDAP_REG_SYNC_INTERVAL : 'LDAP_REG_SYNC_INTERVAL';
+LEAF : 'LEAF';
+LEAD_CDB : 'LEAD_CDB';
+LEAD_CDB_URI : 'LEAD_CDB_URI';
+LEADING : 'LEADING';
+LEFT : 'LEFT';
+LENGTH2 : 'LENGTH2';
+LENGTH4 : 'LENGTH4';
+LENGTHB : 'LENGTHB';
+LENGTHC : 'LENGTHC';
+LENGTH : 'LENGTH';
+LESS : 'LESS';
+LEVEL : 'LEVEL';
+LEVEL_NAME : 'LEVEL_NAME';
+LEVELS : 'LEVELS';
+LIBRARY : 'LIBRARY';
+LIFECYCLE : 'LIFECYCLE';
+LIFE : 'LIFE';
+LIFETIME : 'LIFETIME';
+LIKE2 : 'LIKE2';
+LIKE4 : 'LIKE4';
+LIKEC : 'LIKEC';
+LIKE_EXPAND : 'LIKE_EXPAND';
+LIKE : 'LIKE';
+LIMIT : 'LIMIT';
+LINEAR : 'LINEAR';
+LINK : 'LINK';
+LIST : 'LIST';
+LN : 'LN';
+LNNVL : 'LNNVL';
+LOAD : 'LOAD';
+LOB : 'LOB';
+LOBNVL : 'LOBNVL';
+LOBS : 'LOBS';
+LOCAL_INDEXES : 'LOCAL_INDEXES';
+LOCAL : 'LOCAL';
+LOCALTIME : 'LOCALTIME';
+LOCALTIMESTAMP : 'LOCALTIMESTAMP';
+LOCATION : 'LOCATION';
+LOCATOR : 'LOCATOR';
+LOCKDOWN : 'LOCKDOWN';
+LOCKED : 'LOCKED';
+LOCKING : 'LOCKING';
+LOCK : 'LOCK';
+LOGFILE : 'LOGFILE';
+LOGFILES : 'LOGFILES';
+LOGGING : 'LOGGING';
+LOGICAL : 'LOGICAL';
+LOGICAL_READS_PER_CALL : 'LOGICAL_READS_PER_CALL';
+LOGICAL_READS_PER_SESSION : 'LOGICAL_READS_PER_SESSION';
+LOG : 'LOG';
+LOGMINING : 'LOGMINING';
+LOGOFF : 'LOGOFF';
+LOGON : 'LOGON';
+LOG_READ_ONLY_VIOLATIONS : 'LOG_READ_ONLY_VIOLATIONS';
+LONG : 'LONG';
+LOOP : 'LOOP';
+LOST : 'LOST';
+LOWER : 'LOWER';
+LOW : 'LOW';
+LPAD : 'LPAD';
+LTRIM : 'LTRIM';
+M_LETTER : 'M';
+MAIN : 'MAIN';
+MAKE_REF : 'MAKE_REF';
+MANAGED : 'MANAGED';
+MANAGE : 'MANAGE';
+MANAGEMENT : 'MANAGEMENT';
+MANAGER : 'MANAGER';
+MANDATORY : 'MANDATORY';
+MANUAL : 'MANUAL';
+MAP : 'MAP';
+MAPPING : 'MAPPING';
+MASTER : 'MASTER';
+MATCHED : 'MATCHED';
+MATCHES : 'MATCHES';
+MATCH : 'MATCH';
+MATCH_NUMBER : 'MATCH_NUMBER';
+MATCH_RECOGNIZE : 'MATCH_RECOGNIZE';
+MATERIALIZED : 'MATERIALIZED';
+MATERIALIZE : 'MATERIALIZE';
+MAXARCHLOGS : 'MAXARCHLOGS';
+MAXDATAFILES : 'MAXDATAFILES';
+MAXEXTENTS : 'MAXEXTENTS';
+MAXIMIZE : 'MAXIMIZE';
+MAXINSTANCES : 'MAXINSTANCES';
+MAXLOGFILES : 'MAXLOGFILES';
+MAXLOGHISTORY : 'MAXLOGHISTORY';
+MAXLOGMEMBERS : 'MAXLOGMEMBERS';
+MAX_SHARED_TEMP_SIZE : 'MAX_SHARED_TEMP_SIZE';
+MAXSIZE : 'MAXSIZE';
+MAXTRANS : 'MAXTRANS';
+MAXVALUE : 'MAXVALUE';
+MEASURE : 'MEASURE';
+MEASURES : 'MEASURES';
+MEDIUM : 'MEDIUM';
+MEMBER : 'MEMBER';
+MEMBER_CAPTION : 'MEMBER_CAPTION';
+MEMBER_DESCRIPTION : 'MEMBER_DESCRIPTION';
+MEMBER_NAME : 'MEMBER_NAME';
+MEMBER_UNIQUE_NAME : 'MEMBER_UNIQUE_NAME';
+MEMCOMPRESS : 'MEMCOMPRESS';
+MEMORY : 'MEMORY';
+MERGEACTIONS : 'MERGE$ACTIONS';
+MERGE_AJ : 'MERGE_AJ';
+MERGE_CONST_ON : 'MERGE_CONST_ON';
+MERGE : 'MERGE';
+MERGE_SJ : 'MERGE_SJ';
+METADATA : 'METADATA';
+METHOD : 'METHOD';
+MIGRATE : 'MIGRATE';
+MIGRATION : 'MIGRATION';
+MINEXTENTS : 'MINEXTENTS';
+MINIMIZE : 'MINIMIZE';
+MINIMUM : 'MINIMUM';
+MINING : 'MINING';
+MINUS : 'MINUS';
+MINUS_NULL : 'MINUS_NULL';
+MINUTE : 'MINUTE';
+MINUTES : 'MINUTES';
+MINVALUE : 'MINVALUE';
+MIRRORCOLD : 'MIRRORCOLD';
+MIRRORHOT : 'MIRRORHOT';
+MIRROR : 'MIRROR';
+MISSING : 'MISSING';
+MISMATCH : 'MISMATCH';
+MLSLABEL : 'MLSLABEL';
+MODEL_COMPILE_SUBQUERY : 'MODEL_COMPILE_SUBQUERY';
+MODEL_DONTVERIFY_UNIQUENESS : 'MODEL_DONTVERIFY_UNIQUENESS';
+MODEL_DYNAMIC_SUBQUERY : 'MODEL_DYNAMIC_SUBQUERY';
+MODEL_MIN_ANALYSIS : 'MODEL_MIN_ANALYSIS';
+MODEL : 'MODEL';
+MODEL_NB : 'MODEL_NB';
+MODEL_NO_ANALYSIS : 'MODEL_NO_ANALYSIS';
+MODEL_PBY : 'MODEL_PBY';
+MODEL_PUSH_REF : 'MODEL_PUSH_REF';
+MODEL_SV : 'MODEL_SV';
+MODE : 'MODE';
+MODIFICATION : 'MODIFICATION';
+MODIFY_COLUMN_TYPE : 'MODIFY_COLUMN_TYPE';
+MODIFY : 'MODIFY';
+MOD : 'MOD';
+MODULE : 'MODULE';
+MONITORING : 'MONITORING';
+MONITOR : 'MONITOR';
+MONTH : 'MONTH';
+MONTHS_BETWEEN : 'MONTHS_BETWEEN';
+MONTHS : 'MONTHS';
+MOUNT : 'MOUNT';
+MOUNTPATH : 'MOUNTPATH';
+MOUNTPOINT : 'MOUNTPOINT';
+MOVEMENT : 'MOVEMENT';
+MOVE : 'MOVE';
+MULTIDIMENSIONAL : 'MULTIDIMENSIONAL';
+MULTISET : 'MULTISET';
+MV_MERGE : 'MV_MERGE';
+NAMED : 'NAMED';
+NAME : 'NAME';
+NAMESPACE : 'NAMESPACE';
+NAN : 'NAN';
+NANVL : 'NANVL';
+NATIONAL : 'NATIONAL';
+NATIVE_FULL_OUTER_JOIN : 'NATIVE_FULL_OUTER_JOIN';
+NATIVE : 'NATIVE';
+NATURAL : 'NATURAL';
+NATURALN : 'NATURALN';
+NAV : 'NAV';
+NCHAR_CS : 'NCHAR_CS';
+NCHAR : 'NCHAR';
+NCHR : 'NCHR';
+NCLOB : 'NCLOB';
+NEEDED : 'NEEDED';
+NEG : 'NEG';
+NESTED : 'NESTED';
+NESTED_TABLE_FAST_INSERT : 'NESTED_TABLE_FAST_INSERT';
+NESTED_TABLE_GET_REFS : 'NESTED_TABLE_GET_REFS';
+NESTED_TABLE_ID : 'NESTED_TABLE_ID';
+NESTED_TABLE_SET_REFS : 'NESTED_TABLE_SET_REFS';
+NESTED_TABLE_SET_SETID : 'NESTED_TABLE_SET_SETID';
+NETWORK : 'NETWORK';
+NEVER : 'NEVER';
+NEW : 'NEW';
+NEW_TIME : 'NEW_TIME';
+NEXT_DAY : 'NEXT_DAY';
+NEXT : 'NEXT';
+NL_AJ : 'NL_AJ';
+NLJ_BATCHING : 'NLJ_BATCHING';
+NLJ_INDEX_FILTER : 'NLJ_INDEX_FILTER';
+NLJ_INDEX_SCAN : 'NLJ_INDEX_SCAN';
+NLJ_PREFETCH : 'NLJ_PREFETCH';
+NLS_CALENDAR : 'NLS_CALENDAR';
+NLS_CHARACTERSET : 'NLS_CHARACTERSET';
+NLS_CHARSET_DECL_LEN : 'NLS_CHARSET_DECL_LEN';
+NLS_CHARSET_ID : 'NLS_CHARSET_ID';
+NLS_CHARSET_NAME : 'NLS_CHARSET_NAME';
+NLS_COMP : 'NLS_COMP';
+NLS_CURRENCY : 'NLS_CURRENCY';
+NLS_DATE_FORMAT : 'NLS_DATE_FORMAT';
+NLS_DATE_LANGUAGE : 'NLS_DATE_LANGUAGE';
+NLS_INITCAP : 'NLS_INITCAP';
+NLS_ISO_CURRENCY : 'NLS_ISO_CURRENCY';
+NL_SJ : 'NL_SJ';
+NLS_LANG : 'NLS_LANG';
+NLS_LANGUAGE : 'NLS_LANGUAGE';
+NLS_LENGTH_SEMANTICS : 'NLS_LENGTH_SEMANTICS';
+NLS_LOWER : 'NLS_LOWER';
+NLS_NCHAR_CONV_EXCP : 'NLS_NCHAR_CONV_EXCP';
+NLS_NUMERIC_CHARACTERS : 'NLS_NUMERIC_CHARACTERS';
+NLS_SORT : 'NLS_SORT';
+NLSSORT : 'NLSSORT';
+NLS_SPECIAL_CHARS : 'NLS_SPECIAL_CHARS';
+NLS_TERRITORY : 'NLS_TERRITORY';
+NLS_UPPER : 'NLS_UPPER';
+NO_ACCESS : 'NO_ACCESS';
+NO_ADAPTIVE_PLAN : 'NO_ADAPTIVE_PLAN';
+NO_ANSI_REARCH : 'NO_ANSI_REARCH';
+NOAPPEND : 'NOAPPEND';
+NOARCHIVELOG : 'NOARCHIVELOG';
+NOAUDIT : 'NOAUDIT';
+NO_AUTO_REOPTIMIZE : 'NO_AUTO_REOPTIMIZE';
+NO_BASETABLE_MULTIMV_REWRITE : 'NO_BASETABLE_MULTIMV_REWRITE';
+NO_BATCH_TABLE_ACCESS_BY_ROWID : 'NO_BATCH_TABLE_ACCESS_BY_ROWID';
+NO_BIND_AWARE : 'NO_BIND_AWARE';
+NO_BUFFER : 'NO_BUFFER';
+NOCACHE : 'NOCACHE';
+NO_CARTESIAN : 'NO_CARTESIAN';
+NO_CHECK_ACL_REWRITE : 'NO_CHECK_ACL_REWRITE';
+NO_CLUSTER_BY_ROWID : 'NO_CLUSTER_BY_ROWID';
+NO_CLUSTERING : 'NO_CLUSTERING';
+NO_COALESCE_SQ : 'NO_COALESCE_SQ';
+NO_COMMON_DATA : 'NO_COMMON_DATA';
+NOCOMPRESS : 'NOCOMPRESS';
+NO_CONNECT_BY_CB_WHR_ONLY : 'NO_CONNECT_BY_CB_WHR_ONLY';
+NO_CONNECT_BY_COMBINE_SW : 'NO_CONNECT_BY_COMBINE_SW';
+NO_CONNECT_BY_COST_BASED : 'NO_CONNECT_BY_COST_BASED';
+NO_CONNECT_BY_ELIM_DUPS : 'NO_CONNECT_BY_ELIM_DUPS';
+NO_CONNECT_BY_FILTERING : 'NO_CONNECT_BY_FILTERING';
+NOCOPY : 'NOCOPY';
+NO_COST_XML_QUERY_REWRITE : 'NO_COST_XML_QUERY_REWRITE';
+NO_CPU_COSTING : 'NO_CPU_COSTING';
+NOCPU_COSTING : 'NOCPU_COSTING';
+NOCYCLE : 'NOCYCLE';
+NO_DATA_SECURITY_REWRITE : 'NO_DATA_SECURITY_REWRITE';
+NO_DECORRELATE : 'NO_DECORRELATE';
+NODELAY : 'NODELAY';
+NO_DOMAIN_INDEX_FILTER : 'NO_DOMAIN_INDEX_FILTER';
+NO_DST_UPGRADE_INSERT_CONV : 'NO_DST_UPGRADE_INSERT_CONV';
+NO_ELIM_GROUPBY : 'NO_ELIM_GROUPBY';
+NO_ELIMINATE_JOIN : 'NO_ELIMINATE_JOIN';
+NO_ELIMINATE_OBY : 'NO_ELIMINATE_OBY';
+NO_ELIMINATE_OUTER_JOIN : 'NO_ELIMINATE_OUTER_JOIN';
+NOENTITYESCAPING : 'NOENTITYESCAPING';
+NO_EXPAND_GSET_TO_UNION : 'NO_EXPAND_GSET_TO_UNION';
+NO_EXPAND : 'NO_EXPAND';
+NO_EXPAND_TABLE : 'NO_EXPAND_TABLE';
+NO_FACT : 'NO_FACT';
+NO_FACTORIZE_JOIN : 'NO_FACTORIZE_JOIN';
+NO_FILTERING : 'NO_FILTERING';
+NOFORCE : 'NOFORCE';
+NO_FULL_OUTER_JOIN_TO_OUTER : 'NO_FULL_OUTER_JOIN_TO_OUTER';
+NO_GATHER_OPTIMIZER_STATISTICS : 'NO_GATHER_OPTIMIZER_STATISTICS';
+NO_GBY_PUSHDOWN : 'NO_GBY_PUSHDOWN';
+NOGUARANTEE : 'NOGUARANTEE';
+NO_INDEX_FFS : 'NO_INDEX_FFS';
+NO_INDEX : 'NO_INDEX';
+NO_INDEX_SS : 'NO_INDEX_SS';
+NO_INMEMORY : 'NO_INMEMORY';
+NO_INMEMORY_PRUNING : 'NO_INMEMORY_PRUNING';
+NOKEEP : 'NOKEEP';
+NOSCALE : 'NOSCALE';
+NO_LOAD : 'NO_LOAD';
+NOLOCAL : 'NOLOCAL';
+NOLOGGING : 'NOLOGGING';
+NOMAPPING : 'NOMAPPING';
+NOMAXVALUE : 'NOMAXVALUE';
+NO_MERGE : 'NO_MERGE';
+NOMINIMIZE : 'NOMINIMIZE';
+NOMINVALUE : 'NOMINVALUE';
+NO_MODEL_PUSH_REF : 'NO_MODEL_PUSH_REF';
+NO_MONITORING : 'NO_MONITORING';
+NOMONITORING : 'NOMONITORING';
+NO_MONITOR : 'NO_MONITOR';
+NO_MULTIMV_REWRITE : 'NO_MULTIMV_REWRITE';
+NO_NATIVE_FULL_OUTER_JOIN : 'NO_NATIVE_FULL_OUTER_JOIN';
+NONBLOCKING : 'NONBLOCKING';
+NONEDITIONABLE : 'NONEDITIONABLE';
+NONE : 'NONE';
+NO_NLJ_BATCHING : 'NO_NLJ_BATCHING';
+NO_NLJ_PREFETCH : 'NO_NLJ_PREFETCH';
+NO : 'NO';
+NONSCHEMA : 'NONSCHEMA';
+NO_OBJECT_LINK : 'NO_OBJECT_LINK';
+NOORDER : 'NOORDER';
+NO_ORDER_ROLLUPS : 'NO_ORDER_ROLLUPS';
+NO_OUTER_JOIN_TO_ANTI : 'NO_OUTER_JOIN_TO_ANTI';
+NO_OUTER_JOIN_TO_INNER : 'NO_OUTER_JOIN_TO_INNER';
+NOOVERRIDE : 'NOOVERRIDE';
+NO_PARALLEL_INDEX : 'NO_PARALLEL_INDEX';
+NOPARALLEL_INDEX : 'NOPARALLEL_INDEX';
+NO_PARALLEL : 'NO_PARALLEL';
+NOPARALLEL : 'NOPARALLEL';
+NO_PARTIAL_COMMIT : 'NO_PARTIAL_COMMIT';
+NO_PARTIAL_JOIN : 'NO_PARTIAL_JOIN';
+NO_PARTIAL_ROLLUP_PUSHDOWN : 'NO_PARTIAL_ROLLUP_PUSHDOWN';
+NOPARTITION : 'NOPARTITION';
+NO_PLACE_DISTINCT : 'NO_PLACE_DISTINCT';
+NO_PLACE_GROUP_BY : 'NO_PLACE_GROUP_BY';
+NO_PQ_CONCURRENT_UNION : 'NO_PQ_CONCURRENT_UNION';
+NO_PQ_MAP : 'NO_PQ_MAP';
+NOPROMPT : 'NOPROMPT';
+NO_PQ_REPLICATE : 'NO_PQ_REPLICATE';
+NO_PQ_SKEW : 'NO_PQ_SKEW';
+NO_PRUNE_GSETS : 'NO_PRUNE_GSETS';
+NO_PULL_PRED : 'NO_PULL_PRED';
+NO_PUSH_PRED : 'NO_PUSH_PRED';
+NO_PUSH_SUBQ : 'NO_PUSH_SUBQ';
+NO_PX_FAULT_TOLERANCE : 'NO_PX_FAULT_TOLERANCE';
+NO_PX_JOIN_FILTER : 'NO_PX_JOIN_FILTER';
+NO_QKN_BUFF : 'NO_QKN_BUFF';
+NO_QUERY_TRANSFORMATION : 'NO_QUERY_TRANSFORMATION';
+NO_REF_CASCADE : 'NO_REF_CASCADE';
+NORELOCATE : 'NORELOCATE';
+NORELY : 'NORELY';
+NOREPAIR : 'NOREPAIR';
+NOREPLAY : 'NOREPLAY';
+NORESETLOGS : 'NORESETLOGS';
+NO_RESULT_CACHE : 'NO_RESULT_CACHE';
+NOREVERSE : 'NOREVERSE';
+NO_REWRITE : 'NO_REWRITE';
+NOREWRITE : 'NOREWRITE';
+NORMAL : 'NORMAL';
+NO_ROOT_SW_FOR_LOCAL : 'NO_ROOT_SW_FOR_LOCAL';
+NOROWDEPENDENCIES : 'NOROWDEPENDENCIES';
+NOSCHEMACHECK : 'NOSCHEMACHECK';
+NOSEGMENT : 'NOSEGMENT';
+NO_SEMIJOIN : 'NO_SEMIJOIN';
+NO_SEMI_TO_INNER : 'NO_SEMI_TO_INNER';
+NO_SET_TO_JOIN : 'NO_SET_TO_JOIN';
+NOSORT : 'NOSORT';
+NO_SQL_TRANSLATION : 'NO_SQL_TRANSLATION';
+NO_SQL_TUNE : 'NO_SQL_TUNE';
+NO_STAR_TRANSFORMATION : 'NO_STAR_TRANSFORMATION';
+NO_STATEMENT_QUEUING : 'NO_STATEMENT_QUEUING';
+NO_STATS_GSETS : 'NO_STATS_GSETS';
+NOSTRICT : 'NOSTRICT';
+NO_SUBQUERY_PRUNING : 'NO_SUBQUERY_PRUNING';
+NO_SUBSTRB_PAD : 'NO_SUBSTRB_PAD';
+NO_SWAP_JOIN_INPUTS : 'NO_SWAP_JOIN_INPUTS';
+NOSWITCH : 'NOSWITCH';
+NO_TABLE_LOOKUP_BY_NL : 'NO_TABLE_LOOKUP_BY_NL';
+NO_TEMP_TABLE : 'NO_TEMP_TABLE';
+NOTHING : 'NOTHING';
+NOTIFICATION : 'NOTIFICATION';
+NOT : 'NOT';
+NO_TRANSFORM_DISTINCT_AGG : 'NO_TRANSFORM_DISTINCT_AGG';
+NO_UNNEST : 'NO_UNNEST';
+NO_USE_CUBE : 'NO_USE_CUBE';
+NO_USE_HASH_AGGREGATION : 'NO_USE_HASH_AGGREGATION';
+NO_USE_HASH_GBY_FOR_PUSHDOWN : 'NO_USE_HASH_GBY_FOR_PUSHDOWN';
+NO_USE_HASH : 'NO_USE_HASH';
+NO_USE_INVISIBLE_INDEXES : 'NO_USE_INVISIBLE_INDEXES';
+NO_USE_MERGE : 'NO_USE_MERGE';
+NO_USE_NL : 'NO_USE_NL';
+NO_USE_VECTOR_AGGREGATION : 'NO_USE_VECTOR_AGGREGATION';
+NOVALIDATE : 'NOVALIDATE';
+NO_VECTOR_TRANSFORM_DIMS : 'NO_VECTOR_TRANSFORM_DIMS';
+NO_VECTOR_TRANSFORM_FACT : 'NO_VECTOR_TRANSFORM_FACT';
+NO_VECTOR_TRANSFORM : 'NO_VECTOR_TRANSFORM';
+NOWAIT : 'NOWAIT';
+NO_XDB_FASTPATH_INSERT : 'NO_XDB_FASTPATH_INSERT';
+NO_XML_DML_REWRITE : 'NO_XML_DML_REWRITE';
+NO_XMLINDEX_REWRITE_IN_SELECT : 'NO_XMLINDEX_REWRITE_IN_SELECT';
+NO_XMLINDEX_REWRITE : 'NO_XMLINDEX_REWRITE';
+NO_XML_QUERY_REWRITE : 'NO_XML_QUERY_REWRITE';
+NO_ZONEMAP : 'NO_ZONEMAP';
+NTH_VALUE : 'NTH_VALUE';
+NULLIF : 'NULLIF';
+NULL_ : 'NULL';
+NULLS : 'NULLS';
+NUMBER : 'NUMBER';
+NUMERIC : 'NUMERIC';
+NUM_INDEX_KEYS : 'NUM_INDEX_KEYS';
+NUMTODSINTERVAL : 'NUMTODSINTERVAL';
+NUMTOYMINTERVAL : 'NUMTOYMINTERVAL';
+NVARCHAR2 : 'NVARCHAR2';
+NVL2 : 'NVL2';
+OBJECT2XML : 'OBJECT2XML';
+OBJECT : 'OBJECT';
+OBJ_ID : 'OBJ_ID';
+OBJNO : 'OBJNO';
+OBJNO_REUSE : 'OBJNO_REUSE';
+OCCURENCES : 'OCCURENCES';
+OFFLINE : 'OFFLINE';
+OFF : 'OFF';
+OFFSET : 'OFFSET';
+OF : 'OF';
+OIDINDEX : 'OIDINDEX';
+OID : 'OID';
+OLAP : 'OLAP';
+OLD : 'OLD';
+OLD_PUSH_PRED : 'OLD_PUSH_PRED';
+OLS : 'OLS';
+OLTP : 'OLTP';
+OMIT : 'OMIT';
+ONE : 'ONE';
+ONLINE : 'ONLINE';
+ONLINELOG : 'ONLINELOG';
+ONLY : 'ONLY';
+ON : 'ON';
+OPAQUE : 'OPAQUE';
+OPAQUE_TRANSFORM : 'OPAQUE_TRANSFORM';
+OPAQUE_XCANONICAL : 'OPAQUE_XCANONICAL';
+OPCODE : 'OPCODE';
+OPEN : 'OPEN';
+OPERATIONS : 'OPERATIONS';
+OPERATOR : 'OPERATOR';
+OPT_ESTIMATE : 'OPT_ESTIMATE';
+OPTIMAL : 'OPTIMAL';
+OPTIMIZE : 'OPTIMIZE';
+OPTIMIZER_FEATURES_ENABLE : 'OPTIMIZER_FEATURES_ENABLE';
+OPTIMIZER_GOAL : 'OPTIMIZER_GOAL';
+OPTION : 'OPTION';
+OPT_PARAM : 'OPT_PARAM';
+ORA_BRANCH : 'ORA_BRANCH';
+ORA_CHECK_ACL : 'ORA_CHECK_ACL';
+ORA_CHECK_PRIVILEGE : 'ORA_CHECK_PRIVILEGE';
+ORA_CLUSTERING : 'ORA_CLUSTERING';
+ORADATA : 'ORADATA';
+ORADEBUG : 'ORADEBUG';
+ORA_DST_AFFECTED : 'ORA_DST_AFFECTED';
+ORA_DST_CONVERT : 'ORA_DST_CONVERT';
+ORA_DST_ERROR : 'ORA_DST_ERROR';
+ORA_GET_ACLIDS : 'ORA_GET_ACLIDS';
+ORA_GET_PRIVILEGES : 'ORA_GET_PRIVILEGES';
+ORA_HASH : 'ORA_HASH';
+ORA_INVOKING_USERID : 'ORA_INVOKING_USERID';
+ORA_INVOKING_USER : 'ORA_INVOKING_USER';
+ORA_INVOKING_XS_USER_GUID : 'ORA_INVOKING_XS_USER_GUID';
+ORA_INVOKING_XS_USER : 'ORA_INVOKING_XS_USER';
+ORA_RAWCOMPARE : 'ORA_RAWCOMPARE';
+ORA_RAWCONCAT : 'ORA_RAWCONCAT';
+ORA_ROWSCN : 'ORA_ROWSCN';
+ORA_ROWSCN_RAW : 'ORA_ROWSCN_RAW';
+ORA_ROWVERSION : 'ORA_ROWVERSION';
+ORA_TABVERSION : 'ORA_TABVERSION';
+ORA_WRITE_TIME : 'ORA_WRITE_TIME';
+ORDERED : 'ORDERED';
+ORDERED_PREDICATES : 'ORDERED_PREDICATES';
+ORDER : 'ORDER';
+ORDINALITY : 'ORDINALITY';
+OR_EXPAND : 'OR_EXPAND';
+ORGANIZATION : 'ORGANIZATION';
+OR : 'OR';
+OR_PREDICATES : 'OR_PREDICATES';
+OSERROR : 'OSERROR';
+OTHER : 'OTHER';
+OUTER_JOIN_TO_ANTI : 'OUTER_JOIN_TO_ANTI';
+OUTER_JOIN_TO_INNER : 'OUTER_JOIN_TO_INNER';
+OUTER : 'OUTER';
+OUTLINE_LEAF : 'OUTLINE_LEAF';
+OUTLINE : 'OUTLINE';
+OUT_OF_LINE : 'OUT_OF_LINE';
+OUT : 'OUT';
+OVERFLOW_NOMOVE : 'OVERFLOW_NOMOVE';
+OVERFLOW : 'OVERFLOW';
+OVERLAPS : 'OVERLAPS';
+OVER : 'OVER';
+OVERRIDING : 'OVERRIDING';
+OWNER : 'OWNER';
+OWNERSHIP : 'OWNERSHIP';
+OWN : 'OWN';
+P_LETTER : 'P';
+PACKAGE : 'PACKAGE';
+PACKAGES : 'PACKAGES';
+PARALLEL_ENABLE : 'PARALLEL_ENABLE';
+PARALLEL_INDEX : 'PARALLEL_INDEX';
+PARALLEL : 'PARALLEL';
+PARAMETERFILE : 'PARAMETERFILE';
+PARAMETERS : 'PARAMETERS';
+PARAM : 'PARAM';
+PARENT : 'PARENT';
+PARENT_LEVEL_NAME : 'PARENT_LEVEL_NAME';
+PARENT_UNIQUE_NAME : 'PARENT_UNIQUE_NAME';
+PARITY : 'PARITY';
+PARTIAL_JOIN : 'PARTIAL_JOIN';
+PARTIALLY : 'PARTIALLY';
+PARTIAL : 'PARTIAL';
+PARTIAL_ROLLUP_PUSHDOWN : 'PARTIAL_ROLLUP_PUSHDOWN';
+PARTITION_HASH : 'PARTITION_HASH';
+PARTITION_LIST : 'PARTITION_LIST';
+PARTITION : 'PARTITION';
+PARTITION_RANGE : 'PARTITION_RANGE';
+PARTITIONS : 'PARTITIONS';
+PARTNUMINST : 'PART$NUM$INST';
+PASSING : 'PASSING';
+PASSWORD_GRACE_TIME : 'PASSWORD_GRACE_TIME';
+PASSWORD_LIFE_TIME : 'PASSWORD_LIFE_TIME';
+PASSWORD_LOCK_TIME : 'PASSWORD_LOCK_TIME';
+PASSWORD : 'PASSWORD';
+PASSWORD_REUSE_MAX : 'PASSWORD_REUSE_MAX';
+PASSWORD_REUSE_TIME : 'PASSWORD_REUSE_TIME';
+PASSWORD_ROLLOVER_TIME : 'PASSWORD_ROLLOVER_TIME';
+PASSWORD_VERIFY_FUNCTION : 'PASSWORD_VERIFY_FUNCTION';
+PAST : 'PAST';
+PATCH : 'PATCH';
+PATH : 'PATH';
+PATH_PREFIX : 'PATH_PREFIX';
+PATHS : 'PATHS';
+PATTERN : 'PATTERN';
+PBL_HS_BEGIN : 'PBL_HS_BEGIN';
+PBL_HS_END : 'PBL_HS_END';
+PCTFREE : 'PCTFREE';
+PCTINCREASE : 'PCTINCREASE';
+PCTTHRESHOLD : 'PCTTHRESHOLD';
+PCTUSED : 'PCTUSED';
+PCTVERSION : 'PCTVERSION';
+PENDING : 'PENDING';
+PERCENT_FOUND : '%' SPACE* 'FOUND';
+PERCENT_ISOPEN : '%' SPACE* 'ISOPEN';
+PERCENT_NOTFOUND : '%' SPACE* 'NOTFOUND';
+PERCENT_KEYWORD : 'PERCENT';
+PERCENT_RANKM : 'PERCENT_RANKM';
+PERCENT_ROWCOUNT : '%' SPACE* 'ROWCOUNT';
+PERCENT_ROWTYPE : '%' SPACE* 'ROWTYPE';
+PERCENT_TYPE : '%' SPACE* 'TYPE';
+PERCENT_BULK_EXCEPTIONS : '%' SPACE* 'BULK_EXCEPTIONS';
+PERCENT_BULK_ROWCOUNT : '%' SPACE* 'BULK_ROWCOUNT';
+PERFORMANCE : 'PERFORMANCE';
+PERIOD_KEYWORD : 'PERIOD';
+PERMANENT : 'PERMANENT';
+PERMISSION : 'PERMISSION';
+PERMUTE : 'PERMUTE';
+PER : 'PER';
+PFILE : 'PFILE';
+PHYSICAL : 'PHYSICAL';
+PIKEY : 'PIKEY';
+PIPELINED : 'PIPELINED';
+PIPE : 'PIPE';
+PIV_GB : 'PIV_GB';
+PIVOT : 'PIVOT';
+PIV_SSF : 'PIV_SSF';
+PLACE_DISTINCT : 'PLACE_DISTINCT';
+PLACE_GROUP_BY : 'PLACE_GROUP_BY';
+PLAN : 'PLAN';
+PLSCOPE_SETTINGS : 'PLSCOPE_SETTINGS';
+PLS_INTEGER : 'PLS_INTEGER';
+PLSQL_CCFLAGS : 'PLSQL_CCFLAGS';
+PLSQL_CODE_TYPE : 'PLSQL_CODE_TYPE';
+PLSQL_DEBUG : 'PLSQL_DEBUG';
+PLSQL_OPTIMIZE_LEVEL : 'PLSQL_OPTIMIZE_LEVEL';
+PLSQL_WARNINGS : 'PLSQL_WARNINGS';
+PLUGGABLE : 'PLUGGABLE';
+PMEM : 'PMEM';
+POINT : 'POINT';
+POLICY : 'POLICY';
+POOL_16K : 'POOL_16K';
+POOL_2K : 'POOL_2K';
+POOL_32K : 'POOL_32K';
+POOL_4K : 'POOL_4K';
+POOL_8K : 'POOL_8K';
+POSITIVEN : 'POSITIVEN';
+POSITIVE : 'POSITIVE';
+POST_TRANSACTION : 'POST_TRANSACTION';
+POWERMULTISET_BY_CARDINALITY : 'POWERMULTISET_BY_CARDINALITY';
+POWERMULTISET : 'POWERMULTISET';
+POWER : 'POWER';
+PQ_CONCURRENT_UNION : 'PQ_CONCURRENT_UNION';
+PQ_DISTRIBUTE : 'PQ_DISTRIBUTE';
+PQ_DISTRIBUTE_WINDOW : 'PQ_DISTRIBUTE_WINDOW';
+PQ_FILTER : 'PQ_FILTER';
+PQ_MAP : 'PQ_MAP';
+PQ_NOMAP : 'PQ_NOMAP';
+PQ_REPLICATE : 'PQ_REPLICATE';
+PQ_SKEW : 'PQ_SKEW';
+PRAGMA : 'PRAGMA';
+PREBUILT : 'PREBUILT';
+PRECEDES : 'PRECEDES';
+PRECEDING : 'PRECEDING';
+PRECISION : 'PRECISION';
+PRECOMPUTE_SUBQUERY : 'PRECOMPUTE_SUBQUERY';
+PREDICATE_REORDERS : 'PREDICATE_REORDERS';
+PRELOAD : 'PRELOAD';
+PREPARE : 'PREPARE';
+PRESENTNNV : 'PRESENTNNV';
+PRESENT : 'PRESENT';
+PRESENTV : 'PRESENTV';
+PRESERVE_OID : 'PRESERVE_OID';
+PRESERVE : 'PRESERVE';
+PRETTY : 'PRETTY';
+PREVIOUS : 'PREVIOUS';
+PREV : 'PREV';
+PRIMARY : 'PRIMARY';
+PRINTBLOBTOCLOB : 'PRINTBLOBTOCLOB';
+PRIORITY : 'PRIORITY';
+PRIOR : 'PRIOR';
+PRIVATE : 'PRIVATE';
+PRIVATE_SGA : 'PRIVATE_SGA';
+PRIVILEGED : 'PRIVILEGED';
+PRIVILEGE : 'PRIVILEGE';
+PRIVILEGES : 'PRIVILEGES';
+PROCEDURAL : 'PROCEDURAL';
+PROCEDURE : 'PROCEDURE';
+PROCESS : 'PROCESS';
+PROFILE : 'PROFILE';
+PROGRAM : 'PROGRAM';
+PROJECT : 'PROJECT';
+PROPAGATE : 'PROPAGATE';
+PROPERTY : 'PROPERTY';
+PROTECTED : 'PROTECTED';
+PROTECTION : 'PROTECTION';
+PROTOCOL : 'PROTOCOL';
+PROXY : 'PROXY';
+PRUNING : 'PRUNING';
+PUBLIC : 'PUBLIC';
+PULL_PRED : 'PULL_PRED';
+PURGE : 'PURGE';
+PUSH_PRED : 'PUSH_PRED';
+PUSH_SUBQ : 'PUSH_SUBQ';
+PX_FAULT_TOLERANCE : 'PX_FAULT_TOLERANCE';
+PX_GRANULE : 'PX_GRANULE';
+PX_JOIN_FILTER : 'PX_JOIN_FILTER';
+QB_NAME : 'QB_NAME';
+QUARTERS : 'QUARTERS';
+QUERY_BLOCK : 'QUERY_BLOCK';
+QUERY : 'QUERY';
+QUEUE_CURR : 'QUEUE_CURR';
+QUEUE : 'QUEUE';
+QUEUE_ROWP : 'QUEUE_ROWP';
+QUIESCE : 'QUIESCE';
+QUORUM : 'QUORUM';
+QUOTA : 'QUOTA';
+QUOTAGROUP : 'QUOTAGROUP';
+RAISE : 'RAISE';
+RANDOM_LOCAL : 'RANDOM_LOCAL';
+RANDOM : 'RANDOM';
+RANGE : 'RANGE';
+RANKM : 'RANKM';
+RAPIDLY : 'RAPIDLY';
+RAW : 'RAW';
+RAWTOHEX : 'RAWTOHEX';
+RAWTONHEX : 'RAWTONHEX';
+RBA : 'RBA';
+RBO_OUTLINE : 'RBO_OUTLINE';
+RDBA : 'RDBA';
+READ : 'READ';
+READS : 'READS';
+REALM : 'REALM';
+REAL : 'REAL';
+REBALANCE : 'REBALANCE';
+REBUILD : 'REBUILD';
+RECORD : 'RECORD';
+RECORDS_PER_BLOCK : 'RECORDS_PER_BLOCK';
+RECOVERABLE : 'RECOVERABLE';
+RECOVER : 'RECOVER';
+RECOVERY : 'RECOVERY';
+RECYCLEBIN : 'RECYCLEBIN';
+RECYCLE : 'RECYCLE';
+REDACTION : 'REDACTION';
+REDEFINE : 'REDEFINE';
+REDO : 'REDO';
+REDUCED : 'REDUCED';
+REDUNDANCY : 'REDUNDANCY';
+REF_CASCADE_CURSOR : 'REF_CASCADE_CURSOR';
+REFERENCED : 'REFERENCED';
+REFERENCE : 'REFERENCE';
+REFERENCES : 'REFERENCES';
+REFERENCING : 'REFERENCING';
+REF : 'REF';
+REFRESH : 'REFRESH';
+REFTOHEX : 'REFTOHEX';
+REGEXP_COUNT : 'REGEXP_COUNT';
+REGEXP_INSTR : 'REGEXP_INSTR';
+REGEXP_LIKE : 'REGEXP_LIKE';
+REGEXP_REPLACE : 'REGEXP_REPLACE';
+REGEXP_SUBSTR : 'REGEXP_SUBSTR';
+REGISTER : 'REGISTER';
+REGR_AVGX : 'REGR_AVGX';
+REGR_AVGY : 'REGR_AVGY';
+REGR_COUNT : 'REGR_COUNT';
+REGR_INTERCEPT : 'REGR_INTERCEPT';
+REGR_R2 : 'REGR_R2';
+REGR_SLOPE : 'REGR_SLOPE';
+REGR_SXX : 'REGR_SXX';
+REGR_SXY : 'REGR_SXY';
+REGR_SYY : 'REGR_SYY';
+REGULAR : 'REGULAR';
+REJECT : 'REJECT';
+REKEY : 'REKEY';
+RELATIONAL : 'RELATIONAL';
+RELIES_ON : 'RELIES_ON';
+RELOCATE : 'RELOCATE';
+RELY : 'RELY';
+REMAINDER : 'REMAINDER';
+REMOTE : 'REMOTE';
+REMOTE_MAPPED : 'REMOTE_MAPPED';
+REMOVE : 'REMOVE';
+RENAME : 'RENAME';
+REPAIR : 'REPAIR';
+REPEAT : 'REPEAT';
+REPLACE : 'REPLACE';
+REPLICATION : 'REPLICATION';
+REQUIRED : 'REQUIRED';
+RESETLOGS : 'RESETLOGS';
+RESET : 'RESET';
+RESIZE : 'RESIZE';
+RESOLVE : 'RESOLVE';
+RESOLVER : 'RESOLVER';
+RESOURCE : 'RESOURCE';
+RESPECT : 'RESPECT';
+RESTART : 'RESTART';
+RESTORE_AS_INTERVALS : 'RESTORE_AS_INTERVALS';
+RESTORE : 'RESTORE';
+RESTRICT_ALL_REF_CONS : 'RESTRICT_ALL_REF_CONS';
+RESTRICTED : 'RESTRICTED';
+RESTRICT_REFERENCES : 'RESTRICT_REFERENCES';
+RESTRICT : 'RESTRICT';
+RESULT_CACHE : 'RESULT_CACHE';
+RESULT : 'RESULT';
+RESUMABLE : 'RESUMABLE';
+RESUME : 'RESUME';
+RETENTION : 'RETENTION';
+RETRY_ON_ROW_CHANGE : 'RETRY_ON_ROW_CHANGE';
+RETURNING : 'RETURNING';
+RETURN : 'RETURN';
+REUSE : 'REUSE';
+REVERSE : 'REVERSE';
+REVOKE : 'REVOKE';
+REWRITE_OR_ERROR : 'REWRITE_OR_ERROR';
+REWRITE : 'REWRITE';
+RIGHT : 'RIGHT';
+ROLE : 'ROLE';
+ROLESET : 'ROLESET';
+ROLES : 'ROLES';
+ROLLBACK : 'ROLLBACK';
+ROLLING : 'ROLLING';
+ROLLUP : 'ROLLUP';
+ROWDEPENDENCIES : 'ROWDEPENDENCIES';
+ROWID_MAPPING_TABLE : 'ROWID_MAPPING_TABLE';
+ROWID : 'ROWID';
+ROWIDTOCHAR : 'ROWIDTOCHAR';
+ROWIDTONCHAR : 'ROWIDTONCHAR';
+ROW_LENGTH : 'ROW_LENGTH';
+ROWNUM : 'ROWNUM';
+ROW : 'ROW';
+ROWS : 'ROWS';
+RPAD : 'RPAD';
+RTRIM : 'RTRIM';
+RULE : 'RULE';
+RULES : 'RULES';
+RUNNING : 'RUNNING';
+SALT : 'SALT';
+SAMPLE : 'SAMPLE';
+SAVE_AS_INTERVALS : 'SAVE_AS_INTERVALS';
+SAVEPOINT : 'SAVEPOINT';
+SAVE : 'SAVE';
+SB4 : 'SB4';
+SCALE_ROWS : 'SCALE_ROWS';
+SCALE : 'SCALE';
+SCAN_INSTANCES : 'SCAN_INSTANCES';
+SCAN : 'SCAN';
+SCHEDULER : 'SCHEDULER';
+SCHEMACHECK : 'SCHEMACHECK';
+SCHEMA : 'SCHEMA';
+SCN_ASCENDING : 'SCN_ASCENDING';
+SCN : 'SCN';
+SCOPE : 'SCOPE';
+SCRUB : 'SCRUB';
+SD_ALL : 'SD_ALL';
+SD_INHIBIT : 'SD_INHIBIT';
+SDO_GEOM_MBR : 'SDO_GEOM_MBR';
+SDO_GEOMETRY : 'SDO_GEOMETRY';
+SD_SHOW : 'SD_SHOW';
+SEARCH : 'SEARCH';
+SECOND : 'SECOND';
+SECONDS : 'SECONDS';
+SECRET : 'SECRET';
+SECUREFILE_DBA : 'SECUREFILE_DBA';
+SECUREFILE : 'SECUREFILE';
+SECURITY : 'SECURITY';
+SEED : 'SEED';
+SEG_BLOCK : 'SEG_BLOCK';
+SEG_FILE : 'SEG_FILE';
+SEGMENT : 'SEGMENT';
+SELECTIVITY : 'SELECTIVITY';
+SELECT : 'SELECT';
+SELF : 'SELF';
+SEMIJOIN_DRIVER : 'SEMIJOIN_DRIVER';
+SEMIJOIN : 'SEMIJOIN';
+SEMI_TO_INNER : 'SEMI_TO_INNER';
+SEQUENCED : 'SEQUENCED';
+SEQUENCE : 'SEQUENCE';
+SEQUENTIAL : 'SEQUENTIAL';
+SEQ : 'SEQ';
+SERIALIZABLE : 'SERIALIZABLE';
+SERIALLY_REUSABLE : 'SERIALLY_REUSABLE';
+SERIAL : 'SERIAL';
+SERVERERROR : 'SERVERERROR';
+SERVICE_NAME_CONVERT : 'SERVICE_NAME_CONVERT';
+SERVICE : 'SERVICE';
+SERVICES : 'SERVICES';
+SESSION_CACHED_CURSORS : 'SESSION_CACHED_CURSORS';
+SESSION : 'SESSION';
+SESSIONS_PER_USER : 'SESSIONS_PER_USER';
+SESSIONTIMEZONE : 'SESSIONTIMEZONE';
+SESSIONTZNAME : 'SESSIONTZNAME';
+SET : 'SET';
+SETS : 'SETS';
+SETTINGS : 'SETTINGS';
+SET_TO_JOIN : 'SET_TO_JOIN';
+SEVERE : 'SEVERE';
+SHARDSPACE : 'SHARDSPACE';
+SHARED_POOL : 'SHARED_POOL';
+SHARED : 'SHARED';
+SHARE : 'SHARE';
+SHARING : 'SHARING';
+SHELFLIFE : 'SHELFLIFE';
+SHOW : 'SHOW';
+SHRINK : 'SHRINK';
+SHUTDOWN : 'SHUTDOWN';
+SIBLINGS : 'SIBLINGS';
+SID : 'SID';
+SITE : 'SITE';
+SIGNAL_COMPONENT : 'SIGNAL_COMPONENT';
+SIGNAL_FUNCTION : 'SIGNAL_FUNCTION';
+SIGN : 'SIGN';
+SIGNTYPE : 'SIGNTYPE';
+SIMPLE_INTEGER : 'SIMPLE_INTEGER';
+SIMPLE : 'SIMPLE';
+SINGLE : 'SINGLE';
+SINGLETASK : 'SINGLETASK';
+SINH : 'SINH';
+SIN : 'SIN';
+SIZE : 'SIZE';
+SKIP_EXT_OPTIMIZER : 'SKIP_EXT_OPTIMIZER';
+SKIP_ : 'SKIP';
+SKIP_UNQ_UNUSABLE_IDX : 'SKIP_UNQ_UNUSABLE_IDX';
+SKIP_UNUSABLE_INDEXES : 'SKIP_UNUSABLE_INDEXES';
+SMALLFILE : 'SMALLFILE';
+SMALLINT : 'SMALLINT';
+SNAPSHOT : 'SNAPSHOT';
+SOME : 'SOME';
+SORT : 'SORT';
+SOUNDEX : 'SOUNDEX';
+SOURCE_FILE_DIRECTORY : 'SOURCE_FILE_DIRECTORY';
+SOURCE_FILE_NAME_CONVERT : 'SOURCE_FILE_NAME_CONVERT';
+SOURCE : 'SOURCE';
+SPACE_KEYWORD : 'SPACE';
+SPECIFICATION : 'SPECIFICATION';
+SPFILE : 'SPFILE';
+SPLIT : 'SPLIT';
+SPREADSHEET : 'SPREADSHEET';
+SQLDATA : 'SQLDATA';
+SQLERROR : 'SQLERROR';
+SQLLDR : 'SQLLDR';
+SQL : 'SQL';
+FILE_EXT : 'PKB' | 'PKS';
+SQL_MACRO : 'SQL_MACRO';
+SQL_TRACE : 'SQL_TRACE';
+SQL_TRANSLATION_PROFILE : 'SQL_TRANSLATION_PROFILE';
+SQRT : 'SQRT';
+STALE : 'STALE';
+STANDALONE : 'STANDALONE';
+STANDARD : 'STANDARD';
+STANDARD_HASH : 'STANDARD_HASH';
+STANDBY_MAX_DATA_DELAY : 'STANDBY_MAX_DATA_DELAY';
+STANDBYS : 'STANDBYS';
+STANDBY : 'STANDBY';
+STAR : 'STAR';
+STAR_TRANSFORMATION : 'STAR_TRANSFORMATION';
+START : 'START';
+STARTUP : 'STARTUP';
+STATEMENT_ID : 'STATEMENT_ID';
+STATEMENT_QUEUING : 'STATEMENT_QUEUING';
+STATEMENTS : 'STATEMENTS';
+STATEMENT : 'STATEMENT';
+STATE : 'STATE';
+STATIC : 'STATIC';
+STATISTICS : 'STATISTICS';
+STATS_BINOMIAL_TEST : 'STATS_BINOMIAL_TEST';
+STATS_CROSSTAB : 'STATS_CROSSTAB';
+STATS_F_TEST : 'STATS_F_TEST';
+STATS_KS_TEST : 'STATS_KS_TEST';
+STATS_MODE : 'STATS_MODE';
+STATS_MW_TEST : 'STATS_MW_TEST';
+STATS_ONE_WAY_ANOVA : 'STATS_ONE_WAY_ANOVA';
+STATS_T_TEST_INDEP : 'STATS_T_TEST_INDEP';
+STATS_T_TEST_INDEPU : 'STATS_T_TEST_INDEPU';
+STATS_T_TEST_ONE : 'STATS_T_TEST_ONE';
+STATS_T_TEST_PAIRED : 'STATS_T_TEST_PAIRED';
+STATS_WSR_TEST : 'STATS_WSR_TEST';
+STDDEV_POP : 'STDDEV_POP';
+STDDEV_SAMP : 'STDDEV_SAMP';
+STOP : 'STOP';
+STORAGE : 'STORAGE';
+STORE : 'STORE';
+STREAMS : 'STREAMS';
+STREAM : 'STREAM';
+STRICT : 'STRICT';
+STRING : 'STRING';
+STRIPE_COLUMNS : 'STRIPE_COLUMNS';
+STRIPE_WIDTH : 'STRIPE_WIDTH';
+STRIP : 'STRIP';
+STRUCTURE : 'STRUCTURE';
+SUBMULTISET : 'SUBMULTISET';
+SUBPARTITION_REL : 'SUBPARTITION_REL';
+SUBPARTITIONS : 'SUBPARTITIONS';
+SUBPARTITION : 'SUBPARTITION';
+SUBQUERIES : 'SUBQUERIES';
+SUBQUERY_PRUNING : 'SUBQUERY_PRUNING';
+SUBSCRIBE : 'SUBSCRIBE';
+SUBSET : 'SUBSET';
+SUBSTITUTABLE : 'SUBSTITUTABLE';
+SUBSTR2 : 'SUBSTR2';
+SUBSTR4 : 'SUBSTR4';
+SUBSTRB : 'SUBSTRB';
+SUBSTRC : 'SUBSTRC';
+SUBTYPE : 'SUBTYPE';
+SUCCESSFUL : 'SUCCESSFUL';
+SUCCESS : 'SUCCESS';
+SUMMARY : 'SUMMARY';
+SUPPLEMENTAL : 'SUPPLEMENTAL';
+SUSPEND : 'SUSPEND';
+SWAP_JOIN_INPUTS : 'SWAP_JOIN_INPUTS';
+SWITCHOVER : 'SWITCHOVER';
+SWITCH : 'SWITCH';
+SYNCHRONOUS : 'SYNCHRONOUS';
+SYNC : 'SYNC';
+SYNONYM : 'SYNONYM';
+SYS : 'SYS';
+SYSASM : 'SYSASM';
+SYS_AUDIT : 'SYS_AUDIT';
+SYSAUX : 'SYSAUX';
+SYSBACKUP : 'SYSBACKUP';
+SYS_CHECKACL : 'SYS_CHECKACL';
+SYS_CHECK_PRIVILEGE : 'SYS_CHECK_PRIVILEGE';
+SYS_CONNECT_BY_PATH : 'SYS_CONNECT_BY_PATH';
+SYS_CONTEXT : 'SYS_CONTEXT';
+SYSDATE : 'SYSDATE';
+SYSDBA : 'SYSDBA';
+SYS_DBURIGEN : 'SYS_DBURIGEN';
+SYSDG : 'SYSDG';
+SYS_DL_CURSOR : 'SYS_DL_CURSOR';
+SYS_DM_RXFORM_CHR : 'SYS_DM_RXFORM_CHR';
+SYS_DM_RXFORM_NUM : 'SYS_DM_RXFORM_NUM';
+SYS_DOM_COMPARE : 'SYS_DOM_COMPARE';
+SYS_DST_PRIM2SEC : 'SYS_DST_PRIM2SEC';
+SYS_DST_SEC2PRIM : 'SYS_DST_SEC2PRIM';
+SYS_ET_BFILE_TO_RAW : 'SYS_ET_BFILE_TO_RAW';
+SYS_ET_BLOB_TO_IMAGE : 'SYS_ET_BLOB_TO_IMAGE';
+SYS_ET_IMAGE_TO_BLOB : 'SYS_ET_IMAGE_TO_BLOB';
+SYS_ET_RAW_TO_BFILE : 'SYS_ET_RAW_TO_BFILE';
+SYS_EXTPDTXT : 'SYS_EXTPDTXT';
+SYS_EXTRACT_UTC : 'SYS_EXTRACT_UTC';
+SYS_FBT_INSDEL : 'SYS_FBT_INSDEL';
+SYS_FILTER_ACLS : 'SYS_FILTER_ACLS';
+SYS_FNMATCHES : 'SYS_FNMATCHES';
+SYS_FNREPLACE : 'SYS_FNREPLACE';
+SYS_GET_ACLIDS : 'SYS_GET_ACLIDS';
+SYS_GET_COL_ACLIDS : 'SYS_GET_COL_ACLIDS';
+SYS_GET_PRIVILEGES : 'SYS_GET_PRIVILEGES';
+SYS_GETTOKENID : 'SYS_GETTOKENID';
+SYS_GETXTIVAL : 'SYS_GETXTIVAL';
+SYS_GUID : 'SYS_GUID';
+SYSGUID : 'SYSGUID';
+SYSKM : 'SYSKM';
+SYS_MAKE_XMLNODEID : 'SYS_MAKE_XMLNODEID';
+SYS_MAKEXML : 'SYS_MAKEXML';
+SYS_MKXMLATTR : 'SYS_MKXMLATTR';
+SYS_MKXTI : 'SYS_MKXTI';
+SYSOBJ : 'SYSOBJ';
+SYS_OP_ADT2BIN : 'SYS_OP_ADT2BIN';
+SYS_OP_ADTCONS : 'SYS_OP_ADTCONS';
+SYS_OP_ALSCRVAL : 'SYS_OP_ALSCRVAL';
+SYS_OP_ATG : 'SYS_OP_ATG';
+SYS_OP_BIN2ADT : 'SYS_OP_BIN2ADT';
+SYS_OP_BITVEC : 'SYS_OP_BITVEC';
+SYS_OP_BL2R : 'SYS_OP_BL2R';
+SYS_OP_BLOOM_FILTER_LIST : 'SYS_OP_BLOOM_FILTER_LIST';
+SYS_OP_BLOOM_FILTER : 'SYS_OP_BLOOM_FILTER';
+SYS_OP_C2C : 'SYS_OP_C2C';
+SYS_OP_CAST : 'SYS_OP_CAST';
+SYS_OP_CEG : 'SYS_OP_CEG';
+SYS_OP_CL2C : 'SYS_OP_CL2C';
+SYS_OP_COMBINED_HASH : 'SYS_OP_COMBINED_HASH';
+SYS_OP_COMP : 'SYS_OP_COMP';
+SYS_OP_CONVERT : 'SYS_OP_CONVERT';
+SYS_OP_COUNTCHG : 'SYS_OP_COUNTCHG';
+SYS_OP_CSCONV : 'SYS_OP_CSCONV';
+SYS_OP_CSCONVTEST : 'SYS_OP_CSCONVTEST';
+SYS_OP_CSR : 'SYS_OP_CSR';
+SYS_OP_CSX_PATCH : 'SYS_OP_CSX_PATCH';
+SYS_OP_CYCLED_SEQ : 'SYS_OP_CYCLED_SEQ';
+SYS_OP_DECOMP : 'SYS_OP_DECOMP';
+SYS_OP_DESCEND : 'SYS_OP_DESCEND';
+SYS_OP_DISTINCT : 'SYS_OP_DISTINCT';
+SYS_OP_DRA : 'SYS_OP_DRA';
+SYS_OP_DUMP : 'SYS_OP_DUMP';
+SYS_OP_DV_CHECK : 'SYS_OP_DV_CHECK';
+SYS_OP_ENFORCE_NOT_NULL : 'SYS_OP_ENFORCE_NOT_NULL$';
+SYSOPER : 'SYSOPER';
+SYS_OP_EXTRACT : 'SYS_OP_EXTRACT';
+SYS_OP_GROUPING : 'SYS_OP_GROUPING';
+SYS_OP_GUID : 'SYS_OP_GUID';
+SYS_OP_HASH : 'SYS_OP_HASH';
+SYS_OP_IIX : 'SYS_OP_IIX';
+SYS_OP_ITR : 'SYS_OP_ITR';
+SYS_OP_KEY_VECTOR_CREATE : 'SYS_OP_KEY_VECTOR_CREATE';
+SYS_OP_KEY_VECTOR_FILTER_LIST : 'SYS_OP_KEY_VECTOR_FILTER_LIST';
+SYS_OP_KEY_VECTOR_FILTER : 'SYS_OP_KEY_VECTOR_FILTER';
+SYS_OP_KEY_VECTOR_SUCCEEDED : 'SYS_OP_KEY_VECTOR_SUCCEEDED';
+SYS_OP_KEY_VECTOR_USE : 'SYS_OP_KEY_VECTOR_USE';
+SYS_OP_LBID : 'SYS_OP_LBID';
+SYS_OP_LOBLOC2BLOB : 'SYS_OP_LOBLOC2BLOB';
+SYS_OP_LOBLOC2CLOB : 'SYS_OP_LOBLOC2CLOB';
+SYS_OP_LOBLOC2ID : 'SYS_OP_LOBLOC2ID';
+SYS_OP_LOBLOC2NCLOB : 'SYS_OP_LOBLOC2NCLOB';
+SYS_OP_LOBLOC2TYP : 'SYS_OP_LOBLOC2TYP';
+SYS_OP_LSVI : 'SYS_OP_LSVI';
+SYS_OP_LVL : 'SYS_OP_LVL';
+SYS_OP_MAKEOID : 'SYS_OP_MAKEOID';
+SYS_OP_MAP_NONNULL : 'SYS_OP_MAP_NONNULL';
+SYS_OP_MSR : 'SYS_OP_MSR';
+SYS_OP_NICOMBINE : 'SYS_OP_NICOMBINE';
+SYS_OP_NIEXTRACT : 'SYS_OP_NIEXTRACT';
+SYS_OP_NII : 'SYS_OP_NII';
+SYS_OP_NIX : 'SYS_OP_NIX';
+SYS_OP_NOEXPAND : 'SYS_OP_NOEXPAND';
+SYS_OP_NTCIMG : 'SYS_OP_NTCIMG$';
+SYS_OP_NUMTORAW : 'SYS_OP_NUMTORAW';
+SYS_OP_OIDVALUE : 'SYS_OP_OIDVALUE';
+SYS_OP_OPNSIZE : 'SYS_OP_OPNSIZE';
+SYS_OP_PAR_1 : 'SYS_OP_PAR_1';
+SYS_OP_PARGID_1 : 'SYS_OP_PARGID_1';
+SYS_OP_PARGID : 'SYS_OP_PARGID';
+SYS_OP_PAR : 'SYS_OP_PAR';
+SYS_OP_PART_ID : 'SYS_OP_PART_ID';
+SYS_OP_PIVOT : 'SYS_OP_PIVOT';
+SYS_OP_R2O : 'SYS_OP_R2O';
+SYS_OP_RAWTONUM : 'SYS_OP_RAWTONUM';
+SYS_OP_RDTM : 'SYS_OP_RDTM';
+SYS_OP_REF : 'SYS_OP_REF';
+SYS_OP_RMTD : 'SYS_OP_RMTD';
+SYS_OP_ROWIDTOOBJ : 'SYS_OP_ROWIDTOOBJ';
+SYS_OP_RPB : 'SYS_OP_RPB';
+SYS_OPTLOBPRBSC : 'SYS_OPTLOBPRBSC';
+SYS_OP_TOSETID : 'SYS_OP_TOSETID';
+SYS_OP_TPR : 'SYS_OP_TPR';
+SYS_OP_TRTB : 'SYS_OP_TRTB';
+SYS_OPTXICMP : 'SYS_OPTXICMP';
+SYS_OPTXQCASTASNQ : 'SYS_OPTXQCASTASNQ';
+SYS_OP_UNDESCEND : 'SYS_OP_UNDESCEND';
+SYS_OP_VECAND : 'SYS_OP_VECAND';
+SYS_OP_VECBIT : 'SYS_OP_VECBIT';
+SYS_OP_VECOR : 'SYS_OP_VECOR';
+SYS_OP_VECXOR : 'SYS_OP_VECXOR';
+SYS_OP_VERSION : 'SYS_OP_VERSION';
+SYS_OP_VREF : 'SYS_OP_VREF';
+SYS_OP_VVD : 'SYS_OP_VVD';
+SYS_OP_XMLCONS_FOR_CSX : 'SYS_OP_XMLCONS_FOR_CSX';
+SYS_OP_XPTHATG : 'SYS_OP_XPTHATG';
+SYS_OP_XPTHIDX : 'SYS_OP_XPTHIDX';
+SYS_OP_XPTHOP : 'SYS_OP_XPTHOP';
+SYS_OP_XTXT2SQLT : 'SYS_OP_XTXT2SQLT';
+SYS_OP_ZONE_ID : 'SYS_OP_ZONE_ID';
+SYS_ORDERKEY_DEPTH : 'SYS_ORDERKEY_DEPTH';
+SYS_ORDERKEY_MAXCHILD : 'SYS_ORDERKEY_MAXCHILD';
+SYS_ORDERKEY_PARENT : 'SYS_ORDERKEY_PARENT';
+SYS_PARALLEL_TXN : 'SYS_PARALLEL_TXN';
+SYS_PATHID_IS_ATTR : 'SYS_PATHID_IS_ATTR';
+SYS_PATHID_IS_NMSPC : 'SYS_PATHID_IS_NMSPC';
+SYS_PATHID_LASTNAME : 'SYS_PATHID_LASTNAME';
+SYS_PATHID_LASTNMSPC : 'SYS_PATHID_LASTNMSPC';
+SYS_PATH_REVERSE : 'SYS_PATH_REVERSE';
+SYS_PXQEXTRACT : 'SYS_PXQEXTRACT';
+SYS_RAW_TO_XSID : 'SYS_RAW_TO_XSID';
+SYS_RID_ORDER : 'SYS_RID_ORDER';
+SYS_ROW_DELTA : 'SYS_ROW_DELTA';
+SYS_SC_2_XMLT : 'SYS_SC_2_XMLT';
+SYS_SYNRCIREDO : 'SYS_SYNRCIREDO';
+SYSTEM_DEFINED : 'SYSTEM_DEFINED';
+SYSTEM : 'SYSTEM';
+SYSTIMESTAMP : 'SYSTIMESTAMP';
+SYS_TYPEID : 'SYS_TYPEID';
+SYS_UMAKEXML : 'SYS_UMAKEXML';
+SYS_XMLANALYZE : 'SYS_XMLANALYZE';
+SYS_XMLCONTAINS : 'SYS_XMLCONTAINS';
+SYS_XMLCONV : 'SYS_XMLCONV';
+SYS_XMLEXNSURI : 'SYS_XMLEXNSURI';
+SYS_XMLGEN : 'SYS_XMLGEN';
+SYS_XMLI_LOC_ISNODE : 'SYS_XMLI_LOC_ISNODE';
+SYS_XMLI_LOC_ISTEXT : 'SYS_XMLI_LOC_ISTEXT';
+SYS_XMLINSTR : 'SYS_XMLINSTR';
+SYS_XMLLOCATOR_GETSVAL : 'SYS_XMLLOCATOR_GETSVAL';
+SYS_XMLNODEID_GETCID : 'SYS_XMLNODEID_GETCID';
+SYS_XMLNODEID_GETLOCATOR : 'SYS_XMLNODEID_GETLOCATOR';
+SYS_XMLNODEID_GETOKEY : 'SYS_XMLNODEID_GETOKEY';
+SYS_XMLNODEID_GETPATHID : 'SYS_XMLNODEID_GETPATHID';
+SYS_XMLNODEID_GETPTRID : 'SYS_XMLNODEID_GETPTRID';
+SYS_XMLNODEID_GETRID : 'SYS_XMLNODEID_GETRID';
+SYS_XMLNODEID_GETSVAL : 'SYS_XMLNODEID_GETSVAL';
+SYS_XMLNODEID_GETTID : 'SYS_XMLNODEID_GETTID';
+SYS_XMLNODEID : 'SYS_XMLNODEID';
+SYS_XMLT_2_SC : 'SYS_XMLT_2_SC';
+SYS_XMLTRANSLATE : 'SYS_XMLTRANSLATE';
+SYS_XMLTYPE2SQL : 'SYS_XMLTYPE2SQL';
+SYS_XQ_ASQLCNV : 'SYS_XQ_ASQLCNV';
+SYS_XQ_ATOMCNVCHK : 'SYS_XQ_ATOMCNVCHK';
+SYS_XQBASEURI : 'SYS_XQBASEURI';
+SYS_XQCASTABLEERRH : 'SYS_XQCASTABLEERRH';
+SYS_XQCODEP2STR : 'SYS_XQCODEP2STR';
+SYS_XQCODEPEQ : 'SYS_XQCODEPEQ';
+SYS_XQCON2SEQ : 'SYS_XQCON2SEQ';
+SYS_XQCONCAT : 'SYS_XQCONCAT';
+SYS_XQDELETE : 'SYS_XQDELETE';
+SYS_XQDFLTCOLATION : 'SYS_XQDFLTCOLATION';
+SYS_XQDOC : 'SYS_XQDOC';
+SYS_XQDOCURI : 'SYS_XQDOCURI';
+SYS_XQDURDIV : 'SYS_XQDURDIV';
+SYS_XQED4URI : 'SYS_XQED4URI';
+SYS_XQENDSWITH : 'SYS_XQENDSWITH';
+SYS_XQERRH : 'SYS_XQERRH';
+SYS_XQERR : 'SYS_XQERR';
+SYS_XQESHTMLURI : 'SYS_XQESHTMLURI';
+SYS_XQEXLOBVAL : 'SYS_XQEXLOBVAL';
+SYS_XQEXSTWRP : 'SYS_XQEXSTWRP';
+SYS_XQEXTRACT : 'SYS_XQEXTRACT';
+SYS_XQEXTRREF : 'SYS_XQEXTRREF';
+SYS_XQEXVAL : 'SYS_XQEXVAL';
+SYS_XQFB2STR : 'SYS_XQFB2STR';
+SYS_XQFNBOOL : 'SYS_XQFNBOOL';
+SYS_XQFNCMP : 'SYS_XQFNCMP';
+SYS_XQFNDATIM : 'SYS_XQFNDATIM';
+SYS_XQFNLNAME : 'SYS_XQFNLNAME';
+SYS_XQFNNM : 'SYS_XQFNNM';
+SYS_XQFNNSURI : 'SYS_XQFNNSURI';
+SYS_XQFNPREDTRUTH : 'SYS_XQFNPREDTRUTH';
+SYS_XQFNQNM : 'SYS_XQFNQNM';
+SYS_XQFNROOT : 'SYS_XQFNROOT';
+SYS_XQFORMATNUM : 'SYS_XQFORMATNUM';
+SYS_XQFTCONTAIN : 'SYS_XQFTCONTAIN';
+SYS_XQFUNCR : 'SYS_XQFUNCR';
+SYS_XQGETCONTENT : 'SYS_XQGETCONTENT';
+SYS_XQINDXOF : 'SYS_XQINDXOF';
+SYS_XQINSERT : 'SYS_XQINSERT';
+SYS_XQINSPFX : 'SYS_XQINSPFX';
+SYS_XQIRI2URI : 'SYS_XQIRI2URI';
+SYS_XQLANG : 'SYS_XQLANG';
+SYS_XQLLNMFRMQNM : 'SYS_XQLLNMFRMQNM';
+SYS_XQMKNODEREF : 'SYS_XQMKNODEREF';
+SYS_XQNILLED : 'SYS_XQNILLED';
+SYS_XQNODENAME : 'SYS_XQNODENAME';
+SYS_XQNORMSPACE : 'SYS_XQNORMSPACE';
+SYS_XQNORMUCODE : 'SYS_XQNORMUCODE';
+SYS_XQ_NRNG : 'SYS_XQ_NRNG';
+SYS_XQNSP4PFX : 'SYS_XQNSP4PFX';
+SYS_XQNSPFRMQNM : 'SYS_XQNSPFRMQNM';
+SYS_XQPFXFRMQNM : 'SYS_XQPFXFRMQNM';
+SYS_XQ_PKSQL2XML : 'SYS_XQ_PKSQL2XML';
+SYS_XQPOLYABS : 'SYS_XQPOLYABS';
+SYS_XQPOLYADD : 'SYS_XQPOLYADD';
+SYS_XQPOLYCEL : 'SYS_XQPOLYCEL';
+SYS_XQPOLYCSTBL : 'SYS_XQPOLYCSTBL';
+SYS_XQPOLYCST : 'SYS_XQPOLYCST';
+SYS_XQPOLYDIV : 'SYS_XQPOLYDIV';
+SYS_XQPOLYFLR : 'SYS_XQPOLYFLR';
+SYS_XQPOLYMOD : 'SYS_XQPOLYMOD';
+SYS_XQPOLYMUL : 'SYS_XQPOLYMUL';
+SYS_XQPOLYRND : 'SYS_XQPOLYRND';
+SYS_XQPOLYSQRT : 'SYS_XQPOLYSQRT';
+SYS_XQPOLYSUB : 'SYS_XQPOLYSUB';
+SYS_XQPOLYUMUS : 'SYS_XQPOLYUMUS';
+SYS_XQPOLYUPLS : 'SYS_XQPOLYUPLS';
+SYS_XQPOLYVEQ : 'SYS_XQPOLYVEQ';
+SYS_XQPOLYVGE : 'SYS_XQPOLYVGE';
+SYS_XQPOLYVGT : 'SYS_XQPOLYVGT';
+SYS_XQPOLYVLE : 'SYS_XQPOLYVLE';
+SYS_XQPOLYVLT : 'SYS_XQPOLYVLT';
+SYS_XQPOLYVNE : 'SYS_XQPOLYVNE';
+SYS_XQREF2VAL : 'SYS_XQREF2VAL';
+SYS_XQRENAME : 'SYS_XQRENAME';
+SYS_XQREPLACE : 'SYS_XQREPLACE';
+SYS_XQRESVURI : 'SYS_XQRESVURI';
+SYS_XQRNDHALF2EVN : 'SYS_XQRNDHALF2EVN';
+SYS_XQRSLVQNM : 'SYS_XQRSLVQNM';
+SYS_XQRYENVPGET : 'SYS_XQRYENVPGET';
+SYS_XQRYVARGET : 'SYS_XQRYVARGET';
+SYS_XQRYWRP : 'SYS_XQRYWRP';
+SYS_XQSEQ2CON4XC : 'SYS_XQSEQ2CON4XC';
+SYS_XQSEQ2CON : 'SYS_XQSEQ2CON';
+SYS_XQSEQDEEPEQ : 'SYS_XQSEQDEEPEQ';
+SYS_XQSEQINSB : 'SYS_XQSEQINSB';
+SYS_XQSEQRM : 'SYS_XQSEQRM';
+SYS_XQSEQRVS : 'SYS_XQSEQRVS';
+SYS_XQSEQSUB : 'SYS_XQSEQSUB';
+SYS_XQSEQTYPMATCH : 'SYS_XQSEQTYPMATCH';
+SYS_XQSTARTSWITH : 'SYS_XQSTARTSWITH';
+SYS_XQSTATBURI : 'SYS_XQSTATBURI';
+SYS_XQSTR2CODEP : 'SYS_XQSTR2CODEP';
+SYS_XQSTRJOIN : 'SYS_XQSTRJOIN';
+SYS_XQSUBSTRAFT : 'SYS_XQSUBSTRAFT';
+SYS_XQSUBSTRBEF : 'SYS_XQSUBSTRBEF';
+SYS_XQTOKENIZE : 'SYS_XQTOKENIZE';
+SYS_XQTREATAS : 'SYS_XQTREATAS';
+SYS_XQ_UPKXML2SQL : 'SYS_XQ_UPKXML2SQL';
+SYS_XQXFORM : 'SYS_XQXFORM';
+SYS_XSID_TO_RAW : 'SYS_XSID_TO_RAW';
+SYS_ZMAP_FILTER : 'SYS_ZMAP_FILTER';
+SYS_ZMAP_REFRESH : 'SYS_ZMAP_REFRESH';
+T_LETTER : 'T';
+TABLE_LOOKUP_BY_NL : 'TABLE_LOOKUP_BY_NL';
+TABLESPACE_NO : 'TABLESPACE_NO';
+TABLESPACE : 'TABLESPACE';
+TABLES : 'TABLES';
+TABLE_STATS : 'TABLE_STATS';
+TABLE : 'TABLE';
+TABNO : 'TABNO';
+TAG : 'TAG';
+TANH : 'TANH';
+TAN : 'TAN';
+TBLORIDXPARTNUM : 'TBL$OR$IDX$PART$NUM';
+TEMPFILE : 'TEMPFILE';
+TEMPLATE : 'TEMPLATE';
+TEMPORARY : 'TEMPORARY';
+TEMP_TABLE : 'TEMP_TABLE';
+TEST : 'TEST';
+TEXT : 'TEXT';
+THAN : 'THAN';
+THEN : 'THEN';
+THE : 'THE';
+THREAD : 'THREAD';
+THROUGH : 'THROUGH';
+TIER : 'TIER';
+TIES : 'TIES';
+TIMEOUT : 'TIMEOUT';
+TIMESTAMP_LTZ_UNCONSTRAINED : 'TIMESTAMP_LTZ_UNCONSTRAINED';
+TIMESTAMP : 'TIMESTAMP';
+TIMESTAMP_TZ_UNCONSTRAINED : 'TIMESTAMP_TZ_UNCONSTRAINED';
+TIMESTAMP_UNCONSTRAINED : 'TIMESTAMP_UNCONSTRAINED';
+TIMES : 'TIMES';
+TIME : 'TIME';
+TIMEZONE : 'TIMEZONE';
+TIMEZONE_ABBR : 'TIMEZONE_ABBR';
+TIMEZONE_HOUR : 'TIMEZONE_HOUR';
+TIMEZONE_MINUTE : 'TIMEZONE_MINUTE';
+TIMEZONE_OFFSET : 'TIMEZONE_OFFSET';
+TIMEZONE_REGION : 'TIMEZONE_REGION';
+TIME_ZONE : 'TIME_ZONE';
+TIMING : 'TIMING';
+TIV_GB : 'TIV_GB';
+TIV_SSF : 'TIV_SSF';
+TO_ACLID : 'TO_ACLID';
+TO_BINARY_DOUBLE : 'TO_BINARY_DOUBLE';
+TO_BINARY_FLOAT : 'TO_BINARY_FLOAT';
+TO_BLOB : 'TO_BLOB';
+TO_CLOB : 'TO_CLOB';
+TO_DSINTERVAL : 'TO_DSINTERVAL';
+TO_LOB : 'TO_LOB';
+TO_MULTI_BYTE : 'TO_MULTI_BYTE';
+TO_NCHAR : 'TO_NCHAR';
+TO_NCLOB : 'TO_NCLOB';
+TO_NUMBER : 'TO_NUMBER';
+TOPLEVEL : 'TOPLEVEL';
+TO_SINGLE_BYTE : 'TO_SINGLE_BYTE';
+TO_TIMESTAMP : 'TO_TIMESTAMP';
+TO_TIMESTAMP_TZ : 'TO_TIMESTAMP_TZ';
+TO_TIME : 'TO_TIME';
+TO_TIME_TZ : 'TO_TIME_TZ';
+TO : 'TO';
+TO_YMINTERVAL : 'TO_YMINTERVAL';
+TRACE : 'TRACE';
+TRACING : 'TRACING';
+TRACKING : 'TRACKING';
+TRAILING : 'TRAILING';
+TRANSACTION : 'TRANSACTION';
+TRANSFORM : 'TRANSFORM';
+TRANSFORM_DISTINCT_AGG : 'TRANSFORM_DISTINCT_AGG';
+TRANSITIONAL : 'TRANSITIONAL';
+TRANSITION : 'TRANSITION';
+TRANSLATE : 'TRANSLATE';
+TRANSLATION : 'TRANSLATION';
+TREAT : 'TREAT';
+TRIGGERS : 'TRIGGERS';
+TRIGGER : 'TRIGGER';
+TRUE : 'TRUE';
+TRUNCATE : 'TRUNCATE';
+TRUNC : 'TRUNC';
+TRUSTED : 'TRUSTED';
+TRUST : 'TRUST';
+TUNING : 'TUNING';
+TX : 'TX';
+TYPES : 'TYPES';
+TYPE : 'TYPE';
+TZ_OFFSET : 'TZ_OFFSET';
+UB2 : 'UB2';
+UBA : 'UBA';
+UCS2 : 'UCS2';
+UID : 'UID';
+UNARCHIVED : 'UNARCHIVED';
+UNBOUNDED : 'UNBOUNDED';
+UNBOUND : 'UNBOUND';
+UNCONDITIONAL : 'UNCONDITIONAL';
+UNDER : 'UNDER';
+UNDO : 'UNDO';
+UNDROP : 'UNDROP';
+UNIFORM : 'UNIFORM';
+UNION : 'UNION';
+UNIQUE : 'UNIQUE';
+UNISTR : 'UNISTR';
+UNLIMITED : 'UNLIMITED';
+UNLOAD : 'UNLOAD';
+UNLOCK : 'UNLOCK';
+UNMATCHED : 'UNMATCHED';
+UNNEST_INNERJ_DISTINCT_VIEW : 'UNNEST_INNERJ_DISTINCT_VIEW';
+UNNEST_NOSEMIJ_NODISTINCTVIEW : 'UNNEST_NOSEMIJ_NODISTINCTVIEW';
+UNNEST_SEMIJ_VIEW : 'UNNEST_SEMIJ_VIEW';
+UNNEST : 'UNNEST';
+UNPACKED : 'UNPACKED';
+UNPIVOT : 'UNPIVOT';
+UNPLUG : 'UNPLUG';
+UNPROTECTED : 'UNPROTECTED';
+UNQUIESCE : 'UNQUIESCE';
+UNRECOVERABLE : 'UNRECOVERABLE';
+UNRESTRICTED : 'UNRESTRICTED';
+UNSUBSCRIBE : 'UNSUBSCRIBE';
+UNTIL : 'UNTIL';
+UNUSABLE : 'UNUSABLE';
+UNUSED : 'UNUSED';
+UPDATABLE : 'UPDATABLE';
+UPDATED : 'UPDATED';
+UPDATE : 'UPDATE';
+UPDATEXML : 'UPDATEXML';
+UPD_INDEXES : 'UPD_INDEXES';
+UPD_JOININDEX : 'UPD_JOININDEX';
+UPGRADE : 'UPGRADE';
+UPPER : 'UPPER';
+UPSERT : 'UPSERT';
+UROWID : 'UROWID';
+USABLE : 'USABLE';
+USAGE : 'USAGE';
+USE_ANTI : 'USE_ANTI';
+USE_CONCAT : 'USE_CONCAT';
+USE_CUBE : 'USE_CUBE';
+USE_HASH_AGGREGATION : 'USE_HASH_AGGREGATION';
+USE_HASH_GBY_FOR_PUSHDOWN : 'USE_HASH_GBY_FOR_PUSHDOWN';
+USE_HASH : 'USE_HASH';
+USE_HIDDEN_PARTITIONS : 'USE_HIDDEN_PARTITIONS';
+USE_INVISIBLE_INDEXES : 'USE_INVISIBLE_INDEXES';
+USE_MERGE_CARTESIAN : 'USE_MERGE_CARTESIAN';
+USE_MERGE : 'USE_MERGE';
+USE_NL : 'USE_NL';
+USE_NL_WITH_INDEX : 'USE_NL_WITH_INDEX';
+USE_PRIVATE_OUTLINES : 'USE_PRIVATE_OUTLINES';
+USER_DATA : 'USER_DATA';
+USER_DEFINED : 'USER_DEFINED';
+USERENV : 'USERENV';
+USERGROUP : 'USERGROUP';
+USER_RECYCLEBIN : 'USER_RECYCLEBIN';
+USERS : 'USERS';
+USER_TABLESPACES : 'USER_TABLESPACES';
+USER : 'USER';
+USE_SEMI : 'USE_SEMI';
+USE_STORED_OUTLINES : 'USE_STORED_OUTLINES';
+USE_TTT_FOR_GSETS : 'USE_TTT_FOR_GSETS';
+USE : 'USE';
+USE_VECTOR_AGGREGATION : 'USE_VECTOR_AGGREGATION';
+USE_WEAK_NAME_RESL : 'USE_WEAK_NAME_RESL';
+USING_NO_EXPAND : 'USING_NO_EXPAND';
+USING_NLS_COMP : 'USING_NLS_COMP';
+USING : 'USING';
+UTF16BE : 'UTF16BE';
+UTF16LE : 'UTF16LE';
+UTF32 : 'UTF32';
+UTF8 : 'UTF8';
+V1 : 'V1';
+V2 : 'V2';
+VALIDATE : 'VALIDATE';
+VALIDATE_CONVERSION : 'VALIDATE_CONVERSION';
+VALIDATION : 'VALIDATION';
+VALID_TIME_END : 'VALID_TIME_END';
+VALUES : 'VALUES';
+VALUE : 'VALUE';
+VARCHAR2 : 'VARCHAR2';
+VARCHAR : 'VARCHAR';
+VARIABLE : 'VARIABLE';
+VAR_POP : 'VAR_POP';
+VARRAYS : 'VARRAYS';
+VARRAY : 'VARRAY';
+VAR_SAMP : 'VAR_SAMP';
+VARYING : 'VARYING';
+VECTOR_READ_TRACE : 'VECTOR_READ_TRACE';
+VECTOR_READ : 'VECTOR_READ';
+VECTOR_TRANSFORM_DIMS : 'VECTOR_TRANSFORM_DIMS';
+VECTOR_TRANSFORM_FACT : 'VECTOR_TRANSFORM_FACT';
+VECTOR_TRANSFORM : 'VECTOR_TRANSFORM';
+VERIFIER : 'VERIFIER';
+VERIFY : 'VERIFY';
+VERSIONING : 'VERSIONING';
+VERSIONS_ENDSCN : 'VERSIONS_ENDSCN';
+VERSIONS_ENDTIME : 'VERSIONS_ENDTIME';
+VERSIONS_OPERATION : 'VERSIONS_OPERATION';
+VERSIONS_STARTSCN : 'VERSIONS_STARTSCN';
+VERSIONS_STARTTIME : 'VERSIONS_STARTTIME';
+VERSIONS : 'VERSIONS';
+VERSIONS_XID : 'VERSIONS_XID';
+VERSION : 'VERSION';
+VIEW : 'VIEW';
+VIOLATION : 'VIOLATION';
+VIRTUAL : 'VIRTUAL';
+VISIBILITY : 'VISIBILITY';
+VISIBLE : 'VISIBLE';
+VOLUME : 'VOLUME';
+VSIZE : 'VSIZE';
+WAIT : 'WAIT';
+WALLET : 'WALLET';
+WARNING : 'WARNING';
+WEEKS : 'WEEKS';
+WEEK : 'WEEK';
+WELLFORMED : 'WELLFORMED';
+WHENEVER : 'WHENEVER';
+WHEN : 'WHEN';
+WHERE : 'WHERE';
+WHILE : 'WHILE';
+WHITESPACE : 'WHITESPACE';
+WIDTH_BUCKET : 'WIDTH_BUCKET';
+WITHIN : 'WITHIN';
+WITHOUT : 'WITHOUT';
+WITH_PLSQL : 'WITH_PLSQL';
+WITH : 'WITH';
+WORK : 'WORK';
+WRAPPED : 'WRAPPED';
+WRAPPER : 'WRAPPER';
+WRITE : 'WRITE';
+XDB_FASTPATH_INSERT : 'XDB_FASTPATH_INSERT';
+XDB : 'XDB';
+X_DYN_PRUNE : 'X_DYN_PRUNE';
+XID : 'XID';
+XML2OBJECT : 'XML2OBJECT';
+XMLAGG : 'XMLAGG';
+XMLATTRIBUTES : 'XMLATTRIBUTES';
+XMLCAST : 'XMLCAST';
+XMLCDATA : 'XMLCDATA';
+XMLCOLATTVAL : 'XMLCOLATTVAL';
+XMLCOMMENT : 'XMLCOMMENT';
+XMLCONCAT : 'XMLCONCAT';
+XMLDIFF : 'XMLDIFF';
+XML_DML_RWT_STMT : 'XML_DML_RWT_STMT';
+XMLELEMENT : 'XMLELEMENT';
+XMLEXISTS2 : 'XMLEXISTS2';
+XMLEXISTS : 'XMLEXISTS';
+XMLFOREST : 'XMLFOREST';
+XMLINDEX : 'XMLINDEX';
+XMLINDEX_REWRITE_IN_SELECT : 'XMLINDEX_REWRITE_IN_SELECT';
+XMLINDEX_REWRITE : 'XMLINDEX_REWRITE';
+XMLINDEX_SEL_IDX_TBL : 'XMLINDEX_SEL_IDX_TBL';
+XMLISNODE : 'XMLISNODE';
+XMLISVALID : 'XMLISVALID';
+XMLNAMESPACES : 'XMLNAMESPACES';
+XMLPARSE : 'XMLPARSE';
+XMLPATCH : 'XMLPATCH';
+XMLPI : 'XMLPI';
+XMLQUERYVAL : 'XMLQUERYVAL';
+XMLQUERY : 'XMLQUERY';
+XMLROOT : 'XMLROOT';
+XMLSCHEMA : 'XMLSCHEMA';
+XMLSERIALIZE : 'XMLSERIALIZE';
+XMLTABLE : 'XMLTABLE';
+XMLTRANSFORMBLOB : 'XMLTRANSFORMBLOB';
+XMLTRANSFORM : 'XMLTRANSFORM';
+XMLTYPE : 'XMLTYPE';
+SYSXMLTYPE : '"SYS"."XMLTYPE"';
+XML : 'XML';
+XPATHTABLE : 'XPATHTABLE';
+XS_SYS_CONTEXT : 'XS_SYS_CONTEXT';
+XS : 'XS';
+XTRANSPORT : 'XTRANSPORT';
+YEARS : 'YEARS';
+YEAR : 'YEAR';
+YES : 'YES';
+YMINTERVAL_UNCONSTRAINED : 'YMINTERVAL_UNCONSTRAINED';
+ZONEMAP : 'ZONEMAP';
+ZONE : 'ZONE';
+PREDICTION : 'PREDICTION';
+PREDICTION_BOUNDS : 'PREDICTION_BOUNDS';
+PREDICTION_COST : 'PREDICTION_COST';
+PREDICTION_DETAILS : 'PREDICTION_DETAILS';
+PREDICTION_PROBABILITY : 'PREDICTION_PROBABILITY';
+PREDICTION_SET : 'PREDICTION_SET';
+
+BLOCKCHAIN : 'BLOCKCHAIN';
+COLLATE : 'COLLATE';
+COLLATION : 'COLLATION';
+DEFINITION : 'DEFINITION';
+DUPLICATED : 'DUPLICATED';
+EXTENDED : 'EXTENDED';
+HASHING : 'HASHING';
+IDLE : 'IDLE';
+IMMUTABLE : 'IMMUTABLE';
+ORACLE_DATAPUMP : 'ORACLE_DATAPUMP';
+ORACLE_HDFS : 'ORACLE_HDFS';
+ORACLE_HIVE : 'ORACLE_HIVE';
+ORACLE_LOADER : 'ORACLE_LOADER';
+SHA2_512_Q : '"SHA2_512"';
+SHARDED : 'SHARDED';
+V1_Q : '"V1"';
+
+ISOLATE : 'ISOLATE';
+ROOT : 'ROOT';
+UNITE : 'UNITE';
+ALGORITHM : 'ALGORITHM';
+
+CUME_DIST : 'CUME_DIST';
+DENSE_RANK : 'DENSE_RANK';
+LISTAGG : 'LISTAGG';
+PERCENT_RANK : 'PERCENT_RANK';
+PERCENTILE_CONT : 'PERCENTILE_CONT';
+PERCENTILE_DISC : 'PERCENTILE_DISC';
+RANK : 'RANK';
+
+AVG : 'AVG';
+CORR : 'CORR';
+COVAR_ : 'COVAR_';
+DECODE : 'DECODE';
+LAG : 'LAG';
+LAG_DIFF : 'LAG_DIFF';
+LAG_DIFF_PERCENT : 'LAG_DIFF_PERCENT';
+LEAD : 'LEAD';
+MAX : 'MAX';
+MEDIAN : 'MEDIAN';
+MEMOPTIMIZE : 'MEMOPTIMIZE';
+MIN : 'MIN';
+NTILE : 'NTILE';
+NVL : 'NVL';
+RATIO_TO_REPORT : 'RATIO_TO_REPORT';
+REGR_ : 'REGR_';
+ROUND : 'ROUND';
+ROW_NUMBER : 'ROW_NUMBER';
+SUBSTR : 'SUBSTR';
+TO_CHAR : 'TO_CHAR';
+TRIM : 'TRIM';
+SUM : 'SUM';
+STDDEV : 'STDDEV';
+VAR_ : 'VAR_';
+VARIANCE : 'VARIANCE';
+LEAST : 'LEAST';
+GREATEST : 'GREATEST';
+TO_DATE : 'TO_DATE';
+
+CHARSETID : 'CHARSETID';
+CHARSETFORM : 'CHARSETFORM';
+DURATION : 'DURATION';
+EXTEND : 'EXTEND';
+MAXLEN : 'MAXLEN';
+PERSISTABLE : 'PERSISTABLE';
+POLYMORPHIC : 'POLYMORPHIC';
+STRUCT : 'STRUCT';
+TDO : 'TDO';
+WM_CONCAT : 'WM_CONCAT';
+
+// Rule #358 - subtoken typecast in , it also incorporates
+// Lowercase 'n' is a usual addition to the standard
+
+NATIONAL_CHAR_STRING_LIT: 'N' '\'' (~('\'' | '\r' | '\n') | '\'' '\'' | NEWLINE)* '\'';
+
+// Rule #040 - subtoken typecast in
+// Lowercase 'b' is a usual addition to the standard
+
+BIT_STRING_LIT: 'B' ('\'' [01]* '\'')+;
+
+// Rule #284 - subtoken typecast in
+// Lowercase 'x' is a usual addition to the standard
+
+HEX_STRING_LIT : 'X' ('\'' [A-F0-9]* '\'')+;
+DOUBLE_PERIOD : '..';
+PERIOD : '.';
+
+//{ Rule #238
+// This rule is a bit tricky - it resolves the ambiguity with
+// It also incorporates and for the
+// Rule #501 was incorporated directly in the token
+// See also the rule #617
+/*
+ : (
+ UNSIGNED_INTEGER
+ ( '.' UNSIGNED_INTEGER
+ | {$type = UNSIGNED_INTEGER;}
+ ) ( E ('+' | '-')? UNSIGNED_INTEGER {$type = APPROXIMATE_NUM_LIT;} )?
+ | '.' UNSIGNED_INTEGER ( E ('+' | '-')? UNSIGNED_INTEGER {$type = APPROXIMATE_NUM_LIT;} )?
+ )
+ (D | F)?
+ ;*/
+
+UNSIGNED_INTEGER : [0-9]+;
+APPROXIMATE_NUM_LIT : FLOAT_FRAGMENT ('E' ('+' | '-')? (FLOAT_FRAGMENT | [0-9]+))? ('D' | 'F')?;
+
+// Rule #--- is a base for Rule #065 , it incorporates
+// and a superfluous subtoken typecasting of the "QUOTE"
+CHAR_STRING: '\'' (~('\'' | '\r' | '\n') | '\'' '\'' | NEWLINE)* '\'';
+
+// See https://livesql.oracle.com/apex/livesql/file/content_CIREYU9EA54EOKQ7LAMZKRF6P.html
+// TODO: context sensitive string quotes (any characted after quote)
+CHAR_STRING_PERL:
+ 'Q' '\'' (
+ QS_ANGLE
+ | QS_BRACE
+ | QS_BRACK
+ | QS_PAREN
+ | QS_EXCLAM
+ | QS_SHARP
+ | QS_QUOTE
+ | QS_DQUOTE
+ | QS_TILDA
+ | QS_SOLIDUS
+ | QS_RSOLIDUS
+ ) '\'' -> type(CHAR_STRING)
+;
+fragment QS_ANGLE : '<' .*? '>';
+fragment QS_BRACE : '{' .*? '}';
+fragment QS_BRACK : '[' .*? ']';
+fragment QS_PAREN : '(' .*? ')';
+fragment QS_EXCLAM : '!' .*? '!';
+fragment QS_SHARP : '#' .*? '#';
+fragment QS_QUOTE : '\'' .*? '\'';
+fragment QS_DQUOTE : '"' .*? '"';
+fragment QS_TILDA : '~' .*? '~';
+fragment QS_SOLIDUS : '/' .*? '/';
+fragment QS_RSOLIDUS : '\\' .*? '\\';
+
+DELIMITED_ID: '"' (~ [\u0000"] | '"' '"')+ '"';
+
+PERCENT : '%';
+AMPERSAND : '&';
+LEFT_PAREN : '(';
+RIGHT_PAREN : ')';
+DOUBLE_ASTERISK : '**';
+ASTERISK : '*';
+PLUS_SIGN : '+';
+MINUS_SIGN : '-';
+COMMA : ',';
+SOLIDUS : '/';
+AT_SIGN : '@';
+ASSIGN_OP : ':=';
+HASH_OP : '#';
+
+SQ: '\'';
+
+BINDVAR:
+ ':' SIMPLE_LETTER (SIMPLE_LETTER | [0-9] | '_')*
+ | ':' DELIMITED_ID // not used in SQL but spotted in v$sqltext when using cursor_sharing
+ | ':' UNSIGNED_INTEGER
+ | QUESTION_MARK // not in SQL, not in DM, not in OCI, use this for JDBC
+;
+
+NOT_EQUAL_OP : '!=' | '<>' | '^=' | '~=';
+CARRET_OPERATOR_PART : '^';
+TILDE_OPERATOR_PART : '~';
+EXCLAMATION_OPERATOR_PART : '!';
+GREATER_THAN_OP : '>';
+LESS_THAN_OP : '<';
+COLON : ':';
+SEMICOLON : ';';
+
+BAR : '|';
+EQUALS_OP : '=';
+
+LEFT_BRACKET : '[';
+RIGHT_BRACKET : ']';
+
+INTRODUCER: '_';
+
+// Comments https://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements006.htm
+
+SINGLE_LINE_COMMENT : '--' ~('\r' | '\n')* NEWLINE_EOF -> channel(HIDDEN);
+MULTI_LINE_COMMENT : '/*' .*? '*/' -> channel(HIDDEN);
+// https://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve034.htm#SQPUG054
+REMARK_COMMENT:
+ 'REM' {this.IsNewlineAtPos(-4)}? 'ARK'? (' ' ~('\r' | '\n')*)? NEWLINE_EOF -> channel(HIDDEN)
+;
+
+// https://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve032.htm#SQPUG052
+PROMPT_MESSAGE: 'PRO' {this.IsNewlineAtPos(-4)}? 'MPT'? (' ' ~('\r' | '\n')*)? NEWLINE_EOF;
+
+// TODO: should starts with newline
+START_CMD: // https://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12002.htm
+ '@' '@'?
+; // https://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12003.htm
+
+REGULAR_ID: SIMPLE_LETTER (SIMPLE_LETTER | '$' | '_' | '#' | [0-9])*;
+
+INQUIRY_DIRECTIVE: '$$' (SIMPLE_LETTER | '_')+;
+
+SPACES: [ \t\r\n]+ -> channel(HIDDEN);
+
+// Fragment rules
+
+fragment NEWLINE_EOF : NEWLINE | EOF;
+fragment QUESTION_MARK : '?';
+fragment SIMPLE_LETTER : [\p{Letter}];
+fragment FLOAT_FRAGMENT : UNSIGNED_INTEGER* '.'? UNSIGNED_INTEGER+;
+fragment NEWLINE : '\r'? '\n';
+fragment SPACE : [ \t];
\ No newline at end of file
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMParser.g4 b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMParser.g4
new file mode 100644
index 0000000000..9fedbcb821
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/antlr4/ai/chat2db/plugin/dm/parser/base/DMParser.g4
@@ -0,0 +1,9730 @@
+/**
+ * Oracle(c) PL/SQL 11g Parser
+ *
+ * Adapted for Dameng (DM) SQL parsing in Chat2DB Community.
+ * Derived from the Oracle PL/SQL grammar; dialect-specific rules such as
+ * EXPLAIN may differ from the upstream Oracle grammar.
+ *
+ * Copyright (c) 2009-2011 Alexandre Porcelli
+ * Copyright (c) 2015-2019 Ivan Kochurkin (KvanTTT, kvanttt@gmail.com, 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
+
+parser grammar DMParser;
+
+options {
+ tokenVocab = DMLexer;
+ superClass = DMParserBase;
+}
+
+@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 (
+ EDITIONABLE
+ | NONEDITIONABLE
+ | 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 (SHARING '=' (METADATA | NONE))? (
+ invoker_rights_clause
+ | accessible_by_clause
+ | default_collation_clause
+ | parallel_enable_clause
+ | result_cache_clause
+ | PIPELINED
+ | DETERMINISTIC
+ )* (
+ ((IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec))
+ | aggregate_clause
+ | pipelined_using_clause
+ | 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? ('(' MODE (DEFAULT | FORCE ) ')')?
+ ;
+
+accessible_by_clause
+ : ACCESSIBLE BY '(' accessor (',' accessor)* ')'
+ ;
+
+default_collation_clause
+ : DEFAULT COLLATION USING_NLS_COMP
+ ;
+
+aggregate_clause
+ : AGGREGATE USING implementation_type_name
+ ;
+
+pipelined_using_clause
+ : PIPELINED ((ROW | TABLE) POLYMORPHIC)? USING implementation_type_name
+ ;
+
+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 (EXCEPTION exception_handler+)?)? 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)* ')')? (
+ accessible_by_clause
+ | PARALLEL_ENABLE
+ )* ';'
+ ;
+
+function_spec
+ : FUNCTION identifier ('(' parameter ( ',' parameter)* ')')? RETURN type_spec (
+ DETERMINISTIC
+ | PIPELINED
+ | parallel_enable_clause
+ | RESULT_CACHE
+ | streaming_clause
+ )* ';'
+ ;
+
+package_obj_body
+ : pragma_declaration
+ | exception_declaration
+ | procedure_spec
+ | function_spec
+ | subtype_declaration
+ | cursor_declaration
+ | variable_declaration
+ | type_declaration
+ | procedure_body
+ | function_body
+ | selection_directive
+ ;
+
+// 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 (
+ PIPELINED
+ | DETERMINISTIC
+ | invoker_rights_clause
+ | parallel_enable_clause
+ | result_cache_clause
+ | streaming_clause
+ // see example in section "How Table Functions Stream their Input Data" on streaming_clause in DM 9i: https://docs.oracle.com/cd/B10501_01/appdev.920/a96624/08_subs.htm#20554
+ )* (
+ ( (IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec))
+ | (PIPELINED | AGGREGATE) USING implementation_type_name
+ ) ';'
+ ;
+
+procedure_body
+ : PROCEDURE identifier ('(' parameter (',' parameter)* ')')? (
+ accessible_by_clause
+ | PARALLEL_ENABLE
+ )* (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? PARALLEL_ENABLE? (
+ 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)? EDITIONABLE? 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 tps_block BEFORE STATEMENT ';'
+ | bk = BEFORE EACH ROW IS tps_block BEFORE EACH ROW ';'
+ | ak = AFTER STATEMENT IS tps_block AFTER STATEMENT ';'
+ | ak = AFTER EACH ROW IS tps_block 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 | REFERENCES) 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 (IF NOT EXISTS)? 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 '(' index_partitioning_values_list ')' segment_attributes_clause?
+ ;
+
+index_partitioning_values_list
+ : literal (',' literal)*
+ | TIMESTAMP literal (',' TIMESTAMP literal)*
+ ;
+
+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 (IF NOT EXISTS)? (
+ 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 (IF EXISTS)? 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 (IF EXISTS)?
+ ;
+
+// 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 (
+ IF NOT EXISTS
+ )? (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 | CONSTRAINTS) 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 (IF NOT EXISTS)? 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 (IF NOT EXISTS)? tempfile_specification? tablespace_group_clause? extent_management_clause?
+ ;
+
+undo_tablespace_clause
+ : UNDO TABLESPACE tablespace_name = id_expression (IF NOT EXISTS)? 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 (IF NOT EXISTS)? (
+ 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 ('(' (TABLESPACE tablespace_name = id_expression)? lob_parameters storage_clause?')')?
+ | '(' (TABLESPACE tablespace_name = id_expression)? lob_parameters storage_clause? ')'
+ )?
+ )
+ | 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? monitoring_nomonitoring? (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 '(' range_values_list ')'
+ ;
+
+range_values_list
+ : literal (',' literal)*
+ | TIMESTAMP literal (',' TIMESTAMP 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 (IF EXISTS)? PURGE?
+ ;
+
+// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/DROP-TABLESPACE.html
+drop_tablespace
+ : DROP TABLESPACE ts = id_expression (IF EXISTS)? ((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 (IF EXISTS)? (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
+ : id_expression
+ ;
+
+database
+ : id_expression
+ ;
+
+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 local_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 link_name (
+ CONNECT TO (
+ CURRENT_USER
+ | user_object_name IDENTIFIED BY password_value link_authentication?
+ )
+ | link_authentication
+ )* (USING CHAR_STRING)?
+ ;
+
+drop_database_link
+ : DROP PUBLIC? DATABASE LINK link_name
+ ;
+
+// 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_extended_names (
+ AT '(' literal (',' literal)* ')' INTO '(' range_partition_desc (',' range_partition_desc)* ')'
+ | INTO '(' (
+ range_partition_desc (',' range_partition_desc)*
+ | list_partition_desc (',' list_partition_desc)*
+ ) ')'
+ ) (update_global_index_clause | update_index_clauses)?
+ ;
+
+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 UNSIGNED_INTEGER?
+ | 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
+ | NOKEEP
+ | NOSCALE
+ ;
+
+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_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
+ : java_spec
+ | c_spec
+ ;
+
+// Call Spec Specific Clauses
+
+java_spec
+ : LANGUAGE JAVA NAME CHAR_STRING
+ ;
+
+c_spec
+ : (LANGUAGE C_LETTER | EXTERNAL) (
+ NAME id_expression LIBRARY identifier
+ | LIBRARY identifier (NAME id_expression)?
+ ) c_agent_in_clause? (WITH CONTEXT)? c_parameters_clause?
+ ;
+
+c_agent_in_clause
+ : AGENT IN '(' expressions ')'
+ ;
+
+c_parameters_clause
+ : PARAMETERS '(' c_external_parameter (',' c_external_parameter)* ')'
+ ;
+
+c_external_parameter
+ : CONTEXT
+ | SELF (TDO | c_property)?
+ | (parameter_name | RETURN) c_property? (BY REFERENCE)? external_datatype = regular_id?
+ ;
+
+c_property
+ : INDICATOR (STRUCT | TDO)?
+ | LENGTH
+ | DURATION
+ | MAXLEN
+ | CHARSETID
+ | CHARSETFORM
+ ;
+
+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
+ | selection_directive
+ ;
+
+// 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)+ ')'
+ | DEPRECATE '(' identifier ( ',' CHAR_STRING)? ')'
+ ) ';'
+ ;
+
+// 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 (NOT NULL_)? table_indexed_by_part?
+ ;
+
+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
+ : (pragma_declaration* statement (';' | EOF) | label_declaration | selection_directive)+
+ ;
+
+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 general_element 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 ')'
+ ;
+
+selection_directive
+ : DOLLAR_IF condition DOLLAR_THEN selection_directive_body (
+ DOLLAR_ELSIF selection_directive_body
+ )* (DOLLAR_ELSE selection_directive_body)? DOLLAR_END
+ ;
+
+error_directive
+ : DOLLAR_ERROR concatenation DOLLAR_END
+ ;
+
+selection_directive_body
+ : (
+ pragma_declaration? statement ';'
+ | variable_declaration
+ | error_directive
+ | function_body
+ | procedure_body
+ )+
+ ;
+
+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_block
+ : declare_spec* body
+ ;
+
+block
+ : (DECLARE declare_spec*)? body
+ ;
+
+// SQL Statements
+
+sql_statement
+ : execute_immediate
+ | data_manipulation_language_statements
+ | cursor_manipulation_statements
+ | transaction_control_statements
+ | collection_method_call
+ ;
+
+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
+ ;
+
+// https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/collection-method.html#GUID-7AF1A3C4-D04B-4F91-9D7B-C92C75E3A300
+collection_method_call // collection methods invocation that could be used as a statement
+ : expression '.' (
+ (DELETE | EXTEND) ('(' index += expression (',' index += expression)* ')')?
+ | TRIM ('(' index += expression ')')?
+ )
+ ;
+
+// 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 (
+ select_statement
+ | update_statement
+ | delete_statement
+ | insert_statement
+ | merge_statement
+ )
+ ;
+
+select_only_statement
+ : with_clause? subquery
+ ;
+
+select_statement
+ : select_only_statement (for_update_clause | order_by_clause | offset_clause | fetch_clause)*
+ ;
+
+// Select Specific Clauses
+with_clause
+ : WITH (function_body | procedure_body)* with_factoring_clause (',' with_factoring_clause)*
+ | WITH (function_body | procedure_body)+ (with_factoring_clause (',' with_factoring_clause)*)?
+ ;
+
+with_factoring_clause
+ : subquery_factoring_clause
+ | subav_factoring_clause
+ ;
+
+subquery_factoring_clause
+ : 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
+ ;
+
+subav_factoring_clause
+ : subav_name = id_expression ANALYTIC VIEW AS '(' subav_clause ')'
+ ;
+
+subav_clause
+ : USING subav_name = object_name hierarchies_clause? filter_clauses? add_calcs_clause?
+ ;
+
+hierarchies_clause
+ : HIERARCHIES '(' hier_alias += object_name (',' hier_alias += object_name)* ')'
+ ;
+
+filter_clauses
+ : FILTER FACT '(' filter_clause (',' filter_clause)* ')'
+ ;
+
+filter_clause
+ : (MEASURES | hier_alias = object_name) TO condition
+ ;
+
+add_calcs_clause
+ : ADD MEASURES '(' add_calc_meas_clause (',' add_calc_meas_clause)* ')'
+ ;
+
+add_calc_meas_clause
+ : meas_name = id_expression AS '(' 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? offset_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_thre
+ ;
+
+join_clause
+ : query_partition_clause? (CROSS | NATURAL)? (INNER | outer_join_type)? JOIN table_ref_aux query_partition_clause? (
+ join_on_part
+ | join_using_part
+ )*
+ | (CROSS | OUTER) APPLY table_ref_aux
+ ;
+
+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 (PERIOD_KEYWORD FOR column_name BETWEEN | BETWEEN (SCN | TIMESTAMP)) expression AND expression
+ | AS OF ((SCN | TIMESTAMP | SNAPSHOT) expression | PERIOD_KEYWORD FOR column_name expression)
+ ;
+
+pivot_clause
+ : PIVOT XML? '(' pivot_element (',' pivot_element)* pivot_for_clause pivot_in_clause ')'
+ ;
+
+pivot_element
+ : (numeric_function | 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
+ ;
+
+update_statement
+ : UPDATE general_table_ref update_set_clause where_clause? static_returning_clause? error_logging_clause?
+ ;
+
+// Update Specific Clauses
+
+update_set_clause
+ : SET (
+ column_based_update_set_clause (',' column_based_update_set_clause)*
+ | VALUE '(' identifier ')' '=' expression
+ )
+ ;
+
+column_based_update_set_clause
+ : column_name '=' expression
+ | paren_column_list '=' subquery
+ ;
+
+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
+
+general_table_ref
+ : (dml_table_expression_clause | ONLY '(' dml_table_expression_clause ')') table_alias?
+ ;
+
+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)
+ ;
+
+dml_table_expression_clause
+ : table_collection_expression
+ | '(' select_statement subquery_restriction_clause? ')'
+ | tableview_name hierarchies_clause? sample_clause?
+ | json_table_clause (AS identifier)?
+ | LATERAL '(' subquery subquery_restriction_clause? ')'
+ ;
+
+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_EQUAL '(' expressions ')'
+ ;
+
+expressions
+ : expression (',' expression)*
+ ;
+
+expression
+ : cursor_expression
+ | logical_expression
+ ;
+
+cursor_expression
+ : CURSOR '(' subquery ')'
+ ;
+
+logical_expression
+ : unary_logical_expression
+ | logical_expression AND logical_expression
+ | logical_expression OR logical_expression
+ ;
+
+unary_logical_expression
+ : NOT? multiset_expression unary_logical_operation?
+ ;
+
+unary_logical_operation
+ : IS NOT? logical_operation
+ ;
+
+logical_operation
+ : (
+ NULL_
+ | NAN
+ | PRESENT
+ | INFINITE
+ | A_LETTER SET
+ | EMPTY_
+ | OF TYPE? '(' ONLY? type_spec (',' type_spec)* ')'
+ | JSON (FORMAT JSON)? (STRICT | LAX)? ((WITH | WITHOUT) UNIQUE KEYS)?
+ )
+ ;
+
+multiset_expression
+ : relational_expression (multiset_type = (MEMBER | SUBMULTISET) OF? concatenation)?
+ | multiset_expression MULTISET multiset_operator = (EXCEPT | INTERSECT | UNION) (
+ ALL
+ | DISTINCT
+ )? relational_expression
+ ;
+
+relational_expression
+ : relational_expression relational_operator relational_expression
+ | compound_expression
+ ;
+
+compound_expression
+ : concatenation (
+ NOT? (
+ IN in_elements
+ | BETWEEN between_elements
+ | like_type = (LIKE | LIKEC | LIKE2 | LIKE4) concatenation (ESCAPE concatenation)?
+ )
+ )?
+ ;
+
+relational_operator
+ : '='
+ | (NOT_EQUAL_OP | '<' '>' | '!' '=' | '^' '=')
+ | ('<' | '>') '='?
+ ;
+
+in_elements
+ : '(' subquery ')'
+ | '(' concatenation (',' concatenation)* ')'
+ | constant
+ | bind_variable
+ | general_element
+ ;
+
+between_elements
+ : concatenation AND concatenation
+ ;
+
+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 COLLATE column_collation_name
+ ;
+
+interval_expression
+ : DAY ('(' concatenation ')')? TO SECOND ('(' concatenation ')')?
+ | YEAR ('(' concatenation ')')? TO MONTH
+ | concatenation (SECOND | DAY | MONTH | YEAR)?
+ ;
+
+model_expression
+ : unary_expression ('[' model_expression_element ']')?
+ ;
+
+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? ')') ')'
+ ;
+
+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]*/
+ | unary_expression '.' (
+ (COUNT | FIRST | LAST | LIMIT)
+ | (EXISTS | NEXT | PRIOR) '(' index += expression ')'
+ )
+ | quantified_expression
+ | standard_function
+ | atom
+ | implicit_cursor_expression
+ ;
+
+// 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_ROWCOUNT '(' index = expression ')'
+ | 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_declaration? 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_declaration? ck1 = CASE searched_case_when_part+ case_else_part? END CASE? label_name?
+ ;
+
+searched_case_when_part
+ : WHEN condition THEN (/*TODO{$case_statement::isStatement}?*/ seq_of_statements | expression)
+ ;
+
+case_else_part
+ : ELSE (/*{$case_statement::isStatement}?*/ seq_of_statements | expression)
+ ;
+
+atom
+ : bind_variable
+ | constant
+ | inquiry_directive
+ | general_element outer_join_sign?
+ | '(' subquery ')' subquery_operation_part*
+ | '(' expressions ')'
+ ;
+
+quantified_expression
+ : (SOME | EXISTS | ALL | ANY) (
+ '(' select_only_statement ')'
+ | '(' expression (',' expression)* ')'
+ )
+ ;
+
+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)?)? ')'
+ ;
+
+standard_function
+ : string_function
+ | numeric_function_wrapper
+ | json_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 | identifier) (
+ FORMAT JSON
+ )?
+ ;
+
+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 ')')?
+ ;
+
+literal
+ : CHAR_STRING
+ | string_function
+ | 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)?
+ ;
+
+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 (',' string_delimiter)? 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
+ | (LEAD | LAG) 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 ')' ('.' general_element_part)*
+ | 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
+ ;
+
+over_clause_keyword
+ : AVG
+ | CORR
+ | LAG_DIFF
+ | LAG_DIFF_PERCENT
+ | MAX
+ | MEDIAN
+ | MIN
+ | NTH_VALUE
+ | NTILE
+ | RATIO_TO_REPORT
+ | ROW_NUMBER
+ | SUM
+ | VARIANCE
+ | REGR_
+ | STDDEV
+ | VAR_
+ | VAR_POP
+ | COVAR_
+ | WM_CONCAT
+ ;
+
+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 (',' concatenation)*
+ ;
+
+within_or_over_part
+ : WITHIN GROUP '(' order_by_clause ')'
+ | over_clause
+ ;
+
+string_delimiter
+ : CHAR_STRING
+ | string_function
+ | string_delimiter BAR BAR string_delimiter
+ | '(' string_delimiter ')'
+ | id_expression
+ ;
+
+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 | condition | 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
+ : database ('.' domain)* (AT_SIGN connection_qualifier)?
+ ;
+
+local_link_name
+ : identifier
+ ;
+
+connection_qualifier
+ : identifier
+ ;
+
+column_name
+ : identifier ('.' id_expression)*
+ ;
+
+tableview_name
+ : identifier ('.' id_expression)? (
+ AT_SIGN link_name
+ | /*TODO{!(input.LA(2) == BY)}?*/ partition_extension_clause
+ )?
+ | xmltable outer_join_sign?
+ ;
+
+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) (query_partition_clause | 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
+ ;
+
+argument
+ : (identifier '=' '>')? 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
+ | SYSXMLTYPE
+ ;
+
+bind_variable
+ : (BINDVAR | ':' UNSIGNED_INTEGER)
+ // Pro*C/C++ indicator variables
+ (INDICATOR? (BINDVAR | ':' UNSIGNED_INTEGER))? ('.' general_element_part)*
+ ;
+
+general_element
+ : general_element_part
+ | general_element ('.' general_element_part)+
+ | '(' general_element ')'
+ ;
+
+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
+ ;
+
+// $>
+
+// $ executeMulti(SimpleSqlStatement statement, Connection connection,
+ boolean limitRowSize, Integer offset, Integer count,
+ Integer resultSetId, ExecutionContext executionContext)
+ throws SQLException {
+ DMExecutableSql parsed = parseExecutableSql(statement.getSql());
+ if (!parsed.isExplain()) {
+ return super.executeMulti(statement, connection, limitRowSize, offset, count, resultSetId, executionContext);
+ }
+
+ markStatementAsExplain(statement);
+ Chat2DBContext.guardStatement(parsed.originalSql());
+ long startedAtEpochMs = System.currentTimeMillis();
+ long executeStartedNanos = System.nanoTime();
+ String plan = explainClient.getExplainInfo(connection, parsed.executableSql());
+ long executeDurationNanos = ExecutionTiming.elapsedNanos(executeStartedNanos);
+ return List.of(buildExplainResponse(parsed, plan, executionContext, startedAtEpochMs, executeDurationNanos));
+ }
+
+ @Override
+ protected List executeMultiStreaming(SimpleSqlStatement statement, Connection connection,
+ boolean limitRowSize, Integer offset, Integer count,
+ Integer resultSetId, ISqlExecutionResultConsumer consumer,
+ ISqlExecutionStatementListener statementListener,
+ ISqlExecutionCancellation cancellation, SqlTypeEnum sqlType,
+ String originalSql, int pageNo, int pageSize,
+ AtomicInteger streamResultSequence, int statementSequence,
+ ExecutionContext executionContext)
+ throws SQLException {
+ DMExecutableSql parsed = parseExecutableSql(statement.getSql());
+ if (!parsed.isExplain()) {
+ return super.executeMultiStreaming(statement, connection, limitRowSize, offset, count, resultSetId,
+ consumer, statementListener, cancellation, sqlType, originalSql, pageNo, pageSize,
+ streamResultSequence, statementSequence, executionContext);
+ }
+
+ markStatementAsExplain(statement);
+ checkCanceled(cancellation);
+ Chat2DBContext.guardStatement(parsed.originalSql());
+ long startedAtEpochMs = System.currentTimeMillis();
+ long executeStartedNanos = System.nanoTime();
+ String plan = explainClient.getExplainInfo(connection, parsed.executableSql());
+ long executeDurationNanos = ExecutionTiming.elapsedNanos(executeStartedNanos);
+ checkCanceled(cancellation);
+
+ ExecuteResponse response = buildExplainResponse(
+ parsed, plan, executionContext, startedAtEpochMs, executeDurationNanos);
+ response.setPageNo(pageNo);
+ response.setPageSize(response.getDataList().size());
+ response.setHasNextPage(Boolean.FALSE);
+ response.setFuzzyTotal(Integer.toString(response.getDataList().size()));
+ publishMaterializedQueryResult(response, consumer, streamResultSequence, statementSequence, pageNo, pageSize);
+ return List.of(response);
+ }
+
+ private void markStatementAsExplain(SimpleSqlStatement statement) {
+ // Outer execute/executeStreaming overwrite response.sqlType from statement.sqlType
+ // after setExplain() rewrote the SQL text without updating the type.
+ statement.setSqlType(ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum.EXPLAIN.name());
+ }
+
+ private DMExecutableSql parseExecutableSql(String sql) throws SQLException {
+ try {
+ return parser.parseExecutableSql(sql);
+ } catch (IllegalArgumentException e) {
+ // Keep EXPLAIN off the default JDBC path when the DM grammar cannot classify it.
+ throw new SQLException(e.getMessage(), e);
+ }
+ }
+
+ private ExecuteResponse buildExplainResponse(DMExecutableSql parsed, String plan,
+ ExecutionContext executionContext,
+ long startedAtEpochMs, long executeDurationNanos) {
+ List headerList = new ArrayList<>();
+ headerList.add(Header.builder()
+ .name("Execution Plan")
+ .dataType("VARCHAR")
+ .build());
+
+ List row = new ArrayList<>();
+ row.add(ResultCell.of(plan));
+
+ List> dataList = new ArrayList<>();
+ dataList.add(row);
+
+ return ExecuteResponse.builder()
+ .success(Boolean.TRUE)
+ .sql(parsed.originalSql())
+ .originalSql(parsed.originalSql())
+ .sqlType(ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum.EXPLAIN.name())
+ .headerList(headerList)
+ .dataList(dataList)
+ .hasNextPage(Boolean.FALSE)
+ .executionContext(executionContext)
+ .executionMetrics(ExecutionTiming.complete(
+ ExecutionTiming.started(startedAtEpochMs), executeDurationNanos, 0L, 1))
+ .build();
+ }
+
+ private void checkCanceled(ISqlExecutionCancellation cancellation) throws SQLException {
+ if (cancellation != null && cancellation.isCanceled()) {
+ throw new SQLException("SQL execution canceled");
+ }
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMExplainClient.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMExplainClient.java
new file mode 100644
index 0000000000..d78139a3e5
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMExplainClient.java
@@ -0,0 +1,76 @@
+package ai.chat2db.plugin.dm;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+final class DMExplainClient {
+
+ String getExplainInfo(Connection connection, String sql) throws SQLException {
+ try {
+ Object dmConnection = resolveDmConnection(connection);
+ ClassLoader driverClassLoader = classLoaderOf(dmConnection);
+ Class> dmConnectionClass = Class.forName("dm.jdbc.driver.DmdbConnection", true, driverClassLoader);
+ Method method = dmConnectionClass.getMethod("getExplainInfo", String.class);
+ return (String) method.invoke(dmConnection, sql);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getTargetException();
+ if (cause instanceof SQLException sqlException) {
+ throw sqlException;
+ }
+ throw new SQLException("DM getExplainInfo failed", cause);
+ } catch (ReflectiveOperationException e) {
+ throw new SQLException("DM JDBC driver does not support getExplainInfo", e);
+ }
+ }
+
+ private Object resolveDmConnection(Connection connection) throws SQLException, ClassNotFoundException {
+ Connection unwrapped = safeUnwrapConnection(connection);
+ ClassLoader driverClassLoader = classLoaderOf(unwrapped);
+ Class> dmConnectionClass = Class.forName("dm.jdbc.driver.DmdbConnection", true, driverClassLoader);
+
+ if (dmConnectionClass.isInstance(connection)) {
+ return connection;
+ }
+ if (dmConnectionClass.isInstance(unwrapped)) {
+ return unwrapped;
+ }
+
+ Object fromOuter = safeUnwrapAs(connection, dmConnectionClass);
+ if (fromOuter != null) {
+ return fromOuter;
+ }
+ Object fromInner = safeUnwrapAs(unwrapped, dmConnectionClass);
+ if (fromInner != null) {
+ return fromInner;
+ }
+ throw new SQLException("DM JDBC driver does not support getExplainInfo");
+ }
+
+ private Connection safeUnwrapConnection(Connection connection) {
+ try {
+ Connection unwrapped = connection.unwrap(Connection.class);
+ return unwrapped == null ? connection : unwrapped;
+ } catch (SQLException e) {
+ return connection;
+ }
+ }
+
+ private Object safeUnwrapAs(Connection connection, Class> dmConnectionClass) {
+ try {
+ return connection.unwrap(dmConnectionClass.asSubclass(Connection.class));
+ } catch (SQLException e) {
+ return null;
+ }
+ }
+
+ private ClassLoader classLoaderOf(Object target) {
+ ClassLoader loader = target.getClass().getClassLoader();
+ if (loader != null) {
+ return loader;
+ }
+ ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+ return contextLoader == null ? DMExplainClient.class.getClassLoader() : contextLoader;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java
index 7bac616c98..18a73bf648 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/DMMetaData.java
@@ -6,6 +6,7 @@
import ai.chat2db.plugin.dm.enums.type.DMDefaultValueEnum;
import ai.chat2db.plugin.dm.enums.type.DMIndexTypeEnum;
import ai.chat2db.plugin.dm.value.DMValueProcessor;
+import ai.chat2db.spi.ICommandExecutor;
import ai.chat2db.spi.IDbMetaData;
import ai.chat2db.spi.ISQLIdentifierProcessor;
import ai.chat2db.spi.ISqlBuilder;
@@ -297,6 +298,11 @@ public ISqlBuilder getSqlBuilder() {
return new DMSqlBuilder();
}
+ @Override
+ public ICommandExecutor getCommandExecutor() {
+ return DMCommandExecutor.INSTANCE;
+ }
+
@Override
public TableMeta getTableMeta(String databaseName, String schemaName, String tableName) {
return TableMeta.builder()
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/builder/DMSqlBuilder.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/builder/DMSqlBuilder.java
index 3df748d0e0..3894b9bb19 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/builder/DMSqlBuilder.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/builder/DMSqlBuilder.java
@@ -1,5 +1,7 @@
package ai.chat2db.plugin.dm.builder;
+import ai.chat2db.plugin.dm.parser.DMExecutableSql;
+import ai.chat2db.plugin.dm.parser.DMSqlParser;
import ai.chat2db.spi.constant.SQLConstants;
import ai.chat2db.plugin.dm.identifier.DMIdentifierProcessor;
@@ -32,6 +34,8 @@
import static ai.chat2db.plugin.dm.constant.DMSqlBuilderConstants.*;
public class DMSqlBuilder extends DefaultSqlBuilder {
+ private final DMSqlParser parser = new DMSqlParser();
+
@Override
public String quoteIdentifier(String identifier) {
return DMIdentifierProcessor.INSTANCE.quoteIdentifierAlways(identifier);
@@ -292,6 +296,12 @@ public String buildCreateSchema(Schema schema) {
return sqlBuilder.toString();
}
+ @Override
+ public String buildExplain(String sql) {
+ DMExecutableSql executableSql = parser.parseExecutableSql(sql);
+ return executableSql.isExplain() ? sql : SQLConstants.EXPLAIN_SQL_PREFIX + sql;
+ }
+
private static String quoteStringLiteral(String value) {
return DMIdentifierProcessor.INSTANCE.quoteStringLiteral(value);
}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMDialect.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMDialect.java
new file mode 100644
index 0000000000..db5f7cf57d
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMDialect.java
@@ -0,0 +1,83 @@
+package ai.chat2db.plugin.dm.parser;
+
+import ai.chat2db.spi.parser.dialect.AbstractSQLDialect;
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.rule.manager.DMRuleManager;
+import ai.chat2db.spi.IRuleManager;
+
+import java.util.Set;
+
+public class DMDialect extends AbstractSQLDialect {
+ private static final IRuleManager ORACLE_RULE_MANAGER = new DMRuleManager();
+
+ private static final Set ORACLE_COMMENT_TOKENS = Set.of(DMLexer.SINGLE_LINE_COMMENT, DMLexer.MULTI_LINE_COMMENT);
+
+ private static final Set SQL_START_KEYWORDS = Set.of(
+ "SELECT", "INSERT", "UPDATE", "DELETE", "ALTER", "DROP",
+ "ADMINISTER", "ANALYZE", "BEGIN", "COMMIT", "CREATE",
+ "DECLARE", "EXECUTE", "GRANT", "RENAME", "REVOKE",
+ "SAVEPOINT", "TRUNCATE", "LOCK", "NOAUDIT", "PURGE",
+ "EXPLAIN", "FLASHBACK", "ASSOCIATE", "AUDIT", "MERGE",
+ "ROLLBACK", "DISASSOCIATE", ";", "COMMENT",
+ "WITH", "EXIT", "PROMPT_MESSAGE", "SHOW", "WHENEVER",
+ "TIMING", "START_CMD"
+ );
+
+ @Override
+ public Set getCommentTokens() {
+ return ORACLE_COMMENT_TOKENS;
+ }
+
+ @Override
+ public boolean isComment(int tokenType) {
+ return getCommentTokens().contains(tokenType);
+ }
+
+ @Override
+ public Set getSqlStartKeywords() {
+ return SQL_START_KEYWORDS;
+ }
+
+
+ @Override
+ public Set getBlockHeaderPrefixes() {
+ Set blockHeaderPrefixes = super.getBlockHeaderPrefixes();
+ blockHeaderPrefixes.add("COMPOUND");
+ return blockHeaderPrefixes;
+ }
+
+ @Override
+ public Set getIndependentBlockHeaders() {
+ Set independentBlockHeaders = super.getIndependentBlockHeaders();
+ independentBlockHeaders.add("DECLARE");
+ return independentBlockHeaders;
+ }
+
+ @Override
+ public Set getDependentBlockHeaders() {
+ Set dependentBlockHeaders = super.getDependentBlockHeaders();
+ dependentBlockHeaders.add("PACKAGE");
+ return dependentBlockHeaders;
+ }
+
+ @Override
+ public Set getInnerBlockPrefix() {
+ Set innerBlockPrefix = super.getInnerBlockPrefix();
+ innerBlockPrefix.add("AS");
+ innerBlockPrefix.add("IS");
+ return innerBlockPrefix;
+ }
+
+ @Override
+ public Set getPackageBodyInnerBlockHeaders() {
+ Set packageBodyInnerBlockHeaders = super.getPackageBodyInnerBlockHeaders();
+ packageBodyInnerBlockHeaders.add("FUNCTION");
+ packageBodyInnerBlockHeaders.add("PROCEDURE");
+ return packageBodyInnerBlockHeaders;
+ }
+
+ @Override
+ public IRuleManager getRuleManager() {
+ return ORACLE_RULE_MANAGER;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutableSql.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutableSql.java
new file mode 100644
index 0000000000..59f2b3f264
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutableSql.java
@@ -0,0 +1,10 @@
+package ai.chat2db.plugin.dm.parser;
+
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+
+public record DMExecutableSql(String sqlType, String originalSql, String executableSql) {
+
+ public boolean isExplain() {
+ return SqlTypeEnum.EXPLAIN.name().equals(sqlType);
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutionVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutionVisitor.java
new file mode 100644
index 0000000000..649fec706f
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMExecutionVisitor.java
@@ -0,0 +1,49 @@
+package ai.chat2db.plugin.dm.parser;
+
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class DMExecutionVisitor extends DMParserBaseVisitor {
+
+ private final CommonTokenStream tokens;
+
+ private final String originalSql;
+
+ private DMExecutableSql result;
+
+ public DMExecutionVisitor(CommonTokenStream tokens, String originalSql) {
+ this.tokens = tokens;
+ this.originalSql = originalSql;
+ }
+
+ @Override
+ public DMExecutableSql visitSql_script(DMParser.Sql_scriptContext ctx) {
+ visitChildren(ctx);
+ return result == null ? new DMExecutableSql(SqlTypeEnum.OTHER.name(), originalSql, originalSql) : result;
+ }
+
+ @Override
+ public DMExecutableSql visitExplain_statement(DMParser.Explain_statementContext ctx) {
+ ParserRuleContext innerStatement = firstNonNull(
+ ctx.select_statement(),
+ ctx.update_statement(),
+ ctx.delete_statement(),
+ ctx.insert_statement(),
+ ctx.merge_statement());
+ String executableSql = innerStatement == null ? originalSql : tokens.getText(innerStatement.getSourceInterval());
+ result = new DMExecutableSql(SqlTypeEnum.EXPLAIN.name(), originalSql, executableSql);
+ return result;
+ }
+
+ private ParserRuleContext firstNonNull(ParserRuleContext... candidates) {
+ for (ParserRuleContext candidate : candidates) {
+ if (candidate != null) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMSqlParser.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMSqlParser.java
index 9b66a16999..59b1c02b2c 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMSqlParser.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/DMSqlParser.java
@@ -1,6 +1,487 @@
package ai.chat2db.plugin.dm.parser;
-import ai.chat2db.plugin.oracle.parser.OracleSqlParser;
+import ai.chat2db.spi.DefaultSQLFileSplitter;
+import ai.chat2db.spi.constant.SQLConstants;
+import ai.chat2db.community.domain.api.enums.parser.FileSizeUnitEnum;
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+import ai.chat2db.plugin.dm.parser.error.strategy.DMErrorStrategy;
+import ai.chat2db.plugin.dm.parser.visitor.DMCreateTableVisitor;
+import ai.chat2db.plugin.dm.parser.visitor.DMParserVisitor;
+import ai.chat2db.plugin.dm.parser.visitor.DMSimpleParserVisitor;
+import ai.chat2db.plugin.dm.parser.visitor.DMValidTableVisitor;
+import ai.chat2db.spi.parser.AbstractSqlParser;
+import ai.chat2db.community.domain.api.service.task.ITaskProgressListener;
+import ai.chat2db.spi.IRuleManager;
+import ai.chat2db.community.domain.api.service.db.ISqlBatchHandler;
+import ai.chat2db.spi.util.TokenUtil;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
-public class DMSqlParser extends OracleSqlParser {
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class DMSqlParser extends AbstractSqlParser {
+
+
+ public DMSqlParser() {
+ super(new DMParser(null), new DMDialect());
+ }
+
+ @Override
+ protected Lexer createLexer(CharStream charStream) {
+ return new DMLexer(charStream);
+ }
+
+
+ @Override
+ protected ParseTree parserRoot(DMParser parser) {
+ return parser.sql_script();
+ }
+
+ @Override
+ protected StatementContext createStatementContext(CommonTokenStream tokenStream, SqlTypeEnum sqlTypeEnum) {
+ StatementContext statementContext = new StatementContext(tokenStream);
+ statementContext.setRecoverSet(DMErrorStrategy.recoverSet);
+ DMParserBaseVisitor visitor = createVisitor(statementContext, sqlTypeEnum);
+ statementContext.setVisitor(visitor);
+ return statementContext;
+ }
+
+
+ private DMParserBaseVisitor createVisitor(StatementContext statementContext, SqlTypeEnum sqlTypeEnum) {
+ return switch (sqlTypeEnum) {
+ case SIMPLE -> new DMSimpleParserVisitor(statementContext);
+ case CREATE_TABLE -> new DMCreateTableVisitor(statementContext);
+ case VALID_TABLE -> new DMValidTableVisitor(statementContext);
+ default -> new DMParserVisitor(statementContext);
+ };
+ }
+
+ /**
+ * Classifies an executable statement for the DM command executor.
+ * Ordinary SQL only pays for a cheap lexer scan of the first keyword;
+ * a full ANTLR parse runs only when that keyword is {@code EXPLAIN}.
+ * Parse failures for EXPLAIN never silently fall back to JDBC.
+ */
+ public DMExecutableSql parseExecutableSql(String sql) {
+ if (StringUtils.isBlank(sql)) {
+ return new DMExecutableSql(SqlTypeEnum.OTHER.name(), sql, sql);
+ }
+ DMLexer lexer = new DMLexer(CharStreams.fromString(sql));
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ tokens.fill();
+ if (!isExplainLeadingKeyword(tokens)) {
+ return new DMExecutableSql(SqlTypeEnum.OTHER.name(), sql, sql);
+ }
+
+ DMParser parser = new DMParser(tokens);
+ parser.removeErrorListeners();
+ parser.setErrorHandler(new BailErrorStrategy());
+ try {
+ DMExecutableSql parsed = new DMExecutionVisitor(tokens, sql).visit(parser.sql_script());
+ if (parsed == null || !parsed.isExplain()) {
+ throw new IllegalArgumentException("Failed to parse DM EXPLAIN statement");
+ }
+ return parsed;
+ } catch (ParseCancellationException e) {
+ throw new IllegalArgumentException("Failed to parse DM EXPLAIN statement", e);
+ }
+ }
+
+ private boolean isExplainLeadingKeyword(CommonTokenStream tokens) {
+ for (Token token : tokens.getTokens()) {
+ if (token.getType() == Token.EOF) {
+ break;
+ }
+ if (!TokenUtil.hasValuableText(token) || dialect.isComment(token.getType())) {
+ continue;
+ }
+ return token.getType() == DMLexer.EXPLAIN;
+ }
+ return false;
+ }
+
+ @Override
+ public List parserSqlScript(String sql) {
+ Lexer lexer = getLexer(sql);
+ CommonTokenStream tokenStream = createTokenStream(lexer);
+ tokenStream.fill();
+ List tokens = tokenStream.getTokens();
+
+ List statements = new ArrayList<>();
+ IRuleManager ruleManager = dialect.getRuleManager();
+ Token firstToken = null;
+ Token lastToken = null;
+ Token firstKeyword = null;
+ Token lastKeyword = null;
+ boolean encounteredBlockHeaderPrefix = false;
+ SqlScriptBlockContext curBlock = null;
+ for (int i = 0; i < tokens.size(); i++) {
+ Token token = tokens.get(i);
+ int tokenType = token.getType();
+ if (tokenType == Token.EOF) {
+ break;
+ }
+ String currentTokenText = token.getText().trim();
+ if (!TokenUtil.hasValuableText(token)) {
+ continue;
+ } else if (dialect.isComment(tokenType)) {
+ continue;
+ } else if (tokenType == DMLexer.SOLIDUS && Objects.isNull(firstToken)) {
+ continue;
+ }
+ if (dialect.isStatementDelimiter(currentTokenText) && Objects.isNull(curBlock)) {
+ if (Objects.isNull(firstToken)) {
+ continue;
+ }
+ Statement statement = getStatement(tokenStream, firstToken, lastToken);
+ String originalSql = statement.getOriginalSql();
+ if (StringUtils.isNotBlank(originalSql)) {
+ String trimSql = originalSql.trim();
+ if (trimSql.endsWith("/")) {
+ String substring = trimSql.substring(0, trimSql.length() - 1);
+ if (Objects.nonNull(lastKeyword)) {
+ if ("END".equalsIgnoreCase(lastKeyword.getText())) {
+ substring += ";";
+ }
+ }
+ statement.setSql(substring);
+ }
+ }
+ statements.add(statement);
+ firstToken = null;
+ lastToken = null;
+ firstKeyword = null;
+ lastKeyword = null;
+ curBlock = null;
+ encounteredBlockHeaderPrefix = false;
+ continue;
+ }
+ if (Objects.isNull(firstToken)) {
+ firstToken = token;
+ }
+ if (currentTokenText.length() == 1) {
+ if (StringUtils.equalsAnyIgnoreCase(currentTokenText,
+ SQLConstants.OPEN_PARENTHESIS,
+ SQLConstants.OPEN_CURLY_BRACE,
+ SQLConstants.OPEN_SQUARE_BRACKET)) {
+ curBlock = new SqlScriptBlockContext(curBlock);
+ }
+ if (StringUtils.equalsAnyIgnoreCase(currentTokenText,
+ SQLConstants.CLOSE_PARENTHESIS,
+ SQLConstants.CLOSE_CURLY_BRACE,
+ SQLConstants.CLOSE_SQUARE_BRACKET)) {
+ if (Objects.nonNull(curBlock)) {
+ curBlock = curBlock.parent;
+ }
+ }
+ }
+ if (dialect.isBlockHeaderPrefix(currentTokenText)) {
+ encounteredBlockHeaderPrefix = true;
+ lastToken = token;
+ firstKeyword = token;
+ lastKeyword = token;
+ continue;
+ }
+
+ if (encounteredBlockHeaderPrefix) {
+ if (dialect.isDependentBlockHeader(currentTokenText)) {
+ boolean isBlockHeader = true;
+ if (Objects.nonNull(ruleManager)) {
+ isBlockHeader = ruleManager.matchRules(tokens, i);
+ }
+ if (isBlockHeader) {
+ curBlock = new SqlScriptBlockContext(curBlock, true);
+ lastToken = token;
+ lastKeyword = token;
+ encounteredBlockHeaderPrefix = false;
+ }
+ continue;
+ }
+ } else {
+ if (dialect.isIndependentBlockHeader(currentTokenText) && Objects.isNull(curBlock)) {
+ curBlock = new SqlScriptBlockContext(null, true);
+ if (Objects.isNull(firstKeyword)) {
+ firstKeyword = token;
+ }
+ lastToken = token;
+ lastKeyword = token;
+ continue;
+ }
+ if (Objects.nonNull(curBlock)
+ && dialect.isPackageBodyInnerBlockHeader(currentTokenText)
+ && Objects.nonNull(ruleManager)
+ && ruleManager.matchRules(tokens, i)) {
+ curBlock = new SqlScriptBlockContext(curBlock, true);
+ lastToken = token;
+ lastKeyword = token;
+ continue;
+
+ }
+ }
+
+ if (dialect.isBlockBegin(currentTokenText)) {
+ if (Objects.nonNull(lastToken) && dialect.isBlockEnd(lastToken.getText())) {
+ lastToken = token;
+ continue;
+ } else {
+ boolean isBlock = true;
+ if (Objects.nonNull(ruleManager)) {
+ isBlock = ruleManager.matchRules(tokens, i);
+ }
+ if (isBlock) {
+ if (Objects.nonNull(curBlock) && curBlock.isHeader) {
+ curBlock = curBlock.parent;
+ }
+ curBlock = new SqlScriptBlockContext(curBlock);
+ }
+ }
+ } else if (dialect.isBlockEnd(currentTokenText)) {
+ if (Objects.nonNull(curBlock)) {
+ curBlock = curBlock.parent;
+ }
+ }
+
+
+ lastToken = token;
+ if (dialect.isKeyword(currentTokenText)) {
+ if (Objects.isNull(firstKeyword)) {
+ firstKeyword = token;
+ }
+ lastKeyword = token;
+ }
+
+ }
+
+ return statements;
+ }
+
+ @Override
+ public int parserSqlScript(File file, ITaskProgressListener progressListener, ISqlBatchHandler sqlBatchHandler) {
+ try (DefaultSQLFileSplitter safeSQLFileSplitter = new DefaultSQLFileSplitter(10, FileSizeUnitEnum.MB, file, StandardCharsets.UTF_8)) {
+ String content;
+ Lexer lexer = new DMLexer(null);
+ CharStream charStream = null;
+ long bytesRead = 0L;
+ int statementCount = 0;
+ List currentTokens = new ArrayList<>(50);
+ IRuleManager ruleManager = dialect.getRuleManager();
+ while (StringUtils.isNotBlank(content = safeSQLFileSplitter.nextContent())) {
+ if (CollectionUtils.isNotEmpty(currentTokens)) {
+ String leftTokens = currentTokens.stream().map(Token::getText).collect(Collectors.joining());
+ charStream = CharStreams.fromString(leftTokens + content);
+ currentTokens.clear();
+ } else {
+ charStream = CharStreams.fromString(content);
+ }
+ lexer.setInputStream(charStream);
+ UnbufferedTokenStream tokenStream = createUnbufferedTokenStream(lexer);
+ boolean encounteredBlockHeaderPrefix = false;
+ boolean encounteredOpenParenthesis = false;
+ Token firstToken = null;
+ Token lastToken = null;
+ Token firstKeyword = null;
+ Token lastKeyword = null;
+ SqlScriptBlockContext curBlock = null;
+ while (tokenStream.LA(1) != Token.EOF) {
+ Token token = tokenStream.LT(1);
+ int tokenType = token.getType();
+ String text = token.getText();
+ bytesRead += text.getBytes().length;
+ String currentTokenText = text.trim();
+ if (!TokenUtil.hasValuableText(token) || dialect.isComment(tokenType)) {
+ if (Objects.nonNull(firstToken)) {
+ currentTokens.add(token);
+ }
+ tokenStream.consume();
+ continue;
+ } else if (tokenType == DMLexer.SOLIDUS && Objects.isNull(firstToken)) {
+ tokenStream.consume();
+ continue;
+ }
+ if (dialect.isStatementDelimiter(currentTokenText) && Objects.isNull(curBlock)) {
+ if (Objects.isNull(firstToken)) {
+ tokenStream.consume();
+ continue;
+ }
+ Statement statement = getStatement(currentTokens);
+ String originalSql = statement.getOriginalSql();
+ if (StringUtils.isNotBlank(originalSql)) {
+ String trimSql = originalSql.trim();
+ if (trimSql.endsWith("/")) {
+ String substring = trimSql.substring(0, trimSql.length() - 1);
+ if (Objects.nonNull(lastKeyword)) {
+ if ("END".equalsIgnoreCase(lastKeyword.getText())) {
+ substring += ";";
+ }
+ }
+ statement.setSql(substring);
+ }
+ }
+ sqlBatchHandler.handle(statement);
+ statementCount++;
+ firstToken = null;
+ lastToken = null;
+ firstKeyword = null;
+ lastKeyword = null;
+ curBlock = null;
+ encounteredBlockHeaderPrefix = false;
+ currentTokens.clear();
+ tokenStream.consume();
+ progressListener.onProgress(bytesRead, statementCount);
+ continue;
+ }
+ if (Objects.isNull(firstToken)) {
+ firstToken = token;
+ }
+ currentTokens.add(token);
+ if (currentTokenText.length() == 1) {
+ if (SQLConstants.OPEN_PARENTHESIS.equalsIgnoreCase(currentTokenText)) {
+ encounteredOpenParenthesis = true;
+ curBlock = new SqlScriptBlockContext(curBlock);
+
+ } else if (StringUtils.equalsAnyIgnoreCase(currentTokenText,
+ SQLConstants.OPEN_CURLY_BRACE,
+ SQLConstants.OPEN_SQUARE_BRACKET)) {
+ curBlock = new SqlScriptBlockContext(curBlock);
+ } else if (SQLConstants.CLOSE_PARENTHESIS.equalsIgnoreCase(currentTokenText)) {
+ encounteredOpenParenthesis = false;
+ if (Objects.nonNull(curBlock)) {
+ curBlock = curBlock.parent;
+ }
+ }
+ else if (StringUtils.equalsAnyIgnoreCase(currentTokenText,
+ SQLConstants.CLOSE_CURLY_BRACE,
+ SQLConstants.CLOSE_SQUARE_BRACKET)) {
+ if (Objects.nonNull(curBlock)) {
+ curBlock = curBlock.parent;
+ }
+ }
+ }
+ if (dialect.isBlockHeaderPrefix(currentTokenText)) {
+ encounteredBlockHeaderPrefix = true;
+ lastToken = token;
+ firstKeyword = token;
+ lastKeyword = token;
+ tokenStream.consume();
+ continue;
+ }
+
+ if (encounteredBlockHeaderPrefix) {
+ if (dialect.isDependentBlockHeader(currentTokenText)) {
+ boolean isBlockHeader = true;
+ if (Objects.nonNull(ruleManager)) {
+ isBlockHeader = ruleManager.matchRules(tokenStream);
+ }
+ if (isBlockHeader) {
+ curBlock = new SqlScriptBlockContext(curBlock, true);
+ lastToken = token;
+ lastKeyword = token;
+ encounteredBlockHeaderPrefix = false;
+ }
+ tokenStream.consume();
+ continue;
+ }
+ } else {
+ if (dialect.isIndependentBlockHeader(currentTokenText) && Objects.isNull(curBlock)) {
+ curBlock = new SqlScriptBlockContext(null, true);
+ if (Objects.isNull(firstKeyword)) {
+ firstKeyword = token;
+ }
+ lastToken = token;
+ lastKeyword = token;
+ tokenStream.consume();
+ continue;
+ }
+ if (Objects.nonNull(curBlock)
+ && dialect.isPackageBodyInnerBlockHeader(currentTokenText)
+ && Objects.nonNull(ruleManager)
+ && ruleManager.matchRules(tokenStream)) {
+ if (encounteredOpenParenthesis && DMLexer.PROCEDURE == tokenType) {
+ if (checkLastValuableToken(currentTokens, DMLexer.LEFT_PAREN)) {
+ lastToken = token;
+ lastKeyword = token;
+ tokenStream.consume();
+ continue;
+ }
+ } else {
+ curBlock = new SqlScriptBlockContext(curBlock, true);
+ lastToken = token;
+ lastKeyword = token;
+ tokenStream.consume();
+ continue;
+ }
+
+ }
+ }
+
+ if (dialect.isBlockBegin(currentTokenText)) {
+ if (Objects.nonNull(lastToken) && dialect.isBlockEnd(lastToken.getText())) {
+ lastToken = token;
+ tokenStream.consume();
+ continue;
+ } else {
+ boolean isBlock = true;
+ if (Objects.nonNull(ruleManager)) {
+ isBlock = ruleManager.matchRules(tokenStream);
+ }
+ if (isBlock) {
+ if (Objects.nonNull(curBlock) && curBlock.isHeader) {
+ curBlock = curBlock.parent;
+ }
+ curBlock = new SqlScriptBlockContext(curBlock);
+ }
+ }
+ } else if (dialect.isBlockEnd(currentTokenText)) {
+ if (Objects.nonNull(curBlock)) {
+ curBlock = curBlock.parent;
+ }
+ }
+
+
+ lastToken = token;
+ if (dialect.isKeyword(currentTokenText)) {
+ if (Objects.isNull(firstKeyword)) {
+ firstKeyword = token;
+ }
+ lastKeyword = token;
+ }
+ tokenStream.consume();
+ }
+ }
+ if (CollectionUtils.isNotEmpty(currentTokens)) {
+ Statement statement = getStatement(currentTokens);
+ sqlBatchHandler.handle(statement);
+ statementCount++;
+ currentTokens.clear();
+ progressListener.onProgress(bytesRead, statementCount);
+ }
+ sqlBatchHandler.flush();
+ return statementCount;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private boolean checkLastValuableToken(List currentTokens, Integer targetTokenType) {
+ for (int i = currentTokens.size() - 1; i > 0; i--) {
+ Token token = currentTokens.get(i);
+ if (TokenUtil.hasValuableText(token)) {
+ return token.getType() == targetTokenType;
+ }
+ }
+ return false;
+ }
}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMLexerBase.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMLexerBase.java
new file mode 100644
index 0000000000..1f0aed6db7
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMLexerBase.java
@@ -0,0 +1,20 @@
+package ai.chat2db.plugin.dm.parser.base;
+
+import org.antlr.v4.runtime.*;
+
+public abstract class DMLexerBase extends Lexer
+{
+ public DMLexerBase self;
+
+ public DMLexerBase(CharStream input)
+ {
+ super(input);
+ self = this;
+ }
+
+ protected boolean IsNewlineAtPos(int pos)
+ {
+ int la = _input.LA(pos);
+ return la == -1 || la == '\n';
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMParserBase.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMParserBase.java
new file mode 100644
index 0000000000..4eb7b4bd69
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/base/DMParserBase.java
@@ -0,0 +1,31 @@
+package ai.chat2db.plugin.dm.parser.base;
+
+import org.antlr.v4.runtime.*;
+
+public abstract class DMParserBase extends Parser
+{
+ private boolean _isVersion12 = true;
+ private boolean _isVersion10 = true;
+ public DMParserBase self;
+
+ public DMParserBase(TokenStream input) {
+ super(input);
+ self = this;
+ }
+
+ public boolean isVersion12() {
+ return _isVersion12;
+ }
+
+ public void setVersion12(boolean value) {
+ _isVersion12 = value;
+ }
+
+ public boolean isVersion10() {
+ return _isVersion10;
+ }
+
+ public void setVersion10(boolean value) {
+ _isVersion10 = value;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/error/strategy/DMErrorStrategy.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/error/strategy/DMErrorStrategy.java
new file mode 100644
index 0000000000..7990007e99
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/error/strategy/DMErrorStrategy.java
@@ -0,0 +1,29 @@
+package ai.chat2db.plugin.dm.parser.error.strategy;
+
+import ai.chat2db.spi.parser.error.strategy.BaseErrorStrategy;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import org.antlr.v4.runtime.misc.IntervalSet;
+
+public class DMErrorStrategy extends BaseErrorStrategy {
+
+ private static final int[] stmtBeginToken = new int[]{
+ DMParser.SELECT, DMParser.INSERT, DMParser.UPDATE,
+ DMParser.DELETE, DMParser.ALTER, DMParser.DROP,
+ DMParser.ADMINISTER, DMParser.ANALYZE, DMParser.BEGIN,
+ DMParser.COMMIT, DMParser.CREATE, DMParser.DECLARE,
+ DMParser.EXECUTE, DMParser.GRANT, DMParser.RENAME,
+ DMParser.REVOKE, DMParser.SAVEPOINT, DMParser.TRUNCATE,
+ DMParser.LOCK, DMParser.NOAUDIT, DMParser.PURGE,
+ DMParser.EXPLAIN, DMParser.FLASHBACK, DMParser.ASSOCIATE,
+ DMParser.AUDIT, DMParser.MERGE, DMParser.ROLLBACK,
+ DMParser.DISASSOCIATE, DMParser.SEMICOLON,
+ DMParser.COMMENT,DMParser.WITH,DMParser.EXIT,
+ DMParser.PROMPT_MESSAGE,DMParser.SHOW,DMParser.WHENEVER,
+ DMParser.TIMING,DMParser.START_CMD,
+
+ };
+
+ public static final IntervalSet recoverSet = new IntervalSet(stmtBeginToken);
+
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/listener/DMSelectListener.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/listener/DMSelectListener.java
new file mode 100644
index 0000000000..bba126c913
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/listener/DMSelectListener.java
@@ -0,0 +1,209 @@
+package ai.chat2db.plugin.dm.parser.listener;
+
+import ai.chat2db.community.domain.api.enums.parser.IdentifierTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.info.ColumnInfo;
+import ai.chat2db.community.domain.api.model.parser.info.TableInfo;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.community.domain.api.model.parser.token.Identifier;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseListener;
+import ai.chat2db.spi.util.SqlStringUtil;
+import ai.chat2db.spi.util.TokenUtil;
+import io.vavr.control.Try;
+import lombok.extern.slf4j.Slf4j;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import java.util.*;
+
+@Slf4j
+public class DMSelectListener extends DMParserBaseListener {
+
+
+ private final StatementContext context;
+
+ private Map tableAliasMap = new HashMap<>();
+
+ private Map columnAliasMap = new HashMap<>();
+
+ public DMSelectListener(StatementContext context) {
+ this.context = context;
+ }
+
+ public void parserSelectStatement(ParseTree parseTree) {
+ tableAliasMap = new HashMap<>();
+ columnAliasMap = new HashMap<>();
+ ParseTreeWalker parseTreeWalker = new ParseTreeWalker();
+ parseTreeWalker.walk(this, parseTree);
+ }
+
+
+ @Override
+ public void exitSelect_statement(DMParser.Select_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ currentStatement.setColumnAliasMap(columnAliasMap);
+ currentStatement.setTableAliasMap(tableAliasMap);
+ }
+
+ @Override
+ public void enterSelected_list(DMParser.Selected_listContext ctx) {
+ TerminalNode asterisk = ctx.ASTERISK();
+ if (Objects.nonNull(asterisk)) {
+ columnAliasMap.put(
+ ColumnInfo.builder().column("*").build(), null
+ );
+ }
+ }
+
+ @Override
+ public void enterSelect_list_elements(DMParser.Select_list_elementsContext ctx) {
+ TerminalNode asterisk = ctx.ASTERISK();
+ if (asterisk != null) {
+ String schema = null, table = null;
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ if (tableviewNameContext != null) {
+ String text = tableviewNameContext.getText();
+ String[] split = text.split("\\.");
+ int length = split.length;
+ if (length == 2) {
+ schema = SqlStringUtil.removeQuote(split[0]);
+ }
+ table = SqlStringUtil.removeQuote(split[length - 1]);
+ }
+ columnAliasMap.put(
+ ColumnInfo.builder().schema(schema).table(table).column("*").build(), null
+ );
+ return;
+ }
+ Try.of(() -> {
+ DMParser.Column_aliasContext columnAliasContext = ctx.column_alias();
+ DMParser.ExpressionContext expression = ctx.expression();
+ if (Objects.isNull(expression)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ Token database = null, table = null, column = null, alias = null;
+ String schemaText = null, tableText = null, columnText = null, aliasText = null;
+ ColumnInfo columnInfo;
+ List defaultChannelToken = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, expression);
+ int dotCount = defaultChannelToken.stream()
+ .mapToInt(token -> (int) token.getText().chars().filter(ch -> ch == '.').count())
+ .sum();
+ int defaultTokenSize = defaultChannelToken.size();
+ if (dotCount == 0) {
+ if (defaultTokenSize == 2) {
+ alias = defaultChannelToken.get(1);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 0) {
+ column = defaultChannelToken.get(0);
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+
+ } else if (dotCount == 1) {
+ if (defaultTokenSize - 1 == 3) {
+ alias = defaultChannelToken.get(3);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 2) {
+ table = defaultChannelToken.get(0);
+ column = defaultChannelToken.get(2);
+ tableText = SqlStringUtil.removeQuote(table.getText());
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+ } else if (dotCount == 2) {
+ if (defaultTokenSize - 2 == 4) {
+ alias = defaultChannelToken.get(5);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 4) {
+ database = defaultChannelToken.get(0);
+ table = defaultChannelToken.get(2);
+ column = defaultChannelToken.get(4);
+ schemaText = SqlStringUtil.removeQuote(database.getText());
+ tableText = SqlStringUtil.removeQuote(table.getText());
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+ }
+ if (Objects.isNull(alias) && Objects.nonNull(columnAliasContext)) {
+ alias = columnAliasContext.stop;
+ aliasText = SqlStringUtil.removeQuote(columnAliasContext.getText());
+ }
+
+ if (Objects.nonNull(column)) {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(columnText);
+ identifier.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier.setFirstToken(column);
+ identifier.setIdentifierSchema(schemaText);
+ identifier.setIdentifierTable(tableText);
+ columnInfo = ColumnInfo.builder().schema(schemaText).table(tableText).column(columnText).build();
+ if (Objects.nonNull(alias)) {
+ aliasText = alias.getText();
+ }
+ columnAliasMap.put(columnInfo, aliasText);
+ }
+ return null;
+
+ }).onFailure(e -> {
+ log.error("enter select list error", e);
+ });
+
+ }
+
+
+ @Override
+ public void enterTable_ref_aux(DMParser.Table_ref_auxContext ctx) {
+ Try.of(() -> {
+ DMParser.Table_ref_aux_internalContext tableRefAuxInternalContext = ctx.table_ref_aux_internal();
+ if (Objects.isNull(tableRefAuxInternalContext)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ Token database = null, table, alias = null;
+ String schemaText = null, tableText, aliasText = null;
+ TableInfo tableInfo;
+ DMParser.Table_aliasContext tableAliasContext = ctx.table_alias();
+ if (Objects.nonNull(tableAliasContext)) {
+ alias = tableAliasContext.stop;
+ aliasText = SqlStringUtil.removeQuote(tableAliasContext.getText());
+ }
+ List defaultChannelTokens = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, tableRefAuxInternalContext);
+ int dotCount = defaultChannelTokens.stream()
+ .mapToInt(token -> (int) token.getText().chars().filter(ch -> ch == '.').count())
+ .sum();
+ if (dotCount == 1) {
+ database = defaultChannelTokens.get(0);
+ schemaText = SqlStringUtil.removeQuote(database.getText());
+ }
+ table = defaultChannelTokens.get(defaultChannelTokens.size() - 1);
+ tableText = SqlStringUtil.removeQuote(table.getText());
+
+ if (Objects.nonNull(database)) {
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ }
+ tableInfo = TableInfo.builder().schema(schemaText).table(tableText).build();
+ if (Objects.nonNull(alias)) {
+ aliasText = alias.getText();
+ }
+ tableAliasMap.put(tableInfo, aliasText);
+ return null;
+ }).onFailure(e -> log.error("enter table ref aux error", e));
+ }
+
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/DMRulePredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/DMRulePredicate.java
new file mode 100644
index 0000000000..d572d2ef30
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/DMRulePredicate.java
@@ -0,0 +1,26 @@
+package ai.chat2db.plugin.dm.parser.rule;
+
+import ai.chat2db.spi.parser.AbstractRulePredicate;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+
+import java.util.List;
+
+public abstract class DMRulePredicate extends AbstractRulePredicate {
+
+
+ @Override
+ public boolean matches(List tokens, int currentIndex) {
+ return true;
+ }
+
+ @Override
+ public boolean needUpgradeBlock(List tokens, int currentIndex) {
+ return false;
+ }
+
+ @Override
+ public boolean matches(TokenStream tokenStream) {
+ return true;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/manager/DMRuleManager.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/manager/DMRuleManager.java
new file mode 100644
index 0000000000..118d7d6114
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/manager/DMRuleManager.java
@@ -0,0 +1,30 @@
+package ai.chat2db.plugin.dm.parser.rule.manager;
+
+import ai.chat2db.plugin.dm.parser.rule.predicate.*;
+import ai.chat2db.spi.parser.AbstractRuleManager;
+import ai.chat2db.spi.IRulePredicate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DMRuleManager extends AbstractRuleManager {
+
+
+ private static final Map RULE_PREDICATES = new HashMap<>();
+
+ static {
+ RULE_PREDICATES.put("PACKAGE", new DMCreatePackagePredicate(1));
+ RULE_PREDICATES.put("IF", new DMIfBlockPredicate(20));
+ RULE_PREDICATES.put("FUNCTION",new DMCreateFunctionPredicate(100));
+ RULE_PREDICATES.put("PROCEDURE", new DMCreateProcedurePredicate(100));
+ RULE_PREDICATES.put(("BEGIN"),new DMBeginBlockPredicate(1));
+ }
+
+
+ @Override
+ public Map getRules() {
+ return RULE_PREDICATES;
+ }
+
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMBeginBlockPredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMBeginBlockPredicate.java
new file mode 100644
index 0000000000..25079d3629
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMBeginBlockPredicate.java
@@ -0,0 +1,32 @@
+package ai.chat2db.plugin.dm.parser.rule.predicate;
+
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.rule.DMRulePredicate;
+import lombok.NoArgsConstructor;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+
+import java.util.List;
+import java.util.Set;
+
+@NoArgsConstructor
+public class DMBeginBlockPredicate extends DMRulePredicate {
+
+
+ public DMBeginBlockPredicate(int lookAheadTokens) {
+ this.lookaheadTokens = lookAheadTokens;
+ }
+
+ private static final Set MATCH_TOKENS = Set.of(DMLexer.BACKUP, DMLexer.RETURN);
+
+ @Override
+ public boolean matches(List tokens, int currentIndex) {
+ return getNthValidTokenWithMatch(tokens, currentIndex, 1, Set.of("BACKUP", "RETURN")) == -1;
+
+ }
+
+ @Override
+ public boolean matches(TokenStream tokenStream) {
+ return getNthValidTokenWithMatch(tokenStream, 1, MATCH_TOKENS) == -1;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateFunctionPredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateFunctionPredicate.java
new file mode 100644
index 0000000000..7e75870be6
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateFunctionPredicate.java
@@ -0,0 +1,92 @@
+package ai.chat2db.plugin.dm.parser.rule.predicate;
+
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.rule.DMRulePredicate;
+import ai.chat2db.spi.util.TokenUtil;
+import lombok.NoArgsConstructor;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+
+@NoArgsConstructor
+public class DMCreateFunctionPredicate extends DMRulePredicate {
+
+
+ public DMCreateFunctionPredicate(int lookAheadTokens) {
+ this.lookaheadTokens = lookAheadTokens;
+ }
+
+ @Override
+ public boolean matches(List tokens, int currentIndex) {
+ if (lookaheadTokens == 0) {
+ lookaheadTokens = tokens.size();
+ }
+ int lookaheadIndex = currentIndex + 1;
+ int valuableTokenFound = 0;
+
+ boolean encounteredIsOrAs = false;
+ while (lookaheadIndex < tokens.size() && valuableTokenFound < lookaheadTokens) {
+ Token token = tokens.get(lookaheadIndex);
+ if (!TokenUtil.hasValuableText(token)) {
+ lookaheadIndex++;
+ continue;
+ }
+ lookaheadIndex++;
+ valuableTokenFound++;
+ String text = token.getText().trim();
+ if (StringUtils.equalsAnyIgnoreCase(text, "IS", "AS")) {
+ encounteredIsOrAs = true;
+ } else if ("BEGIN".equalsIgnoreCase(text)) {
+ return true;
+ } else if (!encounteredIsOrAs && ";".equalsIgnoreCase(text)) {
+ return false;
+ } else if ("LANGUAGE".equalsIgnoreCase(text)) {
+ return false;
+ }
+
+ }
+ return false;
+
+ }
+
+ @Override
+ public boolean matches(TokenStream tokenStream) {
+
+ int valuableTokenFound = 0;
+ int offset = 2;
+ boolean encounteredIsOrAs = false;
+
+ while (valuableTokenFound < lookaheadTokens) {
+ Token token = tokenStream.LT(offset);
+ int tokenType = token.getType();
+ if (tokenType == Token.EOF) {
+ return false;
+ }
+
+ if (!TokenUtil.hasValuableText(token)) {
+ offset++;
+ continue;
+ }
+
+ valuableTokenFound++;
+ String text = token.getText().trim();
+ if (DMLexer.AS == tokenType || DMLexer.IS == tokenType) {
+ encounteredIsOrAs = true;
+ } else if (DMLexer.BEGIN == tokenType) {
+ return true;
+ } else if (!encounteredIsOrAs && DMLexer.SEMICOLON == tokenType) {
+ return false;
+ } else if (DMLexer.LANGUAGE == tokenType) {
+ return false;
+ }
+
+ offset++;
+ }
+
+ return false;
+ }
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreatePackagePredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreatePackagePredicate.java
new file mode 100644
index 0000000000..cc9890ae7c
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreatePackagePredicate.java
@@ -0,0 +1,38 @@
+package ai.chat2db.plugin.dm.parser.rule.predicate;
+
+import ai.chat2db.plugin.dm.parser.rule.DMRulePredicate;
+import ai.chat2db.spi.util.TokenUtil;
+import org.antlr.v4.runtime.Token;
+
+import java.util.List;
+
+public class DMCreatePackagePredicate extends DMRulePredicate {
+
+
+ public DMCreatePackagePredicate(int lookAheadTokens) {
+ this.lookaheadTokens = lookAheadTokens;
+ }
+
+
+ @Override
+ public boolean needUpgradeBlock(List tokens, int currentIndex) {
+ int lookaheadIndex = currentIndex + 1;
+ int valuableTokenFound = 0;
+ while (lookaheadIndex < tokens.size() && valuableTokenFound < lookaheadTokens) {
+ Token token = tokens.get(lookaheadIndex);
+ if (!TokenUtil.hasValuableText(token)) {
+ lookaheadIndex++;
+ continue;
+ }
+ valuableTokenFound++;
+ String text = token.getText().trim();
+ if (valuableTokenFound == 1 && "BODY".equalsIgnoreCase(text)) {
+ return false;
+ }
+ lookaheadIndex++;
+
+ }
+
+ return true;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateProcedurePredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateProcedurePredicate.java
new file mode 100644
index 0000000000..04b11d5cbe
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMCreateProcedurePredicate.java
@@ -0,0 +1,106 @@
+package ai.chat2db.plugin.dm.parser.rule.predicate;
+
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.rule.DMRulePredicate;
+import ai.chat2db.spi.util.TokenUtil;
+import lombok.NoArgsConstructor;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+@NoArgsConstructor
+public class DMCreateProcedurePredicate extends DMRulePredicate {
+
+
+ public DMCreateProcedurePredicate(int lookAheadTokens) {
+ this.lookaheadTokens = lookAheadTokens;
+ }
+
+
+ @Override
+ public boolean matches(List tokens, int currentIndex) {
+ if (lookaheadTokens == 0) {
+ lookaheadTokens = tokens.size();
+ }
+ int lookaheadIndex = currentIndex + 1;
+ int valuableTokenFound = 0;
+
+ boolean encounteredIsOrAs = false;
+ boolean previousIsLeftParen = getNthValidTokenWithMatchBackward(tokens, currentIndex, 1, "(") != -1;
+
+ while (lookaheadIndex < tokens.size() && valuableTokenFound < lookaheadTokens) {
+ Token token = tokens.get(lookaheadIndex);
+ if (!TokenUtil.hasValuableText(token)) {
+ lookaheadIndex++;
+ continue;
+ }
+ lookaheadIndex++;
+ valuableTokenFound++;
+ String text = token.getText().trim();
+ if (StringUtils.equalsAnyIgnoreCase(text, "IS", "AS")) {
+ encounteredIsOrAs = true;
+ } else if ("BEGIN".equalsIgnoreCase(text)) {
+ return true;
+ } else if (!encounteredIsOrAs && ";".equalsIgnoreCase(text)) {
+ return false;
+ } else if ("LANGUAGE".equalsIgnoreCase(text)) {
+ return false;
+ } else if ("EXTERNAL".equalsIgnoreCase(text)) {
+ return false;
+ } else if (previousIsLeftParen && ")".equalsIgnoreCase(text)) {
+ return false;
+ }
+
+ }
+ return false;
+
+ }
+
+
+ @Override
+ public boolean matches(TokenStream tokenStream) {
+
+ int offset = 2;
+ int valuableTokenFound = 0;
+
+ boolean encounteredIsOrAs = false;
+
+
+ while (valuableTokenFound < lookaheadTokens) {
+ Token token = tokenStream.LT(offset);
+ int tokenType = token.getType();
+ if (tokenType == Token.EOF) {
+ return false;
+ }
+ if (!TokenUtil.hasValuableText(token)) {
+ offset++;
+ continue;
+ }
+
+ valuableTokenFound++;
+ switch (tokenType) {
+ case DMLexer.IS:
+ case DMLexer.AS:
+ encounteredIsOrAs = true;
+ break;
+ case DMLexer.BEGIN:
+ return true;
+ case DMLexer.SEMICOLON:
+ if (!encounteredIsOrAs) {
+ return false;
+ }
+ break;
+ case DMLexer.LANGUAGE:
+ case DMLexer.EXTERNAL:
+ return false;
+ }
+
+ offset++;
+ }
+ return false;
+ }
+
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMIfBlockPredicate.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMIfBlockPredicate.java
new file mode 100644
index 0000000000..411fd74bbb
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/rule/predicate/DMIfBlockPredicate.java
@@ -0,0 +1,50 @@
+package ai.chat2db.plugin.dm.parser.rule.predicate;
+
+import ai.chat2db.plugin.dm.parser.base.DMLexer;
+import ai.chat2db.plugin.dm.parser.rule.DMRulePredicate;
+import ai.chat2db.spi.util.TokenUtil;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+
+import java.util.List;
+import java.util.Set;
+
+public class DMIfBlockPredicate extends DMRulePredicate {
+
+ public DMIfBlockPredicate(int lookAheadTokens) {
+ this.lookaheadTokens = lookAheadTokens;
+ }
+
+ private static final Set MATCH_TOKENS = Set.of(DMLexer.NOT, DMLexer.EXISTS);
+
+ @Override
+ public boolean matches(List tokens, int currentIndex) {
+ int lookaheadIndex = currentIndex + 1;
+ int valuableTokenFound = 0;
+
+ while (lookaheadIndex < tokens.size() && valuableTokenFound < lookaheadTokens) {
+ Token token = tokens.get(lookaheadIndex);
+ if (!TokenUtil.hasValuableText(token)) {
+ lookaheadIndex++;
+ continue;
+ }
+ valuableTokenFound++;
+ String text = token.getText().trim();
+ if ("THEN".equalsIgnoreCase(text)) {
+ return true;
+ } else if ("NOT".equalsIgnoreCase(text) && valuableTokenFound == 1) {
+ return false;
+ } else if ("EXISTS".equalsIgnoreCase(text) && valuableTokenFound == 1) {
+ return false;
+ }
+ lookaheadIndex++;
+
+ }
+ return false;
+ }
+
+ @Override
+ public boolean matches(TokenStream tokenStream) {
+ return getNthValidTokenWithMatch(tokenStream, 1, MATCH_TOKENS) == -1;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMCreateTableVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMCreateTableVisitor.java
new file mode 100644
index 0000000000..9a8be76d55
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMCreateTableVisitor.java
@@ -0,0 +1,13 @@
+package ai.chat2db.plugin.dm.parser.visitor;
+
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+
+public class DMCreateTableVisitor extends DMParserBaseVisitor {
+
+ private StatementContext context;
+
+ public DMCreateTableVisitor(StatementContext context) {
+ this.context = context;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
new file mode 100644
index 0000000000..1ce02754e1
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
@@ -0,0 +1,1075 @@
+package ai.chat2db.plugin.dm.parser.visitor;
+
+import ai.chat2db.community.domain.api.enums.parser.IdentifierTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.StatementValidTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.community.domain.api.model.parser.statement.insert.InsertRowTokenRange;
+import ai.chat2db.community.domain.api.model.parser.token.Identifier;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+import ai.chat2db.spi.util.InsertValueTokenUtil;
+import ai.chat2db.spi.util.SqlCommentUtil;
+import ai.chat2db.spi.util.SqlStringUtil;
+import ai.chat2db.spi.util.TokenUtil;
+import io.vavr.control.Try;
+import lombok.extern.slf4j.Slf4j;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+@Slf4j
+public class DMParserVisitor extends DMParserBaseVisitor {
+
+ private final StatementContext context;
+
+ public DMParserVisitor(StatementContext context) {
+ this.context = context;
+ }
+
+
+ @Override
+ public Void visitSql_script(DMParser.Sql_scriptContext ctx) {
+
+ List unitStatement = ctx.unit_statement();
+ TokenStream commonTokenStream = context.getCommonTokenStream();
+ for (int i = 0; i < unitStatement.size(); i++) {
+ DMParser.Unit_statementContext child = unitStatement.get(i);
+ Statement statement = new Statement();
+ int sqlCommentSearchStartIndex = 0;
+ if (i != 0) {
+ DMParser.Unit_statementContext unitStatementContext = unitStatement.get(i - 1);
+ if (Objects.nonNull(unitStatementContext)) {
+ sqlCommentSearchStartIndex = unitStatementContext.getStop().getTokenIndex();
+
+ }
+ }
+ int sqlCommentSearchEndIndex = child.getStart().getTokenIndex();
+ String sqlComment = SqlCommentUtil.searchSqlComment(sqlCommentSearchStartIndex, sqlCommentSearchEndIndex, commonTokenStream);
+ statement.setComment(sqlComment);
+ context.setCurrentStatement(statement);
+ statement.setStatementType(StatementValidTypeEnum.VALID.name());
+ String sql = "";
+ if (StringUtils.isNotBlank(sqlComment)) {
+ sql = "--" + " " + sqlComment + "\n";
+ }
+ sql += commonTokenStream.getText(child.getSourceInterval());
+ statement.setSql(sql);
+ statement.setFirstToken(child.getStart());
+ statement.setLastToken(child.getStop());
+ context.addStatement(statement);
+ visit(child);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
+ return super.visitExplain_statement(ctx);
+ }
+
+ @Override
+ public Void visitAlter_table(DMParser.Alter_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TABLE.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return null;
+ }
+
+ @Override
+ public Void visitSelect_statement(DMParser.Select_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.SELECT.name());
+ return super.visitSelect_statement(ctx);
+ }
+
+
+ @Override
+ public Void visitCreate_function_body(DMParser.Create_function_bodyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_FUNCTION.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_function_body(ctx);
+ }
+
+
+ @Override
+ public Void visitAnonymous_block(DMParser.Anonymous_blockContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ANONYMOUS_BLOCK.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitAnonymous_block(ctx);
+ }
+
+ @Override
+ public Void visitFunction_name(DMParser.Function_nameContext ctx) {
+ Try.run(() -> {
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.FUNCTION.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ Identifier identifier = new Identifier();
+ String functionText = SqlStringUtil.removeQuote(stop.getText());
+ identifier.setIdentifierName(functionText);
+ identifier.setIdentifierType(IdentifierTypeEnum.FUNCTION.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitFunction_name error", e);
+ });
+ return super.visitFunction_name(ctx);
+ }
+
+ @Override
+ public Void visitCreate_procedure_body(DMParser.Create_procedure_bodyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_PROCEDURE.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_procedure_body(ctx);
+ }
+
+ @Override
+ public Void visitProcedure_name(DMParser.Procedure_nameContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.PROCEDURE.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String procedureText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(procedureText);
+ identifier.setIdentifierType(IdentifierTypeEnum.PROCEDURE.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitProcedure_name error", e);
+ });
+ return super.visitProcedure_name(ctx);
+ }
+
+ @Override
+ public Void visitCreate_trigger(DMParser.Create_triggerContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_TRIGGER.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_trigger(ctx);
+ }
+
+ @Override
+ public Void visitTrigger_name(DMParser.Trigger_nameContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.TRIGGER.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String triggerText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(triggerText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TRIGGER.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitTrigger_name error", e);
+ });
+ return super.visitTrigger_name(ctx);
+ }
+
+ @Override
+ public Void visitCreate_index(DMParser.Create_indexContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_INDEX.name());
+ DMParser.Table_index_clauseContext tableIndexClauseContext = ctx.table_index_clause();
+ if (Objects.nonNull(tableIndexClauseContext)) {
+ DMParser.Tableview_nameContext tableviewNameContext = tableIndexClauseContext.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ }
+ return super.visitCreate_index(ctx);
+ }
+
+ @Override
+ public Void visitIndex_name(DMParser.Index_nameContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.INDEX.name(), start);
+ } else {
+ String tableText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(tableText,
+ IdentifierTypeEnum.TABLE.name(), start);
+ String indexText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(indexText);
+ identifier.setIdentifierType(IdentifierTypeEnum.INDEX.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierTable(tableText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitIndex_name error", e);
+ });
+ return super.visitIndex_name(ctx);
+ }
+
+ private void visitTableViewName(DMParser.Tableview_nameContext ctx, IdentifierTypeEnum identifierTypeEnum) {
+ Try.run(() -> {
+ if (Objects.nonNull(ctx)) {
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ identifierTypeEnum.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String tableViewText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableViewText);
+ identifier.setIdentifierType(identifierTypeEnum.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }
+ }).onFailure(e -> log.error("visitTableViewName error", e));
+
+ }
+
+
+ @Override
+ public Void visitCreate_user(DMParser.Create_userContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_USER.name());
+ DMParser.User_object_nameContext userObjectNameContext = ctx.user_object_name();
+ if (Objects.nonNull(userObjectNameContext)) {
+ Token start = userObjectNameContext.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.USER.name(), start);
+ }
+ return super.visitCreate_user(ctx);
+ }
+
+
+ @Override
+ public Void visitCreate_view(DMParser.Create_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_VIEW.name());
+ Try.run(() -> {
+ DMParser.Schema_nameContext schemaNameContext = ctx.schema_name();
+ String schemaText = null;
+ if (Objects.nonNull(schemaNameContext)) {
+ Token start = schemaNameContext.getStart();
+ schemaText = SqlStringUtil.removeQuote(start.getText());
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ }
+ DMParser.Id_expressionContext idExpressionContext = ctx.id_expression(0);
+ if (Objects.nonNull(idExpressionContext)) {
+ Token start = idExpressionContext.getStart();
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(SqlStringUtil.removeQuote(start.getText()));
+ identifier.setIdentifierType(IdentifierTypeEnum.VIEW.name());
+ identifier.setFirstToken(start);
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitCreate_view error", e);
+ });
+
+ return super.visitCreate_view(ctx);
+ }
+
+
+ @Override
+ public Void visitCreate_role(DMParser.Create_roleContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_ROLE.name());
+ DMParser.Role_nameContext roleNameContext = ctx.role_name();
+ if (Objects.nonNull(roleNameContext)) {
+ Token start = roleNameContext.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.ROLE.name(), start);
+ }
+ return super.visitCreate_role(ctx);
+ }
+
+ @Override
+ public Void visitCreate_table(DMParser.Create_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_TABLE.name());
+ return super.visitCreate_table(ctx);
+ }
+
+ @Override
+ public Void visitTable_name(DMParser.Table_nameContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.TABLE.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String tableText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitTable_name error", e);
+ });
+
+ return super.visitTable_name(ctx);
+ }
+
+ @Override
+ public Void visitSchema_name(DMParser.Schema_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ Token start = ctx.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ return super.visitSchema_name(ctx);
+ }
+
+ @Override
+ public Void visitCreate_database(DMParser.Create_databaseContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_DATABASE.name());
+ return super.visitCreate_database(ctx);
+ }
+
+ @Override
+ public Void visitDatabase_name(DMParser.Database_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ Token start = ctx.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ return super.visitDatabase_name(ctx);
+ }
+
+ @Override
+ public Void visitDrop_function(DMParser.Drop_functionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_FUNCTION.name());
+ return super.visitDrop_function(ctx);
+ }
+
+ @Override
+ public Void visitDrop_procedure(DMParser.Drop_procedureContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_PROCEDURE.name());
+ return super.visitDrop_procedure(ctx);
+ }
+
+ @Override
+ public Void visitDrop_role(DMParser.Drop_roleContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_ROLE.name());
+ DMParser.Role_nameContext roleNameContext = ctx.role_name();
+ if (Objects.nonNull(roleNameContext)) {
+ Token start = roleNameContext.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.ROLE.name(), start);
+ }
+ return super.visitDrop_role(ctx);
+ }
+
+ @Override
+ public Void visitDrop_trigger(DMParser.Drop_triggerContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_TRIGGER.name());
+ return super.visitDrop_trigger(ctx);
+ }
+
+
+ @Override
+ public Void visitDrop_user(DMParser.Drop_userContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_USER.name());
+ DMParser.User_object_nameContext userObjectNameContext = ctx.user_object_name();
+ if (Objects.nonNull(userObjectNameContext)) {
+ Token start = userObjectNameContext.getStart();
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.USER.name(), start);
+ }
+ return super.visitDrop_user(ctx);
+ }
+
+ @Override
+ public Void visitDrop_index(DMParser.Drop_indexContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_INDEX.name());
+ return super.visitDrop_index(ctx);
+ }
+
+
+ @Override
+ public Void visitDrop_table(DMParser.Drop_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_TABLE.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return super.visitDrop_table(ctx);
+ }
+
+
+ @Override
+ public Void visitDrop_view(DMParser.Drop_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_VIEW.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.VIEW);
+ return super.visitDrop_view(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_session(DMParser.Alter_sessionContext ctx) {
+
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ DMParser.Alter_session_set_clauseContext alterSessionSetClauseContext = ctx.alter_session_set_clause();
+ if (Objects.isNull(alterSessionSetClauseContext)
+ || alterSessionSetClauseContext.parameter_name().isEmpty()
+ || !"CURRENT_SCHEMA".equalsIgnoreCase(
+ alterSessionSetClauseContext.parameter_name(0).getText())) {
+ return super.visitAlter_session(ctx);
+ }
+ currentStatement.setType(SqlTypeEnum.SET_SCHEMA.name());
+ Try.run(() -> {
+ DMParser.Parameter_valueContext parameterValueContext = alterSessionSetClauseContext.parameter_value(0);
+ if (Objects.nonNull(parameterValueContext)) {
+ String schemaText = SqlStringUtil.removeQuote(parameterValueContext.getText());
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), parameterValueContext.getStart());
+ }
+ }).onFailure(e -> {
+ log.error("alter session error", e);
+ });
+ return super.visitAlter_session(ctx);
+ }
+
+ @Override
+ public Void visitDml_table_expression_clause(DMParser.Dml_table_expression_clauseContext ctx) {
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return super.visitDml_table_expression_clause(ctx);
+ }
+
+ @Override
+ public Void visitUpdate_statement(DMParser.Update_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.UPDATE.name());
+ return super.visitUpdate_statement(ctx);
+ }
+
+ @Override
+ public Void visitInsert_statement(DMParser.Insert_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.INSERT.name());
+ visitInsertValueMappings(context, ctx);
+ return super.visitInsert_statement(ctx);
+ }
+
+ static void visitInsertValueMappings(StatementContext context, DMParser.Insert_statementContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement) || Objects.isNull(ctx)) {
+ return;
+ }
+ DMParser.Single_table_insertContext singleTableInsertContext = ctx.single_table_insert();
+ if (Objects.isNull(singleTableInsertContext)) {
+ return;
+ }
+ DMParser.Insert_into_clauseContext insertIntoClauseContext = singleTableInsertContext.insert_into_clause();
+ DMParser.Values_clauseContext valuesClauseContext = singleTableInsertContext.values_clause();
+ if (Objects.isNull(insertIntoClauseContext)) {
+ return;
+ }
+ DMParser.Paren_column_listContext columnListContext = insertIntoClauseContext.paren_column_list();
+ DMParser.ExpressionsContext expressionsContext = Objects.nonNull(valuesClauseContext)
+ ? valuesClauseContext.expressions() : null;
+ if (Objects.isNull(columnListContext) || Objects.isNull(columnListContext.column_list())) {
+ return;
+ }
+ List columnContexts = columnListContext.column_list().column_name();
+ if (CollectionUtils.isEmpty(columnContexts)) {
+ return;
+ }
+ List rowTokenRanges = getInsertRowTokenRanges(context, ctx, valuesClauseContext);
+ if (rowTokenRanges.isEmpty()) {
+ return;
+ }
+ Token rowFirstToken = rowTokenRanges.get(0).getFirstToken();
+ Token rowLastToken = rowTokenRanges.get(0).getLastToken();
+ List valueContexts = Objects.nonNull(expressionsContext)
+ ? expressionsContext.expression() : List.of();
+
+ int columnSize = Math.min(columnContexts.size(), valueContexts.size());
+ for (int columnIndex = 0; columnIndex < columnSize; columnIndex++) {
+ DMParser.Column_nameContext columnContext = columnContexts.get(columnIndex);
+ DMParser.ExpressionContext expressionContext = valueContexts.get(columnIndex);
+ if (Objects.isNull(columnContext) || Objects.isNull(expressionContext)) {
+ continue;
+ }
+ currentStatement.addInsertValueMapping(columnContext.getStart(), columnContext.getStop(),
+ expressionContext.getStart(), expressionContext.getStop(), rowFirstToken, rowLastToken,
+ 0, columnIndex);
+ }
+ for (int columnIndex = columnSize; columnIndex < columnContexts.size(); columnIndex++) {
+ DMParser.Column_nameContext columnContext = columnContexts.get(columnIndex);
+ if (Objects.isNull(columnContext)) {
+ continue;
+ }
+ currentStatement.addUnmappedInsertColumn(columnContext.getStart(), columnContext.getStop(),
+ rowFirstToken, rowLastToken, 0, columnIndex);
+ }
+ for (int valueIndex = columnSize; valueIndex < valueContexts.size(); valueIndex++) {
+ DMParser.ExpressionContext expressionContext = valueContexts.get(valueIndex);
+ if (Objects.isNull(expressionContext)) {
+ continue;
+ }
+ currentStatement.addUnmappedInsertValue(expressionContext.getStart(), expressionContext.getStop(),
+ rowFirstToken, rowLastToken, 0, valueIndex);
+ }
+ }).onFailure(e -> log.error("oracle visitInsertValueMappings error", e));
+ }
+
+ private static List getInsertRowTokenRanges(StatementContext context,
+ DMParser.Insert_statementContext ctx,
+ DMParser.Values_clauseContext valuesClauseContext) {
+ List rowTokenRanges = List.of();
+ if (Objects.nonNull(valuesClauseContext)) {
+ Token rowFirstToken = Objects.nonNull(valuesClauseContext.LEFT_PAREN())
+ ? valuesClauseContext.LEFT_PAREN().getSymbol() : valuesClauseContext.getStart();
+ Token rowLastToken = Objects.nonNull(valuesClauseContext.RIGHT_PAREN())
+ ? valuesClauseContext.RIGHT_PAREN().getSymbol() : valuesClauseContext.getStop();
+ rowTokenRanges = InsertValueTokenUtil.singleRowTokenRange(rowFirstToken, rowLastToken);
+ }
+ if (!rowTokenRanges.isEmpty()) {
+ return rowTokenRanges;
+ }
+ return InsertValueTokenUtil.searchValuesRowTokenRanges(context, ctx.getStart(), ctx.getStop());
+ }
+
+ @Override
+ public Void visitDelete_statement(DMParser.Delete_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DELETE.name());
+ return super.visitDelete_statement(ctx);
+ }
+
+ @Override
+ public Void visitColumn_name(DMParser.Column_nameContext ctx) {
+ Try.of(() -> {
+ DMParser.IdentifierContext identifier = ctx.identifier();
+ if (Objects.isNull(identifier)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ List idExpressionContexts = ctx.id_expression();
+ if (CollectionUtils.isEmpty(idExpressionContexts)) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(identifier.getText()),
+ IdentifierTypeEnum.COLUMN.name(), identifier.getStart());
+ } else {
+ String schemaText = null, tableText = null, columnText = null;
+ Token databaseToken = null, tableToken = null, columnToken = null;
+ if (idExpressionContexts.size() == 2) {
+ databaseToken = identifier.getStart();
+ tableToken = idExpressionContexts.get(0).getStop();
+ columnToken = idExpressionContexts.get(1).getStop();
+ schemaText = SqlStringUtil.removeQuote(SqlStringUtil.removeQuote(identifier.getText()));
+ tableText = SqlStringUtil.removeQuote(SqlStringUtil.removeQuote(idExpressionContexts.get(0).getText()));
+ columnText = SqlStringUtil.removeQuote(SqlStringUtil.removeQuote(idExpressionContexts.get(1).getText()));
+ } else if (idExpressionContexts.size() == 1) {
+ tableToken = identifier.getStop();
+ columnToken = idExpressionContexts.get(0).getStop();
+ tableText = SqlStringUtil.removeQuote(SqlStringUtil.removeQuote(identifier.getText()));
+ columnText = SqlStringUtil.removeQuote(SqlStringUtil.removeQuote(idExpressionContexts.get(0).getText()));
+ }
+
+ if (Objects.nonNull(databaseToken)) {
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), databaseToken);
+ }
+ if (Objects.nonNull(tableToken)) {
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(tableText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier1.setFirstToken(tableToken);
+ identifier1.setIdentifierDatabase(schemaText);
+
+ currentStatement.addIdentifier(identifier1);
+ }
+ if (Objects.nonNull(columnToken)) {
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(columnText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier1.setFirstToken(columnToken);
+ identifier1.setIdentifierDatabase(schemaText);
+ identifier1.setIdentifierTable(tableText);
+ currentStatement.addIdentifier(identifier1);
+ }
+ }
+ return null;
+ }).onFailure(e -> {
+ log.error("visitColumn_name error", e);
+ });
+
+ return null;
+ }
+
+
+ @Override
+ public Void visitSelect_list_elements(DMParser.Select_list_elementsContext ctx) {
+ Try.of(() -> {
+ DMParser.Column_aliasContext columnAliasContext = ctx.column_alias();
+ DMParser.ExpressionContext expression = ctx.expression();
+ if (Objects.isNull(expression)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ Token database = null, table = null, column = null, alias = null;
+ String schemaText = null, tableText = null, columnText = null, aliasText = null;
+ List defaultChannelToken = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, expression);
+ int dotCount = defaultChannelToken.stream()
+ .mapToInt(token -> (int) token.getText().chars().filter(ch -> ch == '.').count())
+ .sum();
+ int defaultTokenSize = defaultChannelToken.size();
+ if (dotCount == 0) {
+ if (defaultTokenSize == 2) {
+ alias = defaultChannelToken.get(1);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 0) {
+ column = defaultChannelToken.get(0);
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+
+ } else if (dotCount == 1) {
+ if (defaultTokenSize - 1 == 3) {
+ alias = defaultChannelToken.get(3);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 2) {
+ table = defaultChannelToken.get(0);
+ column = defaultChannelToken.get(2);
+ tableText = SqlStringUtil.removeQuote(table.getText());
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+ } else if (dotCount == 2) {
+ if (defaultTokenSize - 2 == 4) {
+ alias = defaultChannelToken.get(5);
+ aliasText = SqlStringUtil.removeQuote(alias.getText());
+ }
+ if (defaultTokenSize > 4) {
+ database = defaultChannelToken.get(0);
+ table = defaultChannelToken.get(2);
+ column = defaultChannelToken.get(4);
+ schemaText = SqlStringUtil.removeQuote(database.getText());
+ tableText = SqlStringUtil.removeQuote(table.getText());
+ columnText = SqlStringUtil.removeQuote(column.getText());
+ }
+ }
+ if (Objects.isNull(alias) && Objects.nonNull(columnAliasContext)) {
+ alias = columnAliasContext.stop;
+ aliasText = SqlStringUtil.removeQuote(columnAliasContext.getText());
+ }
+ if (Objects.nonNull(database)) {
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ }
+ if (Objects.nonNull(table)) {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ if (Objects.nonNull(column)) {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(columnText);
+ identifier.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier.setFirstToken(column);
+ identifier.setIdentifierSchema(schemaText);
+ identifier.setIdentifierTable(tableText);
+ if (Objects.nonNull(alias)) {
+ identifier.setIdentifierAlias(aliasText);
+ identifier.setLastToken(alias);
+ }
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+
+ }).onFailure(e -> {
+ log.error("visit select list error", e);
+ });
+
+ return null;
+ }
+
+
+ @Override
+ public Void visitTable_ref_aux(DMParser.Table_ref_auxContext ctx) {
+ if (ctx.getStart().getText().equalsIgnoreCase("(")) {
+ return super.visitTable_ref_aux(ctx);
+ }
+ Try.of(() -> {
+ DMParser.Table_ref_aux_internalContext tableRefAuxInternalContext = ctx.table_ref_aux_internal();
+ if (Objects.isNull(tableRefAuxInternalContext)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ Token database = null, table, alias = null;
+ String schemaText = null, tableText, aliasText = null;
+ DMParser.Table_aliasContext tableAliasContext = ctx.table_alias();
+ if (Objects.nonNull(tableAliasContext)) {
+ alias = tableAliasContext.stop;
+ aliasText = SqlStringUtil.removeQuote(tableAliasContext.getText());
+ }
+ List defaultChannelTokens = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, tableRefAuxInternalContext);
+ int dotCount = defaultChannelTokens.stream()
+ .mapToInt(token -> (int) token.getText().chars().filter(ch -> ch == '.').count())
+ .sum();
+ if (dotCount == 1) {
+ database = defaultChannelTokens.get(0);
+ schemaText = SqlStringUtil.removeQuote(database.getText());
+ }
+ table = defaultChannelTokens.get(defaultChannelTokens.size() - 1);
+ tableText = SqlStringUtil.removeQuote(table.getText());
+
+ if (Objects.nonNull(database)) {
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ }
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+ identifier.setIdentifierSchema(schemaText);
+ if (Objects.nonNull(alias)) {
+ identifier.setIdentifierAlias(aliasText);
+ identifier.setLastToken(alias);
+ }
+ currentStatement.addIdentifier(identifier);
+ return null;
+ }).onFailure(e -> log.error("visit table ref aux error", e));
+ return null;
+ }
+
+ @Override
+ public Void visitJoin_on_part(DMParser.Join_on_partContext ctx) {
+ Try.of(() -> {
+ DMParser.ConditionContext condition = ctx.condition();
+ if (Objects.isNull(condition)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ List defaultChannelTokens = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, condition);
+ List> tokenLists = TokenUtil.splitTokensBySymbolText(defaultChannelTokens, "=");
+ for (List tokenList : tokenLists) {
+ int size = tokenList.size();
+ if (size == 5) {
+ Token database = tokenList.get(0);
+ Token table = tokenList.get(2);
+ Token column = tokenList.get(4);
+ String schemaText = SqlStringUtil.removeQuote(database.getText());
+ String tableText = SqlStringUtil.removeQuote(table.getText());
+ String columnText = SqlStringUtil.removeQuote(column.getText());
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(columnText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier1.setFirstToken(column);
+ identifier1.setIdentifierDatabase(schemaText);
+ identifier1.setIdentifierTable(tableText);
+ currentStatement.addIdentifier(identifier1);
+ } else if (size == 3) {
+ Token table = tokenList.get(0);
+ Token column = tokenList.get(2);
+ String tableText = SqlStringUtil.removeQuote(table.getText());
+ String columnText = SqlStringUtil.removeQuote(column.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+
+ currentStatement.addIdentifier(identifier);
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(columnText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier1.setFirstToken(column);
+ identifier1.setIdentifierTable(tableText);
+ currentStatement.addIdentifier(identifier1);
+ }
+ }
+
+ return null;
+ }).onFailure(e -> {
+ log.error("visit join on part error", e);
+ });
+
+ return null;
+ }
+
+
+ @Override
+ public Void visitColumn_definition(DMParser.Column_definitionContext ctx) {
+ Try.of(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ DMParser.Column_nameContext columnNameContext = ctx.column_name();
+ if (Objects.isNull(columnNameContext)) {
+ return null;
+ }
+ String columnName = context.getText(columnNameContext.getSourceInterval());
+ if (StringUtils.isBlank(columnName)) {
+ return null;
+ }
+ String[] split = columnName.split("\\.");
+ columnName = split[split.length - 1];
+ DMParser.DatatypeContext datatype = ctx.datatype();
+ if (Objects.isNull(datatype)) {
+ return null;
+ }
+ String datatypeText = datatype.getText();
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(SqlStringUtil.removeQuote(columnName));
+ identifier.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier.setIdentifierDataType(datatypeText);
+
+ currentStatement.addIdentifier(identifier);
+ return null;
+ }).onFailure(e -> log.error("visit column definition error", e));
+
+ return null;
+ }
+
+ @Override
+ public Void visitCall_statement(DMParser.Call_statementContext ctx) {
+ Try.of(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ DMParser.Routine_nameContext routineNameContext = ctx.routine_name(0);
+ if (Objects.isNull(routineNameContext)) {
+ return null;
+ }
+ Token start = routineNameContext.getStart();
+ Token stop = routineNameContext.getStop();
+ if (start.getTokenIndex() != stop.getTokenIndex()) {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(SqlStringUtil.removeQuote(start.getText()));
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ identifier.setFirstToken(start);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(SqlStringUtil.removeQuote(stop.getText()));
+ identifier.setIdentifierType(IdentifierTypeEnum.PROCEDURE.name());
+ identifier.setFirstToken(stop);
+ currentStatement.addIdentifier(identifier);
+ return null;
+ }).onFailure(e -> log.error("visit call statement error", e));
+ return null;
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
new file mode 100644
index 0000000000..b62a39ef05
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
@@ -0,0 +1,464 @@
+package ai.chat2db.plugin.dm.parser.visitor;
+
+import ai.chat2db.community.domain.api.enums.parser.IdentifierTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.StatementValidTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.community.domain.api.model.parser.token.Identifier;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+import ai.chat2db.spi.util.SqlCommentUtil;
+import ai.chat2db.spi.util.SqlStringUtil;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+
+import java.util.List;
+import java.util.Objects;
+
+
+public class DMSimpleParserVisitor extends DMParserBaseVisitor {
+
+ private final StatementContext context;
+
+ public DMSimpleParserVisitor(StatementContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public Void visitSql_script(DMParser.Sql_scriptContext ctx) {
+
+ List unitStatement = ctx.unit_statement();
+ TokenStream commonTokenStream = context.getCommonTokenStream();
+ for (int i = 0; i < unitStatement.size(); i++) {
+ DMParser.Unit_statementContext child = unitStatement.get(i);
+ Statement statement = new Statement();
+ int sqlCommentSearchStartIndex = 0;
+ if (i != 0) {
+ DMParser.Unit_statementContext unitStatementContext = unitStatement.get(i - 1);
+ if (Objects.nonNull(unitStatementContext)) {
+ sqlCommentSearchStartIndex = unitStatementContext.getStop().getTokenIndex();
+
+ }
+ }
+ int sqlCommentSearchEndIndex = child.getStart().getTokenIndex();
+ String sqlComment = SqlCommentUtil.searchSqlComment(sqlCommentSearchStartIndex, sqlCommentSearchEndIndex, commonTokenStream);
+ statement.setComment(sqlComment);
+ context.setCurrentStatement(statement);
+ statement.setStatementType(StatementValidTypeEnum.VALID.name());
+ statement.setSql(commonTokenStream.getText(child.getSourceInterval()));
+ statement.setFirstToken(child.getStart());
+ statement.setLastToken(child.getStop());
+ context.addStatement(statement);
+ visit(child);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitSelect_statement(DMParser.Select_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.SELECT.name());
+ return null;
+ }
+
+ @Override
+ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
+ return super.visitExplain_statement(ctx);
+ }
+
+ @Override
+ public Void visitAnonymous_block(DMParser.Anonymous_blockContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ANONYMOUS_BLOCK.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitAnonymous_block(ctx);
+ }
+
+ @Override
+ public Void visitCreate_function_body(DMParser.Create_function_bodyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_FUNCTION.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_function_body(ctx);
+ }
+
+ @Override
+ public Void visitCreate_procedure_body(DMParser.Create_procedure_bodyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_PROCEDURE.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_procedure_body(ctx);
+ }
+
+ @Override
+ public Void visitCreate_trigger(DMParser.Create_triggerContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_TRIGGER.name());
+ String sql = currentStatement.getSql();
+ if (!sql.endsWith(";")) {
+ sql = sql + ";";
+ currentStatement.setSql(sql);
+ }
+ return super.visitCreate_trigger(ctx);
+ }
+
+ @Override
+ public Void visitCreate_index(DMParser.Create_indexContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_INDEX.name());
+ return null;
+ }
+
+ @Override
+ public Void visitCreate_user(DMParser.Create_userContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_USER.name());
+ currentStatement.addIdentifier(new Identifier());
+ return null;
+ }
+
+
+ @Override
+ public Void visitCreate_view(DMParser.Create_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_VIEW.name());
+ DMParser.Schema_nameContext schemaNameContext = ctx.schema_name();
+ String schemaText;
+ if (Objects.nonNull(schemaNameContext)) {
+ Token start = schemaNameContext.getStart();
+ schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierSchema(schemaText);
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+
+ currentStatement.addIdentifier(identifier);
+ } else {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitCreate_role(DMParser.Create_roleContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_ROLE.name());
+ currentStatement.addIdentifier(new Identifier());
+ return null;
+ }
+
+ @Override
+ public Void visitCreate_table(DMParser.Create_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_TABLE.name());
+ DMParser.Schema_nameContext schemaNameContext = ctx.schema_name();
+ if (Objects.nonNull(schemaNameContext)) {
+ Token start = schemaNameContext.getStart();
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierSchema(schemaText);
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+
+ currentStatement.addIdentifier(identifier);
+ } else {
+ currentStatement.addIdentifier(new Identifier());
+ }
+ return super.visitCreate_table(ctx);
+ }
+
+ @Override
+ public Void visitCreate_database(DMParser.Create_databaseContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_DATABASE.name());
+ currentStatement.addIdentifier(new Identifier());
+ return null;
+ }
+
+
+ @Override
+ public Void visitDrop_function(DMParser.Drop_functionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_FUNCTION.name());
+ return super.visitDrop_function(ctx);
+ }
+
+ @Override
+ public Void visitDrop_procedure(DMParser.Drop_procedureContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_PROCEDURE.name());
+ return super.visitDrop_procedure(ctx);
+ }
+
+ @Override
+ public Void visitDrop_role(DMParser.Drop_roleContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_ROLE.name());
+ return null;
+ }
+
+ @Override
+ public Void visitDrop_trigger(DMParser.Drop_triggerContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_TRIGGER.name());
+ return super.visitDrop_trigger(ctx);
+ }
+
+
+ @Override
+ public Void visitDrop_user(DMParser.Drop_userContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_USER.name());
+ currentStatement.addIdentifier(new Identifier());
+
+ return null;
+ }
+
+ @Override
+ public Void visitDrop_index(DMParser.Drop_indexContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_INDEX.name());
+ return null;
+ }
+
+ @Override
+ public Void visitDrop_table(DMParser.Drop_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_TABLE.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext);
+ return null;
+ }
+
+
+ @Override
+ public Void visitDrop_view(DMParser.Drop_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_VIEW.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext);
+ return super.visitDrop_view(ctx);
+ }
+
+ @Override
+ public Void visitAlter_session(DMParser.Alter_sessionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ DMParser.Alter_session_set_clauseContext alterSessionSetClauseContext = ctx.alter_session_set_clause();
+ if (Objects.isNull(alterSessionSetClauseContext)
+ || alterSessionSetClauseContext.parameter_name().isEmpty()
+ || !"CURRENT_SCHEMA".equalsIgnoreCase(
+ alterSessionSetClauseContext.parameter_name(0).getText())) {
+ return super.visitAlter_session(ctx);
+ }
+ currentStatement.setType(SqlTypeEnum.SET_SCHEMA.name());
+ DMParser.Parameter_valueContext parameterValueContext = alterSessionSetClauseContext.parameter_value(0);
+ if (Objects.nonNull(parameterValueContext)) {
+ Identifier identifier = new Identifier();
+ String schemaText = SqlStringUtil.removeQuote(parameterValueContext.getText());
+ identifier.setIdentifierSchema(schemaText);
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitUpdate_statement(DMParser.Update_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.UPDATE.name());
+ return null;
+ }
+
+ @Override
+ public Void visitInsert_statement(DMParser.Insert_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.INSERT.name());
+ DMParserVisitor.visitInsertValueMappings(context, ctx);
+ return null;
+ }
+
+ @Override
+ public Void visitDelete_statement(DMParser.Delete_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DELETE.name());
+ return null;
+ }
+
+ private void visitTableViewName(DMParser.Tableview_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ if (Objects.nonNull(ctx)) {
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() != stop.getTokenIndex()) {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ } else {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+
+ }
+ }
+
+ @Override
+ public Void visitFunction_name(DMParser.Function_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() != stop.getTokenIndex()) {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ } else {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitProcedure_name(DMParser.Procedure_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() != stop.getTokenIndex()) {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ } else {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitTrigger_name(DMParser.Trigger_nameContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() != stop.getTokenIndex()) {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ identifier.setIdentifierSchema(schemaText);
+ currentStatement.addIdentifier(identifier);
+ } else {
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierType(IdentifierTypeEnum.SCHEMA.name());
+ currentStatement.addIdentifier(identifier);
+ }
+ return null;
+ }
+
+
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
new file mode 100644
index 0000000000..364f558c31
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
@@ -0,0 +1,1207 @@
+package ai.chat2db.plugin.dm.parser.visitor;
+
+import ai.chat2db.community.domain.api.enums.parser.IdentifierTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.community.domain.api.enums.parser.StatementValidTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.community.domain.api.model.parser.statement.StatementContext;
+import ai.chat2db.community.domain.api.model.parser.token.Identifier;
+import ai.chat2db.plugin.dm.parser.base.DMParser;
+import ai.chat2db.plugin.dm.parser.base.DMParserBaseVisitor;
+import ai.chat2db.plugin.dm.parser.listener.DMSelectListener;
+import ai.chat2db.spi.util.SqlStringUtil;
+import ai.chat2db.spi.util.TokenUtil;
+import io.vavr.control.Try;
+import lombok.extern.slf4j.Slf4j;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+
+import java.util.List;
+import java.util.Objects;
+
+@Slf4j
+public class DMValidTableVisitor extends DMParserBaseVisitor {
+
+ private final StatementContext context;
+
+ private final DMSelectListener oracleSelectListener;
+
+ public DMValidTableVisitor(StatementContext context) {
+ this.context = context;
+ oracleSelectListener = new DMSelectListener(context);
+ }
+
+
+ @Override
+ public Void visitSql_script(DMParser.Sql_scriptContext ctx) {
+
+ List unitStatement = ctx.unit_statement();
+ TokenStream commonTokenStream = context.getCommonTokenStream();
+ for (DMParser.Unit_statementContext child : unitStatement) {
+ Statement statement = new Statement();
+ context.setCurrentStatement(statement);
+ statement.setStatementType(StatementValidTypeEnum.VALID.name());
+ statement.setSql(commonTokenStream.getText(child.getSourceInterval()));
+ statement.setFirstToken(child.getStart());
+ statement.setLastToken(child.getStop());
+ context.addStatement(statement);
+ visit(child);
+ }
+ return null;
+ }
+
+
+ @Override
+ public Void visitTruncate_table(DMParser.Truncate_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.TRUNCATE_TABLE.name());
+ return null;
+ }
+
+ @Override
+ public Void visitDml_table_expression_clause(DMParser.Dml_table_expression_clauseContext ctx) {
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return super.visitDml_table_expression_clause(ctx);
+ }
+ @Override
+ public Void visitDrop_table(DMParser.Drop_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_TABLE.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return super.visitDrop_table(ctx);
+ }
+
+ @Override
+ public Void visitCreate_table(DMParser.Create_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_TABLE.name());
+ return null;
+ }
+
+ @Override
+ public Void visitTable_name(DMParser.Table_nameContext ctx) {
+ Try.run(() -> {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ IdentifierTypeEnum.TABLE.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String tableText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }).onFailure(e -> {
+ log.error("visitTable_name error", e);
+ });
+
+ return super.visitTable_name(ctx);
+ }
+
+ @Override
+ public Void visitTable_ref_aux(DMParser.Table_ref_auxContext ctx) {
+ Try.of(() -> {
+ DMParser.Table_ref_aux_internalContext tableRefAuxInternalContext = ctx.table_ref_aux_internal();
+ if (Objects.isNull(tableRefAuxInternalContext)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ Token database = null, table, alias = null;
+ String schemaText = null, tableText, aliasText = null;
+ DMParser.Table_aliasContext tableAliasContext = ctx.table_alias();
+ if (Objects.nonNull(tableAliasContext)) {
+ alias = tableAliasContext.stop;
+ aliasText = SqlStringUtil.removeQuote(tableAliasContext.getText());
+ }
+ List defaultChannelTokens = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, tableRefAuxInternalContext);
+ int dotCount = defaultChannelTokens.stream()
+ .mapToInt(token -> (int) token.getText().chars().filter(ch -> ch == '.').count())
+ .sum();
+ if (dotCount == 1) {
+ database = defaultChannelTokens.get(0);
+ schemaText = SqlStringUtil.removeQuote(database.getText());
+ }
+ table = defaultChannelTokens.get(defaultChannelTokens.size() - 1);
+ tableText = SqlStringUtil.removeQuote(table.getText());
+
+ if (Objects.nonNull(database)) {
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ }
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+ identifier.setIdentifierSchema(schemaText);
+ if (Objects.nonNull(alias)) {
+ identifier.setIdentifierAlias(aliasText);
+ identifier.setLastToken(alias);
+ }
+ currentStatement.addIdentifier(identifier);
+ return null;
+ }).onFailure(e -> log.error("visit table ref aux error", e));
+
+ return null;
+ }
+
+ @Override
+ public Void visitJoin_on_part(DMParser.Join_on_partContext ctx) {
+ Try.of(() -> {
+ DMParser.ConditionContext condition = ctx.condition();
+ if (Objects.isNull(condition)) {
+ return null;
+ }
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ CommonTokenStream commonTokenStream = context.getCommonTokenStream();
+ List defaultChannelTokens = TokenUtil.getParserRuleTokensOnDefault(commonTokenStream, condition);
+ List> tokenLists = TokenUtil.splitTokensBySymbolText(defaultChannelTokens, "=");
+ for (List tokenList : tokenLists) {
+ int size = tokenList.size();
+ if (size == 5) {
+ Token database = tokenList.get(0);
+ Token table = tokenList.get(2);
+ Token column = tokenList.get(4);
+ String schemaText = SqlStringUtil.removeQuote(database.getText());
+ String tableText = SqlStringUtil.removeQuote(table.getText());
+ String columnText = SqlStringUtil.removeQuote(column.getText());
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), database);
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(columnText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier1.setFirstToken(column);
+ identifier1.setIdentifierDatabase(schemaText);
+ identifier1.setIdentifierTable(tableText);
+ currentStatement.addIdentifier(identifier1);
+ } else if (size == 3) {
+ Token table = tokenList.get(0);
+ Token column = tokenList.get(2);
+ String tableText = SqlStringUtil.removeQuote(table.getText());
+ String columnText = SqlStringUtil.removeQuote(column.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableText);
+ identifier.setIdentifierType(IdentifierTypeEnum.TABLE.name());
+ identifier.setFirstToken(table);
+
+ currentStatement.addIdentifier(identifier);
+ Identifier identifier1 = new Identifier();
+ identifier1.setIdentifierName(columnText);
+ identifier1.setIdentifierType(IdentifierTypeEnum.COLUMN.name());
+ identifier1.setFirstToken(column);
+ identifier1.setIdentifierTable(tableText);
+ currentStatement.addIdentifier(identifier1);
+ }
+ }
+
+ return null;
+ }).onFailure(e -> {
+ log.error("visit join on part error", e);
+ });
+
+ return null;
+ }
+
+
+ @Override
+ public Void visitAlter_view(DMParser.Alter_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_VIEW.name());
+ return super.visitAlter_view(ctx);
+ }
+
+ @Override
+ public Void visitAlter_analytic_view(DMParser.Alter_analytic_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_ANALYTIC_VIEW.name());
+ return super.visitAlter_analytic_view(ctx);
+ }
+
+ @Override
+ public Void visitAlter_attribute_dimension(DMParser.Alter_attribute_dimensionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_ATTRIBUTE_DIMENSION.name());
+ return super.visitAlter_attribute_dimension(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_audit_policy(DMParser.Alter_audit_policyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_AUDIT_POLICY.name());
+ return super.visitAlter_audit_policy(ctx);
+ }
+
+ @Override
+ public Void visitAlter_cluster(DMParser.Alter_clusterContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_CLUSTER.name());
+ return super.visitAlter_cluster(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_database(DMParser.Alter_databaseContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_DATABASE.name());
+ return super.visitAlter_database(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_database_link(DMParser.Alter_database_linkContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_DATABASE_LINK.name());
+ return super.visitAlter_database_link(ctx);
+ }
+
+ @Override
+ public Void visitAlter_dimension(DMParser.Alter_dimensionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_DIMENSION.name());
+ return super.visitAlter_dimension(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_diskgroup(DMParser.Alter_diskgroupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_DISKGROUP.name());
+ return super.visitAlter_diskgroup(ctx);
+ }
+
+ @Override
+ public Void visitAlter_flashback_archive(DMParser.Alter_flashback_archiveContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_FLASHBACK_ARCHIVE.name());
+ return super.visitAlter_flashback_archive(ctx);
+ }
+
+ @Override
+ public Void visitAlter_function(DMParser.Alter_functionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_FUNCTION.name());
+ return super.visitAlter_function(ctx);
+ }
+
+ @Override
+ public Void visitAlter_hierarchy(DMParser.Alter_hierarchyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_HIERARCHY.name());
+ return super.visitAlter_hierarchy(ctx);
+ }
+
+ @Override
+ public Void visitAlter_index(DMParser.Alter_indexContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_INDEX.name());
+ return super.visitAlter_index(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_inmemory_join_group(DMParser.Alter_inmemory_join_groupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_INMEMORY_JOIN_GROUP.name());
+ return super.visitAlter_inmemory_join_group(ctx);
+ }
+
+ @Override
+ public Void visitAlter_java(DMParser.Alter_javaContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_JAVA.name());
+ return super.visitAlter_java(ctx);
+ }
+
+ @Override
+ public Void visitAlter_library(DMParser.Alter_libraryContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_LIBRARY.name());
+ return super.visitAlter_library(ctx);
+ }
+
+ @Override
+ public Void visitAlter_lockdown_profile(DMParser.Alter_lockdown_profileContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_LOCKDOWN_PROFILE.name());
+ return super.visitAlter_lockdown_profile(ctx);
+ }
+
+ @Override
+ public Void visitAlter_materialized_view(DMParser.Alter_materialized_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_MATERIALIZED_VIEW.name());
+ return super.visitAlter_materialized_view(ctx);
+ }
+
+ @Override
+ public Void visitAlter_materialized_view_log(DMParser.Alter_materialized_view_logContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_MATERIALIZED_VIEW_LOG.name());
+ return super.visitAlter_materialized_view_log(ctx);
+ }
+
+ @Override
+ public Void visitAlter_materialized_zonemap(DMParser.Alter_materialized_zonemapContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_MATERIALIZED_ZONEMAP.name());
+ return super.visitAlter_materialized_zonemap(ctx);
+ }
+
+ @Override
+ public Void visitAlter_operator(DMParser.Alter_operatorContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_OPERATOR.name());
+ return super.visitAlter_operator(ctx);
+ }
+
+ @Override
+ public Void visitAlter_outline(DMParser.Alter_outlineContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_OUTLINE.name());
+ return super.visitAlter_outline(ctx);
+ }
+
+ @Override
+ public Void visitAlter_package(DMParser.Alter_packageContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_PACKAGE.name());
+ return super.visitAlter_package(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_pmem_filestore(DMParser.Alter_pmem_filestoreContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_PMEM_FILESTORE.name());
+ return super.visitAlter_pmem_filestore(ctx);
+ }
+
+ @Override
+ public Void visitAlter_procedure(DMParser.Alter_procedureContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_PROCEDURE.name());
+ return super.visitAlter_procedure(ctx);
+ }
+
+
+ @Override
+ public Void visitAlter_resource_cost(DMParser.Alter_resource_costContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_RESOURCE_COST.name());
+ return super.visitAlter_resource_cost(ctx);
+ }
+
+ @Override
+ public Void visitAlter_role(DMParser.Alter_roleContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_ROLE.name());
+ return super.visitAlter_role(ctx);
+ }
+
+ @Override
+ public Void visitAlter_rollback_segment(DMParser.Alter_rollback_segmentContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_ROLLBACK_SEGMENT.name());
+ return super.visitAlter_rollback_segment(ctx);
+ }
+
+ @Override
+ public Void visitAlter_sequence(DMParser.Alter_sequenceContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_SEQUENCE.name());
+ return super.visitAlter_sequence(ctx);
+ }
+
+ @Override
+ public Void visitAlter_session(DMParser.Alter_sessionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_SESSION.name());
+ return super.visitAlter_session(ctx);
+ }
+
+ @Override
+ public Void visitAlter_synonym(DMParser.Alter_synonymContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_SYNONYM.name());
+ return super.visitAlter_synonym(ctx);
+ }
+
+ @Override
+ public Void visitAlter_table(DMParser.Alter_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TABLE.name());
+ DMParser.Tableview_nameContext tableviewNameContext = ctx.tableview_name();
+ visitTableViewName(tableviewNameContext, IdentifierTypeEnum.TABLE);
+ return null;
+ }
+ private void visitTableViewName(DMParser.Tableview_nameContext ctx, IdentifierTypeEnum identifierTypeEnum) {
+ Try.run(() -> {
+ if (Objects.nonNull(ctx)) {
+ Token start = ctx.getStart();
+ Token stop = ctx.getStop();
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return;
+ }
+ if (start.getTokenIndex() == stop.getTokenIndex()) {
+ currentStatement.addIdentifier(SqlStringUtil.removeQuote(start.getText()),
+ identifierTypeEnum.name(), start);
+ } else {
+ String schemaText = SqlStringUtil.removeQuote(start.getText());
+
+ currentStatement.addIdentifier(schemaText,
+ IdentifierTypeEnum.SCHEMA.name(), start);
+ String tableViewText = SqlStringUtil.removeQuote(stop.getText());
+ Identifier identifier = new Identifier();
+ identifier.setIdentifierName(tableViewText);
+ identifier.setIdentifierType(identifierTypeEnum.name());
+ identifier.setFirstToken(stop);
+ identifier.setIdentifierSchema(schemaText);
+
+ currentStatement.addIdentifier(identifier);
+ }
+ }
+ }).onFailure(e -> log.error("visitTableViewName error", e));
+
+ }
+
+
+ @Override
+ public Void visitAlter_tablespace(DMParser.Alter_tablespaceContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TABLESPACE.name());
+ return super.visitAlter_tablespace(ctx);
+ }
+
+ @Override
+ public Void visitAlter_tablespace_set(DMParser.Alter_tablespace_setContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TABLESPACE_SET.name());
+ return super.visitAlter_tablespace_set(ctx);
+ }
+
+ @Override
+ public Void visitAlter_trigger(DMParser.Alter_triggerContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TRIGGER.name());
+ return super.visitAlter_trigger(ctx);
+ }
+
+ @Override
+ public Void visitAlter_type(DMParser.Alter_typeContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_TYPE.name());
+ return super.visitAlter_type(ctx);
+ }
+
+ @Override
+ public Void visitAlter_user(DMParser.Alter_userContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.ALTER_USER.name());
+ return super.visitAlter_user(ctx);
+ }
+
+
+ @Override
+ public Void visitCall_statement(DMParser.Call_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CALL_PROC.name());
+ return super.visitCall_statement(ctx);
+ }
+
+ @Override
+ public Void visitCreate_analytic_view(DMParser.Create_analytic_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_ANALYTIC_VIEW.name());
+ return super.visitCreate_analytic_view(ctx);
+ }
+
+ @Override
+ public Void visitCreate_attribute_dimension(DMParser.Create_attribute_dimensionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_ATTRIBUTE_DIMENSION.name());
+ return super.visitCreate_attribute_dimension(ctx);
+ }
+
+ @Override
+ public Void visitCreate_audit_policy(DMParser.Create_audit_policyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_AUDIT_POLICY.name());
+ return super.visitCreate_audit_policy(ctx);
+ }
+
+ @Override
+ public Void visitCreate_cluster(DMParser.Create_clusterContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_CLUSTER.name());
+ return super.visitCreate_cluster(ctx);
+ }
+
+ @Override
+ public Void visitCreate_context(DMParser.Create_contextContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_CONTEXT.name());
+ return super.visitCreate_context(ctx);
+ }
+
+ @Override
+ public Void visitCreate_controlfile(DMParser.Create_controlfileContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_CONTROLFILE.name());
+ return super.visitCreate_controlfile(ctx);
+ }
+
+ @Override
+ public Void visitCreate_diskgroup(DMParser.Create_diskgroupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_DISKGROUP.name());
+ return super.visitCreate_diskgroup(ctx);
+ }
+
+ @Override
+ public Void visitCreate_edition(DMParser.Create_editionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_EDITION.name());
+ return super.visitCreate_edition(ctx);
+ }
+
+ @Override
+ public Void visitCreate_flashback_archive(DMParser.Create_flashback_archiveContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_FLASHBACK_ARCHIVE.name());
+ return super.visitCreate_flashback_archive(ctx);
+ }
+
+ @Override
+ public Void visitCreate_hierarchy(DMParser.Create_hierarchyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_HIERARCHY.name());
+ return super.visitCreate_hierarchy(ctx);
+ }
+
+ @Override
+ public Void visitCreate_inmemory_join_group(DMParser.Create_inmemory_join_groupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_INMEMORY_JOIN_GROUP.name());
+ return super.visitCreate_inmemory_join_group(ctx);
+ }
+
+ @Override
+ public Void visitCreate_java(DMParser.Create_javaContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_JAVA.name());
+ return super.visitCreate_java(ctx);
+ }
+
+ @Override
+ public Void visitCreate_library(DMParser.Create_libraryContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_LIBRARY.name());
+ return super.visitCreate_library(ctx);
+ }
+
+ @Override
+ public Void visitCreate_lockdown_profile(DMParser.Create_lockdown_profileContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_LOCKDOWN_PROFILE.name());
+ return super.visitCreate_lockdown_profile(ctx);
+ }
+
+ @Override
+ public Void visitCreate_operator(DMParser.Create_operatorContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_OPERATOR.name());
+ return super.visitCreate_operator(ctx);
+ }
+
+ @Override
+ public Void visitCreate_outline(DMParser.Create_outlineContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_OUTLINE.name());
+ return super.visitCreate_outline(ctx);
+ }
+
+ @Override
+ public Void visitCreate_restore_point(DMParser.Create_restore_pointContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_RESTORE_POINT.name());
+ return super.visitCreate_restore_point(ctx);
+ }
+
+ @Override
+ public Void visitCreate_spfile(DMParser.Create_spfileContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.CREATE_SPFILE.name());
+ return super.visitCreate_spfile(ctx);
+ }
+
+ @Override
+ public Void visitDrop_analytic_view(DMParser.Drop_analytic_viewContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_ANALYTIC_VIEW.name());
+ return super.visitDrop_analytic_view(ctx);
+ }
+
+ @Override
+ public Void visitDrop_attribute_dimension(DMParser.Drop_attribute_dimensionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_ATTRIBUTE_DIMENSION.name());
+ return super.visitDrop_attribute_dimension(ctx);
+ }
+
+ @Override
+ public Void visitDrop_audit_policy(DMParser.Drop_audit_policyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_AUDIT_POLICY.name());
+ return super.visitDrop_audit_policy(ctx);
+ }
+
+ @Override
+ public Void visitDrop_cluster(DMParser.Drop_clusterContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_CLUSTER.name());
+ return super.visitDrop_cluster(ctx);
+ }
+
+ @Override
+ public Void visitDrop_context(DMParser.Drop_contextContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_CONTEXT.name());
+ return super.visitDrop_context(ctx);
+ }
+
+ @Override
+ public Void visitDrop_directory(DMParser.Drop_directoryContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_DIRECTORY.name());
+ return super.visitDrop_directory(ctx);
+ }
+
+ @Override
+ public Void visitDrop_diskgroup(DMParser.Drop_diskgroupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_DISKGROUP.name());
+ return super.visitDrop_diskgroup(ctx);
+ }
+
+ @Override
+ public Void visitDrop_edition(DMParser.Drop_editionContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_EDITION.name());
+ return super.visitDrop_edition(ctx);
+ }
+
+ @Override
+ public Void visitDrop_flashback_archive(DMParser.Drop_flashback_archiveContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_FLASHBACK_ARCHIVE.name());
+ return super.visitDrop_flashback_archive(ctx);
+ }
+
+ @Override
+ public Void visitDrop_hierarchy(DMParser.Drop_hierarchyContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_HIERARCHY.name());
+ return super.visitDrop_hierarchy(ctx);
+ }
+
+ @Override
+ public Void visitDrop_inmemory_join_group(DMParser.Drop_inmemory_join_groupContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_INMEMORY_JOIN_GROUP.name());
+ return super.visitDrop_inmemory_join_group(ctx);
+ }
+
+ @Override
+ public Void visitDrop_java(DMParser.Drop_javaContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_JAVA.name());
+ return super.visitDrop_java(ctx);
+ }
+
+ @Override
+ public Void visitDrop_library(DMParser.Drop_libraryContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_LIBRARY.name());
+ return super.visitDrop_library(ctx);
+ }
+
+ @Override
+ public Void visitDrop_lockdown_profile(DMParser.Drop_lockdown_profileContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_LOCKDOWN_PROFILE.name());
+ return super.visitDrop_lockdown_profile(ctx);
+ }
+
+ @Override
+ public Void visitDrop_operator(DMParser.Drop_operatorContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_OPERATOR.name());
+ return super.visitDrop_operator(ctx);
+ }
+
+ @Override
+ public Void visitDrop_outline(DMParser.Drop_outlineContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_OUTLINE.name());
+ return super.visitDrop_outline(ctx);
+ }
+
+ @Override
+ public Void visitDrop_restore_point(DMParser.Drop_restore_pointContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DROP_RESTORE_POINT.name());
+ return super.visitDrop_restore_point(ctx);
+ }
+
+ @Override
+ public Void visitComment_on_column(DMParser.Comment_on_columnContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.COMMENT_ON_COLUMN.name());
+ return super.visitComment_on_column(ctx);
+ }
+
+ @Override
+ public Void visitComment_on_table(DMParser.Comment_on_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.COMMENT_ON_TABLE.name());
+ return super.visitComment_on_table(ctx);
+ }
+
+ @Override
+ public Void visitComment_on_materialized(DMParser.Comment_on_materializedContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.COMMENT_ON_MATERIALIZED.name());
+ return super.visitComment_on_materialized(ctx);
+ }
+
+ @Override
+ public Void visitDisassociate_statistics(DMParser.Disassociate_statisticsContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DISASSOCIATE_STATISTICS.name());
+ return super.visitDisassociate_statistics(ctx);
+ }
+
+ @Override
+ public Void visitFlashback_table(DMParser.Flashback_tableContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.FLASHBACK_TABLE.name());
+ return super.visitFlashback_table(ctx);
+ }
+
+ @Override
+ public Void visitGrant_statement(DMParser.Grant_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.GRANT.name());
+ return super.visitGrant_statement(ctx);
+ }
+
+ @Override
+ public Void visitNoaudit_statement(DMParser.Noaudit_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.NOAUDIT.name());
+ return super.visitNoaudit_statement(ctx);
+ }
+
+ @Override
+ public Void visitPurge_statement(DMParser.Purge_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.PURGE.name());
+ return super.visitPurge_statement(ctx);
+ }
+
+ @Override
+ public Void visitRename_object(DMParser.Rename_objectContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.RENAME.name());
+ return super.visitRename_object(ctx);
+ }
+
+ @Override
+ public Void visitRevoke_statement(DMParser.Revoke_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.REVOKE.name());
+ return super.visitRevoke_statement(ctx);
+ }
+
+ @Override
+ public Void visitTruncate_cluster(DMParser.Truncate_clusterContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.TRUNCATE_CLUSTER.name());
+ return super.visitTruncate_cluster(ctx);
+ }
+
+ @Override
+ public Void visitUnified_auditing(DMParser.Unified_auditingContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.UNIFIED_AUDIT.name());
+ return super.visitUnified_auditing(ctx);
+ }
+
+ @Override
+ public Void visitSelect_statement(DMParser.Select_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.SELECT.name());
+ oracleSelectListener.parserSelectStatement(ctx);
+ return null;
+ }
+
+ @Override
+ public Void visitInsert_statement(DMParser.Insert_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.INSERT.name());
+ return super.visitInsert_statement(ctx);
+ }
+
+ @Override
+ public Void visitDelete_statement(DMParser.Delete_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.DELETE.name());
+ return super.visitDelete_statement(ctx);
+ }
+
+ @Override
+ public Void visitUpdate_statement(DMParser.Update_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.UPDATE.name());
+ return super.visitUpdate_statement(ctx);
+ }
+
+ @Override
+ public Void visitMerge_statement(DMParser.Merge_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.MERGE.name());
+ return super.visitMerge_statement(ctx);
+ }
+
+ @Override
+ public Void visitLock_table_statement(DMParser.Lock_table_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.LOCK_TABLES.name());
+ return super.visitLock_table_statement(ctx);
+ }
+
+
+ @Override
+ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
+ Statement currentStatement = context.getCurrentStatement();
+ if (Objects.isNull(currentStatement)) {
+ return null;
+ }
+ currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
+ return super.visitExplain_statement(ctx);
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMCommandExecutorTest.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMCommandExecutorTest.java
new file mode 100644
index 0000000000..723bf42ca9
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMCommandExecutorTest.java
@@ -0,0 +1,638 @@
+package ai.chat2db.plugin.dm;
+
+import ai.chat2db.community.domain.api.model.result.ExecuteResponse;
+import ai.chat2db.community.domain.api.model.result.ExecutionContext;
+import ai.chat2db.community.domain.api.model.result.ResultCell;
+import ai.chat2db.community.domain.api.config.DriverConfig;
+import ai.chat2db.community.domain.api.enums.plugin.SqlTypeEnum;
+import ai.chat2db.community.domain.api.model.sql.SqlExecuteRequest;
+import ai.chat2db.community.domain.api.model.sql.SimpleSqlStatement;
+import ai.chat2db.community.tools.util.I18nUtils;
+import ai.chat2db.community.domain.api.service.db.ISqlExecutionCancellation;
+import ai.chat2db.community.domain.api.service.db.ISqlExecutionResultConsumer;
+import ai.chat2db.community.domain.api.service.db.ISqlExecutionStatementListener;
+import ai.chat2db.spi.IPlugin;
+import ai.chat2db.spi.model.datasource.ConnectInfo;
+import ai.chat2db.spi.sql.Chat2DBContext;
+import ai.chat2db.spi.sql.ConnectionPool;
+import ai.chat2db.plugin.dm.builder.DMSqlBuilder;
+import ai.chat2db.plugin.dm.parser.DMExecutableSql;
+import ai.chat2db.plugin.dm.parser.DMSqlParser;
+import dm.jdbc.driver.DmdbConnection;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceResolvable;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class DMCommandExecutorTest {
+
+ private static final long DATA_SOURCE_ID = 2762L;
+
+ private IPlugin previousPlugin;
+
+ private boolean contextBound;
+
+ @BeforeAll
+ static void setUpI18n() throws Exception {
+ Field field = I18nUtils.class.getDeclaredField("messageSourceStatic");
+ field.setAccessible(true);
+ field.set(null, new MessageSource() {
+ @Override
+ public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
+ return defaultMessage == null ? code : defaultMessage;
+ }
+
+ @Override
+ public String getMessage(String code, Object[] args, Locale locale) {
+ return code;
+ }
+
+ @Override
+ public String getMessage(MessageSourceResolvable resolvable, Locale locale) {
+ String[] codes = resolvable.getCodes();
+ return codes == null || codes.length == 0 ? resolvable.getDefaultMessage() : codes[0];
+ }
+ });
+ }
+
+ @AfterEach
+ void tearDownContext() {
+ if (!contextBound) {
+ return;
+ }
+ Chat2DBContext.removeContext();
+ ConnectionPool.removeConnection(DATA_SOURCE_ID);
+ if (previousPlugin == null) {
+ Chat2DBContext.PLUGIN_MAP.remove("DM");
+ } else {
+ Chat2DBContext.PLUGIN_MAP.put("DM", previousPlugin);
+ }
+ contextBound = false;
+ previousPlugin = null;
+ }
+
+ @Test
+ void allDmSqlShouldUseDmExecutor() {
+ assertSame(DMCommandExecutor.INSTANCE, new DMMetaData().getCommandExecutor());
+ }
+
+ @Test
+ void parserShouldRecognizeExplicitExplainAndReturnInnerSql() {
+ DMExecutableSql result = new DMSqlParser().parseExecutableSql("EXPLAIN SELECT * FROM SYSOBJECTS");
+
+ assertTrue(result.isExplain());
+ assertEquals("SELECT * FROM SYSOBJECTS", result.executableSql());
+ }
+
+ @Test
+ void builderShouldNotAddExplainTwice() {
+ assertEquals("EXPLAIN SELECT * FROM SYSOBJECTS",
+ new DMSqlBuilder().buildExplain("EXPLAIN SELECT * FROM SYSOBJECTS"));
+ }
+
+ @Test
+ void ordinarySqlShouldDelegateToDefaultExecutionInsideDmExecutor() throws Exception {
+ try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:dm_executor_select")) {
+ putContext(connection);
+ List results = executeMulti("SELECT 1 AS ID", connection);
+
+ assertEquals(1, results.size());
+ assertEquals("1", results.get(0).getDataList().get(0).get(0).getValue());
+ }
+ }
+
+ @Test
+ void explainShouldCallGetExplainInfoInsteadOfPreparedStatementExecute() throws Exception {
+ Connection connection = dmExplainConnection();
+
+ List results = executeMulti("EXPLAIN SELECT * FROM SYSOBJECTS", connection);
+
+ assertEquals(1, results.size());
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", results.get(0).getDataList().get(0).get(0).getValue());
+ }
+
+ @Test
+ void explainButtonShouldBuildExplainOnceAndCallGetExplainInfo() throws Exception {
+ Connection connection = dmExplainConnection();
+ putContext(connection);
+
+ SqlExecuteRequest request = request("SELECT * FROM SYSOBJECTS");
+ request.setExplain(true);
+
+ List results = DMCommandExecutor.INSTANCE.execute(request);
+
+ assertEquals(1, results.size());
+ assertEquals(ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum.EXPLAIN.name(),
+ results.get(0).getSqlType());
+ // non-streaming path will add row-number, so plan is in the 2nd column.
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", results.get(0).getDataList().get(0).get(1).getValue());
+ assertNotNull(results.get(0).getExecutionMetrics());
+ assertNotNull(results.get(0).getExecutionMetrics().getTotalDurationMs());
+ assertEquals(1, results.get(0).getExecutionMetrics().getFetchedRowCount());
+ }
+
+ @Test
+ void explainButtonStreamingShouldKeepSqlTypeExplain() throws Exception {
+ Connection connection = dmExplainConnection();
+ putContext(connection);
+
+ SqlExecuteRequest request = request("SELECT * FROM SYSOBJECTS");
+ request.setExplain(true);
+ CapturingResultConsumer consumer = new CapturingResultConsumer();
+
+ DMCommandExecutor.INSTANCE.executeStreaming(request, consumer, null, () -> false);
+
+ assertEquals(1, consumer.resultStartedCount);
+ assertEquals(0, consumer.resultStartedRowCount);
+ assertEquals(1, consumer.rowsEventCount);
+ assertEquals(1, consumer.receivedRows.size());
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", consumer.receivedRows.get(0).get(1).getValue());
+ assertEquals(1, consumer.resultFinished.size());
+ assertEquals(ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum.EXPLAIN.name(),
+ consumer.resultFinished.get(0).getSqlType());
+ assertNotNull(consumer.resultFinished.get(0).getExecutionMetrics());
+ assertEquals(1, consumer.resultFinished.get(0).getExecutionMetrics().getFetchedRowCount());
+ }
+
+ @Test
+ void shouldStreamExplainPlanWithRowNumber() throws Exception {
+ Connection connection = dmExplainConnection();
+ putContext(connection);
+
+ SqlExecuteRequest request = request("EXPLAIN SELECT * FROM SYSOBJECTS");
+ CapturingResultConsumer consumer = new CapturingResultConsumer();
+
+ DMCommandExecutor.INSTANCE.executeStreaming(request, consumer, null, () -> false);
+
+ // Outer executeStreaming owns the single resultFinished; publishMaterializedQueryResult must not duplicate it.
+ assertEquals(1, consumer.resultFinished.size());
+ assertEquals(1, consumer.resultStartedCount);
+ assertEquals(0, consumer.resultStartedRowCount);
+ assertEquals(1, consumer.rowsEventCount);
+ assertEquals(1, consumer.receivedRows.size());
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", consumer.receivedRows.get(0).get(1).getValue());
+
+ ExecuteResponse response = consumer.resultFinished.get(0);
+ assertEquals(ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum.EXPLAIN.name(), response.getSqlType());
+ assertTrue(response.getHeaderList().size() >= 2);
+ assertEquals("Execution Plan", response.getHeaderList().get(response.getHeaderList().size() - 1).getName());
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", response.getDataList().get(0).get(1).getValue());
+ assertNotNull(response.getExecutionMetrics());
+ assertNotNull(response.getExecutionMetrics().getTotalDurationMs());
+ assertEquals(1, response.getExecutionMetrics().getFetchedRowCount());
+ }
+
+ @Test
+ void ordinarySqlShouldSkipFullAntlrParseAtExecutorEntry() {
+ DMExecutableSql parsed = new DMSqlParser().parseExecutableSql("SELECT 1 AS ID FROM DUAL");
+
+ assertTrue(!parsed.isExplain());
+ assertEquals("SELECT 1 AS ID FROM DUAL", parsed.executableSql());
+ }
+
+ @Test
+ void invalidExplainShouldNotFallBackToJdbcPath() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new DMSqlParser().parseExecutableSql("EXPLAIN PLAN FOR SELECT 1 FROM DUAL"));
+ }
+
+ @Test
+ void explainShouldWorkThroughStatementGuardAndConnectionOnlyWrapper() throws Exception {
+ List guardedSql = new ArrayList<>();
+ Connection dmdb = dmExplainConnection();
+ Connection poolWrapped = connectionOnlyWrapper(dmdb);
+ putContext(poolWrapped);
+
+ try (Chat2DBContext.StatementGuardScope ignored = Chat2DBContext.bindStatementGuard(guardedSql::add)) {
+ SqlExecuteRequest request = request("EXPLAIN SELECT * FROM SYSOBJECTS");
+ List results = DMCommandExecutor.INSTANCE.execute(request);
+
+ assertEquals(1, results.size());
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", results.get(0).getDataList().get(0).get(1).getValue());
+ assertTrue(guardedSql.contains("EXPLAIN SELECT * FROM SYSOBJECTS"));
+ }
+ }
+
+ @Test
+ void shouldHandleMultiStatementsWithExplainAndNormalSelect() throws Exception {
+ try (Connection h2Connection = DriverManager.getConnection("jdbc:h2:mem:dm_multi_statement")) {
+ Connection hybrid = dmHybridConnection(h2Connection);
+ putContext(hybrid);
+
+ SqlExecuteRequest request = request("EXPLAIN SELECT * FROM SYSOBJECTS; SELECT 1 AS ID");
+ request.setExplain(false);
+ request.setSingle(false);
+
+ List results = DMCommandExecutor.INSTANCE.execute(request);
+
+ // Should return at least 2 execute results: one EXPLAIN plan and one SELECT result.
+ assertTrue(results.size() >= 2);
+
+ String explainPlan = results.stream()
+ .flatMap(r -> r.getDataList().stream())
+ .filter(row -> row.size() >= 2 && "plan for: SELECT * FROM SYSOBJECTS".equals(row.get(1).getValue()))
+ .map(row -> row.get(1).getValue())
+ .findFirst()
+ .orElse(null);
+ assertEquals("plan for: SELECT * FROM SYSOBJECTS", explainPlan);
+
+ String selectValue = results.stream()
+ .flatMap(r -> r.getDataList().stream())
+ .filter(row -> row.size() >= 2 && "1".equals(row.get(1).getValue()))
+ .map(row -> row.get(1).getValue())
+ .findFirst()
+ .orElse(null);
+ assertEquals("1", selectValue);
+ }
+ }
+
+ @Test
+ void streamingCancellationShouldStopAfterSecondCancellationCheck() throws Exception {
+ Connection connection = dmExplainConnection();
+
+ CapturingResultConsumer consumer = new CapturingResultConsumer();
+ AtomicInteger streamResultSequence = new AtomicInteger(0);
+ ISqlExecutionCancellation cancellation = () -> streamResultSequence.incrementAndGet() >= 2;
+
+ SimpleSqlStatement statement = new SimpleSqlStatement("EXPLAIN SELECT * FROM SYSOBJECTS");
+
+ var method = DMCommandExecutor.class.getDeclaredMethod("executeMultiStreaming",
+ SimpleSqlStatement.class,
+ Connection.class,
+ boolean.class,
+ Integer.class,
+ Integer.class,
+ Integer.class,
+ ISqlExecutionResultConsumer.class,
+ ISqlExecutionStatementListener.class,
+ ISqlExecutionCancellation.class,
+ SqlTypeEnum.class,
+ String.class,
+ int.class,
+ int.class,
+ AtomicInteger.class,
+ int.class,
+ ExecutionContext.class);
+ method.setAccessible(true);
+
+ InvocationTargetException exception = assertThrows(InvocationTargetException.class,
+ () -> method.invoke(DMCommandExecutor.INSTANCE,
+ statement,
+ connection,
+ true,
+ 0,
+ 10,
+ null,
+ consumer,
+ null,
+ cancellation,
+ null,
+ statement.getSql(),
+ 1,
+ 10,
+ streamResultSequence,
+ 1,
+ null));
+ assertTrue(exception.getCause() instanceof SQLException);
+ assertEquals(0, consumer.resultFinished.size());
+ assertEquals(0, consumer.rowsEventCount);
+ }
+
+ @Test
+ void explainShouldResolveDmdbConnectionFromIndependentDriverClassLoader() throws Exception {
+ try (URLClassLoader driverClassLoader = newDriverIsolatingClassLoader()) {
+ Class> isolatedDmConnection = Class.forName(
+ "dm.jdbc.driver.DmdbConnection", true, driverClassLoader);
+ assertNotSame(DmdbConnection.class, isolatedDmConnection,
+ "driver ClassLoader must define its own DmdbConnection type");
+
+ Connection connection = (Connection) Proxy.newProxyInstance(
+ driverClassLoader,
+ new Class>[]{Connection.class, isolatedDmConnection},
+ (proxy, method, args) -> switch (method.getName()) {
+ case "unwrap" -> unwrap(proxy, (Class>) args[0]);
+ case "isWrapperFor" -> ((Class>) args[0]).isInstance(proxy);
+ case "getExplainInfo" -> "isolated-plan:" + args[0];
+ case "isClosed" -> false;
+ default -> defaultValue(method.getReturnType());
+ });
+
+ assertNotSame(getClass().getClassLoader(), connection.getClass().getClassLoader());
+ putContext(connection);
+
+ List results = DMCommandExecutor.INSTANCE.execute(
+ request("EXPLAIN SELECT * FROM SYSOBJECTS"));
+
+ assertEquals(1, results.size());
+ assertEquals("isolated-plan:SELECT * FROM SYSOBJECTS",
+ results.get(0).getDataList().get(0).get(1).getValue());
+ }
+ }
+
+ @Test
+ void explainDriverSqlExceptionShouldSurfaceOnNonStreamingPath() throws Exception {
+ Connection connection = dmExplainConnectionThrowing(
+ new SQLException("DM-EXPLAIN-ERR-2762", "HY000", 2762));
+ putContext(connection);
+
+ List results = DMCommandExecutor.INSTANCE.execute(
+ request("EXPLAIN SELECT * FROM SYSOBJECTS"));
+
+ assertEquals(1, results.size());
+ assertEquals(Boolean.FALSE, results.get(0).getSuccess());
+ assertTrue(results.get(0).getMessage().contains("DM-EXPLAIN-ERR-2762"));
+ }
+
+ @Test
+ void explainDriverSqlExceptionShouldFinishStreamingPath() throws Exception {
+ Connection connection = dmExplainConnectionThrowing(
+ new SQLException("DM-EXPLAIN-ERR-STREAM", "HY000", 2763));
+ putContext(connection);
+
+ CapturingResultConsumer consumer = new CapturingResultConsumer();
+ DMCommandExecutor.INSTANCE.executeStreaming(
+ request("EXPLAIN SELECT * FROM SYSOBJECTS"), consumer, null, () -> false);
+
+ assertEquals(0, consumer.resultStartedCount);
+ assertEquals(0, consumer.rowsEventCount);
+ assertEquals(1, consumer.statementFinishedCount);
+ assertEquals(1, consumer.resultFinished.size());
+ ExecuteResponse finished = consumer.resultFinished.get(0);
+ assertEquals(Boolean.FALSE, finished.getSuccess());
+ assertTrue(finished.getMessage().contains("DM-EXPLAIN-ERR-STREAM"));
+ }
+
+ @SuppressWarnings("unchecked")
+ private List executeMulti(String sql, Connection connection) throws Exception {
+ Method method = DMCommandExecutor.class.getDeclaredMethod("executeMulti", SimpleSqlStatement.class,
+ Connection.class, boolean.class, Integer.class, Integer.class, Integer.class,
+ ai.chat2db.community.domain.api.model.result.ExecutionContext.class);
+ method.setAccessible(true);
+ return (List) method.invoke(DMCommandExecutor.INSTANCE,
+ new SimpleSqlStatement(sql), connection, true, 0, 10, null, null);
+ }
+
+ private Connection dmExplainConnection() {
+ return dmExplainConnection(null);
+ }
+
+ private Connection dmExplainConnectionThrowing(SQLException failure) {
+ return dmExplainConnection(failure);
+ }
+
+ private Connection dmExplainConnection(SQLException failure) {
+ return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class>[]{Connection.class, DmdbConnection.class},
+ (proxy, method, args) -> {
+ if ("getExplainInfo".equals(method.getName())) {
+ if (failure != null) {
+ throw failure;
+ }
+ return "plan for: " + args[0];
+ }
+ return switch (method.getName()) {
+ case "unwrap" -> unwrap(proxy, (Class>) args[0]);
+ case "isWrapperFor" -> ((Class>) args[0]).isInstance(proxy);
+ case "isClosed" -> false;
+ default -> defaultValue(method.getReturnType());
+ };
+ });
+ }
+
+ /**
+ * Child-first loader that defines {@code dm.jdbc.driver.*} from its own URLs,
+ * mimicking Chat2DB's independent JDBC driver ClassLoader.
+ */
+ private URLClassLoader newDriverIsolatingClassLoader() throws Exception {
+ URL classResource = getClass().getClassLoader().getResource("dm/jdbc/driver/DmdbConnection.class");
+ assertNotNull(classResource, "test stub DmdbConnection.class must be on the test classpath");
+
+ Path root = Files.createTempDirectory("dm-driver-isolation");
+ Path packageDir = root.resolve("dm/jdbc/driver");
+ Files.createDirectories(packageDir);
+ try (var in = classResource.openStream()) {
+ Files.copy(in, packageDir.resolve("DmdbConnection.class"));
+ }
+
+ return new URLClassLoader(new URL[]{root.toUri().toURL()}, getClass().getClassLoader()) {
+ @Override
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.startsWith("dm.jdbc.driver.")) {
+ Class> loaded = findLoadedClass(name);
+ if (loaded == null) {
+ loaded = findClass(name);
+ }
+ if (resolve) {
+ resolveClass(loaded);
+ }
+ return loaded;
+ }
+ return super.loadClass(name, resolve);
+ }
+ };
+ }
+
+ private Connection dmHybridConnection(Connection delegate) {
+ return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class>[]{Connection.class, DmdbConnection.class},
+ (proxy, method, args) -> {
+ String name = method.getName();
+ if ("getExplainInfo".equals(name)) {
+ return "plan for: " + args[0];
+ }
+ if ("unwrap".equals(name)) {
+ Class> target = (Class>) args[0];
+ if (target == Connection.class || target.isInstance(proxy) || target == DmdbConnection.class) {
+ return proxy;
+ }
+ return delegate.unwrap(target);
+ }
+ if ("isWrapperFor".equals(name)) {
+ Class> target = (Class>) args[0];
+ return target == Connection.class || target == DmdbConnection.class
+ || target.isInstance(proxy) || delegate.isWrapperFor(target);
+ }
+ if ("isClosed".equals(name)) {
+ return delegate.isClosed();
+ }
+ if (method.getDeclaringClass() == Object.class) {
+ return switch (name) {
+ case "equals" -> proxy == args[0];
+ case "hashCode" -> System.identityHashCode(proxy);
+ case "toString" -> "DMHybridConnection";
+ default -> throw new IllegalStateException("Unexpected Object method: " + name);
+ };
+ }
+ return method.invoke(delegate, args);
+ });
+ }
+
+ private Connection connectionOnlyWrapper(Connection delegate) {
+ return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class>[]{Connection.class},
+ (proxy, method, args) -> {
+ String name = method.getName();
+ if ("unwrap".equals(name)) {
+ Class> target = (Class>) args[0];
+ if (target == Connection.class) {
+ return proxy;
+ }
+ if (target.isInstance(delegate) || target == DmdbConnection.class) {
+ return delegate;
+ }
+ return delegate.unwrap(target);
+ }
+ if ("isWrapperFor".equals(name)) {
+ Class> target = (Class>) args[0];
+ return target == Connection.class
+ || target.isInstance(delegate)
+ || target == DmdbConnection.class
+ || delegate.isWrapperFor(target);
+ }
+ if (method.getDeclaringClass() == Object.class) {
+ return switch (name) {
+ case "equals" -> proxy == args[0];
+ case "hashCode" -> System.identityHashCode(proxy);
+ case "toString" -> "ConnectionOnlyWrapper";
+ default -> throw new IllegalStateException("Unexpected Object method: " + name);
+ };
+ }
+ return method.invoke(delegate, args);
+ });
+ }
+
+ private void putContext(Connection connection) {
+ previousPlugin = Chat2DBContext.PLUGIN_MAP.put("DM", new DMPlugin());
+ contextBound = true;
+ ConnectInfo connectInfo = new ConnectInfo();
+ connectInfo.setDataSourceId(DATA_SOURCE_ID);
+ connectInfo.setConsoleId(1L);
+ connectInfo.setDbType("DM");
+ connectInfo.setDatabaseName("");
+ connectInfo.setSchemaName("SYSDBA");
+ connectInfo.setUrl("jdbc:test:dm");
+ connectInfo.setConnection(connection);
+ DriverConfig driverConfig = new DriverConfig();
+ driverConfig.setDbType("DM");
+ connectInfo.setDriverConfig(driverConfig);
+ Chat2DBContext.putContext(connectInfo);
+ }
+
+ private SqlExecuteRequest request(String sql) {
+ SqlExecuteRequest request = new SqlExecuteRequest();
+ request.setScript(sql);
+ request.setConsoleId(1L);
+ request.setDataSourceId(DATA_SOURCE_ID);
+ request.setDatabaseName("");
+ request.setSchemaName("SYSDBA");
+ request.setPageNo(1);
+ request.setPageSize(10);
+ request.setErrorContinue(Boolean.TRUE);
+ return request;
+ }
+
+ private Object unwrap(Object proxy, Class> targetClass) throws SQLException {
+ if (targetClass.isInstance(proxy) || targetClass == Connection.class) {
+ return proxy;
+ }
+ throw new SQLException("Unsupported unwrap target: " + targetClass.getName());
+ }
+
+ private Object defaultValue(Class> returnType) {
+ if (!returnType.isPrimitive()) {
+ return null;
+ }
+ if (returnType == boolean.class) {
+ return false;
+ }
+ if (returnType == int.class) {
+ return 0;
+ }
+ if (returnType == long.class) {
+ return 0L;
+ }
+ if (returnType == double.class) {
+ return 0D;
+ }
+ if (returnType == float.class) {
+ return 0F;
+ }
+ if (returnType == short.class) {
+ return (short) 0;
+ }
+ if (returnType == byte.class) {
+ return (byte) 0;
+ }
+ if (returnType == char.class) {
+ return '\0';
+ }
+ return null;
+ }
+
+ private static final class CapturingResultConsumer implements ISqlExecutionResultConsumer {
+
+ private int resultStartedCount;
+ /** Row count carried on resultStarted; should stay 0 for materialized explain streaming. */
+ private int resultStartedRowCount;
+ private int rowsEventCount;
+ private int statementFinishedCount;
+ private final List> receivedRows = new ArrayList<>();
+ private final List resultFinished = new ArrayList<>();
+
+ @Override
+ public void statementStarted(String sql, String originalSql, String comment) {
+ }
+
+ @Override
+ public void resultStarted(ExecuteResponse result) {
+ resultStartedCount++;
+ resultStartedRowCount = result.getDataList() == null ? 0 : result.getDataList().size();
+ }
+
+ @Override
+ public void rows(ExecuteResponse result, List> rows) {
+ rowsEventCount++;
+ receivedRows.addAll(rows);
+ }
+
+ @Override
+ public void resultFinished(ExecuteResponse result) {
+ resultFinished.add(result);
+ }
+
+ @Override
+ public void updateCount(ExecuteResponse result) {
+ }
+
+ @Override
+ public void statementFinished(String sql, long duration) {
+ statementFinishedCount++;
+ }
+ }
+}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/dm/jdbc/driver/DmdbConnection.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/dm/jdbc/driver/DmdbConnection.java
new file mode 100644
index 0000000000..13c008c300
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/dm/jdbc/driver/DmdbConnection.java
@@ -0,0 +1,9 @@
+package dm.jdbc.driver;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public interface DmdbConnection extends Connection {
+
+ String getExplainInfo(String sql) throws SQLException;
+}
diff --git a/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/DefaultSQLExecutor.java b/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/DefaultSQLExecutor.java
index 346659bd59..54ab64f821 100644
--- a/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/DefaultSQLExecutor.java
+++ b/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/DefaultSQLExecutor.java
@@ -1316,6 +1316,31 @@ private ExecuteResponse streamQueryExecuteResponse(Statement stmt, boolean limit
return executeResult;
}
+ /**
+ * Publishes an already-materialized query result on the streaming path.
+ * Sends an empty {@code dataList} with {@code resultStarted}, then the real
+ * rows via {@code rows}, matching {@link #streamQueryExecuteResponse}.
+ * The caller ({@link #executeStreaming}) remains responsible for a single
+ * {@code resultFinished}.
+ */
+ protected void publishMaterializedQueryResult(ExecuteResponse response,
+ ISqlExecutionResultConsumer consumer,
+ AtomicInteger streamResultSequence,
+ int statementSequence,
+ int pageNo,
+ int pageSize) {
+ response.setStatementSequence(statementSequence);
+ setStreamResultId(response, streamResultSequence.incrementAndGet());
+ addRowNumber(response, pageNo, pageSize);
+ List> numberedRows = response.getDataList() == null
+ ? new ArrayList<>()
+ : new ArrayList<>(response.getDataList());
+ response.setDataList(new ArrayList<>());
+ consumer.resultStarted(response);
+ consumer.rows(response, numberedRows);
+ response.setDataList(numberedRows);
+ }
+
private void setStreamResultId(ExecuteResponse executeResult, int streamResultId) {
Map extra = executeResult.getExtra();
if (extra == null) {
diff --git a/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java b/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java
index 4f0e028538..5dbeee541c 100644
--- a/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java
+++ b/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/sql/Chat2DBContext.java
@@ -139,6 +139,13 @@ public static StatementGuardScope bindStatementGuard(Consumer statementG
return new StatementGuardScope(previous);
}
+ public static void guardStatement(String sql) {
+ Consumer statementGuard = STATEMENT_GUARD_THREAD_LOCAL.get();
+ if (statementGuard != null) {
+ statementGuard.accept(sql);
+ }
+ }
+
public static String getDbVersion() {
ConnectInfo connectInfo = getConnectInfo();
From 44de376960f786fdee68ca810a325c4b1f60e2b6 Mon Sep 17 00:00:00 2001
From: hhz <1839462565@qq.com>
Date: Fri, 28 Aug 2026 16:52:24 +0800
Subject: [PATCH 2/3] test(dm): cover EXPLAIN statement classification
---
.../dm/parser/visitor/DMParserVisitor.java | 2 +
.../parser/visitor/DMSimpleParserVisitor.java | 2 +
.../parser/visitor/DMValidTableVisitor.java | 2 +
.../ai/chat2db/plugin/dm/DMSqlParserTest.java | 52 +++++++++++++++++++
4 files changed, 58 insertions(+)
create mode 100644 chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMSqlParserTest.java
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
index 1ce02754e1..96a87e3c5e 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
@@ -75,6 +75,8 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
+ // Statement#setType is first-write-wins. Set the outer type before visiting the
+ // inner DML so EXPLAIN remains the statement type while identifiers are collected.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
return super.visitExplain_statement(ctx);
}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
index b62a39ef05..6d94a7a66f 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
@@ -71,6 +71,8 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
+ // Statement#setType is first-write-wins. Set the outer type before visiting the
+ // inner DML so EXPLAIN remains the statement type.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
return super.visitExplain_statement(ctx);
}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
index 364f558c31..78bda28044 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
@@ -1201,6 +1201,8 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
+ // Statement#setType is first-write-wins. Set the outer type before visiting the
+ // inner DML so EXPLAIN remains the statement type while table metadata is collected.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
return super.visitExplain_statement(ctx);
}
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMSqlParserTest.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMSqlParserTest.java
new file mode 100644
index 0000000000..98fd157248
--- /dev/null
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/test/java/ai/chat2db/plugin/dm/DMSqlParserTest.java
@@ -0,0 +1,52 @@
+package ai.chat2db.plugin.dm;
+
+import ai.chat2db.community.domain.api.enums.parser.SqlTypeEnum;
+import ai.chat2db.community.domain.api.model.parser.result.SqlParserResponse;
+import ai.chat2db.community.domain.api.model.parser.statement.Statement;
+import ai.chat2db.plugin.dm.parser.DMSqlParser;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DMSqlParserTest {
+
+ @ParameterizedTest(name = "{index}: {0}")
+ @MethodSource("explainStatements")
+ void parserStatementsShouldPreserveExplainAsOuterStatementType(String sql) {
+ assertExplainType(new DMSqlParser().parserStatements(sql), sql);
+ }
+
+ @ParameterizedTest(name = "{index}: {0}")
+ @MethodSource("explainStatements")
+ void simpleParserStatementsShouldPreserveExplainAsOuterStatementType(String sql) {
+ assertExplainType(new DMSqlParser().simpleParserStatements(sql), sql);
+ }
+
+ @ParameterizedTest(name = "{index}: {0}")
+ @MethodSource("explainStatements")
+ void validTableStatementsShouldPreserveExplainAsOuterStatementType(String sql) {
+ assertExplainType(new DMSqlParser().validTableStatements(sql), sql);
+ }
+
+ private static Stream explainStatements() {
+ return Stream.of(
+ "EXPLAIN SELECT * FROM SYSOBJECTS",
+ "EXPLAIN UPDATE SYSOBJECTS SET NAME = 'UPDATED' WHERE ID = 1",
+ "EXPLAIN DELETE FROM SYSOBJECTS WHERE ID = 1",
+ "EXPLAIN INSERT INTO SYSOBJECTS (ID, NAME) VALUES (1, 'CREATED')",
+ "EXPLAIN MERGE INTO TARGET_TABLE T USING SOURCE_TABLE S ON (T.ID = S.ID) "
+ + "WHEN MATCHED THEN UPDATE SET T.NAME = S.NAME"
+ );
+ }
+
+ private void assertExplainType(SqlParserResponse response, String sql) {
+ List statements = response.getStatements();
+
+ assertEquals(1, statements.size(), sql);
+ assertEquals(SqlTypeEnum.EXPLAIN.name(), statements.get(0).getType(), sql);
+ }
+}
From 6a8950c4042f1d38b5691ca5d172685f299d9f02 Mon Sep 17 00:00:00 2001
From: hhz <1839462565@qq.com>
Date: Fri, 28 Aug 2026 17:04:10 +0800
Subject: [PATCH 3/3] fix(dm): preserve EXPLAIN parser statement type
---
.../ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java | 4 +---
.../plugin/dm/parser/visitor/DMSimpleParserVisitor.java | 4 +---
.../chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java | 4 +---
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
index 96a87e3c5e..f58273c14c 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMParserVisitor.java
@@ -75,10 +75,8 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
- // Statement#setType is first-write-wins. Set the outer type before visiting the
- // inner DML so EXPLAIN remains the statement type while identifiers are collected.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
- return super.visitExplain_statement(ctx);
+ return null;
}
@Override
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
index 6d94a7a66f..b8fa570f9c 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMSimpleParserVisitor.java
@@ -71,10 +71,8 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
- // Statement#setType is first-write-wins. Set the outer type before visiting the
- // inner DML so EXPLAIN remains the statement type.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
- return super.visitExplain_statement(ctx);
+ return null;
}
@Override
diff --git a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
index 78bda28044..5179a28333 100644
--- a/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
+++ b/chat2db-community-server/chat2db-community-plugins/chat2db-community-dm/src/main/java/ai/chat2db/plugin/dm/parser/visitor/DMValidTableVisitor.java
@@ -1201,9 +1201,7 @@ public Void visitExplain_statement(DMParser.Explain_statementContext ctx) {
if (Objects.isNull(currentStatement)) {
return null;
}
- // Statement#setType is first-write-wins. Set the outer type before visiting the
- // inner DML so EXPLAIN remains the statement type while table metadata is collected.
currentStatement.setType(SqlTypeEnum.EXPLAIN.name());
- return super.visitExplain_statement(ctx);
+ return null;
}
}