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; } }