This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new b7054656712 Support parsing Oracle CREATE TABLE with ORGANIZATION 
EXTERNAL clause (#39524)
b7054656712 is described below

commit b7054656712e4b94541b0a89bf10932b3290766c
Author: Liang Zhang <[email protected]>
AuthorDate: Thu Aug 20 01:06:38 2026 +0800

    Support parsing Oracle CREATE TABLE with ORGANIZATION EXTERNAL clause 
(#39524)
    
    - add RECORDS, DELIMITED, FIXED, FIELDS keyword tokens with unreservedWord 
fallback
    - support parenthesized ACCESS PARAMETERS with RECORDS FIXED/DELIMITED BY 
and FIELDS RTRIM/LTRIM field lists
    - accept quoted location specifier and single location entry in LOCATION 
clause
    - add 5 parser IT cases for the CREATE TABLE statements from issue #27096
    
    Fixes #27096
---
 .../src/main/antlr4/imports/oracle/BaseRule.g4     |  6 +-
 .../src/main/antlr4/imports/oracle/DDLStatement.g4 | 27 ++++++-
 .../main/antlr4/imports/oracle/OracleKeyword.g4    | 16 +++++
 .../src/main/resources/case/ddl/create-table.xml   | 83 ++++++++++++++++++++++
 .../resources/sql/supported/ddl/create-table.xml   |  5 ++
 5 files changed, 133 insertions(+), 4 deletions(-)

diff --git 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
index 0a008e3b204..47b7822adb8 100644
--- 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
+++ 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
@@ -82,7 +82,7 @@ identifier
     ;
 
 unreservedWord
-    : SELECT | INSERT | UPDATE | DELETE | CREATE | ALTER | DROP | TRUNCATE | 
SCHEMA | GRANT | REVOKE | ADD | SET | TABLE | COLUMN | INDEX | CONSTRAINT | 
PRIMARY | UNIQUE | FOREIGN | KEY | POSITION | PRECISION | FUNCTION | 
CONSTRUCTOR | RESULT | TRIGGER | MAP | PROCEDURE | SPECIFICATION | VIEW | INTO 
| VALUES | WITH | UNION | DISTINCT | CASE | WHEN | CAST | TRIM | SUBSTRING | 
FROM | NATURAL | JOIN | FULL | INNER | OUTER | LEFT | RIGHT | CROSS | USING | 
WHERE | AS | ON | IF | ELSE | ELSIF  [...]
+    : SELECT | INSERT | UPDATE | DELETE | CREATE | ALTER | DROP | TRUNCATE | 
SCHEMA | GRANT | REVOKE | ADD | SET | TABLE | COLUMN | INDEX | CONSTRAINT | 
PRIMARY | UNIQUE | FOREIGN | KEY | POSITION | PRECISION | FUNCTION | 
CONSTRUCTOR | RESULT | TRIGGER | MAP | PROCEDURE | SPECIFICATION | VIEW | INTO 
| VALUES | WITH | UNION | DISTINCT | CASE | WHEN | CAST | TRIM | SUBSTRING | 
FROM | NATURAL | JOIN | FULL | INNER | OUTER | LEFT | RIGHT | CROSS | USING | 
WHERE | AS | ON | IF | ELSE | ELSIF  [...]
     | BEQUEATH | BINARY | ESCAPE | MOD | XOR | ROW | ROWS | UNKNOWN | ALWAYS | 
CASCADE | CHECK | CONVERSION | GENERATED | PRIVILEGES | READ | WRITE | 
REFERENCES | START | TRANSACTION | USER | ROLE | VISIBLE | INVISIBLE | EXECUTE 
| USE | DEBUG | UNDER | FLASHBACK | ARCHIVE | REFRESH | QUERY | REWRITE | KEEP 
| SEQUENCE | INHERIT | TRANSLATE | MERGE | AT | BITMAP | CACHE | NOCACHE | 
CHECKPOINT | CONNECT | CONSTRAINTS | CYCLE | NOCYCLE | DBTIMEZONE | ENCRYPT | 
DECRYPT | DEFERRABLE | DEFERRED [...]
     | SINGLE_K | SINGLE_M | SINGLE_G | SINGLE_T | SINGLE_P | SINGLE_E | 
SINGLE_H | V1
     ;
@@ -280,7 +280,7 @@ lobSegname
     ;
 
 locationSpecifier
-    : identifier
+    : identifier | STRING_
     ;
 
 xmlSchemaURLName
@@ -1976,5 +1976,5 @@ optionallyEnclosedBySpec
      ;
 
 lrtrimSpec
-     : LRTRIM
+     : LTRIM | RTRIM | LRTRIM
      ;
diff --git 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DDLStatement.g4
 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DDLStatement.g4
index 03186aa0efc..80ea5d2c344 100644
--- 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DDLStatement.g4
+++ 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DDLStatement.g4
@@ -1096,7 +1096,32 @@ externalTableClause
     ;
 
 externalTableDataProps
-    : (DEFAULT DIRECTORY directoryName)? (ACCESS PARAMETERS ((opaqueFormatSpec 
delimSpec)? | USING CLOB subquery))? (LOCATION LP_ (directoryName | 
(directoryName COLON_)? locationSpecifier (COMMA_ (directoryName COLON_)? 
locationSpecifier)+) RP_)?
+    : (DEFAULT DIRECTORY directoryName)? (ACCESS PARAMETERS 
(parenthesizedOpaqueFormatSpec | (opaqueFormatSpec delimSpec)? | USING CLOB 
subquery))? (LOCATION LP_ (directoryName | (directoryName COLON_)? 
locationSpecifier (COMMA_ (directoryName COLON_)? locationSpecifier)*) RP_)?
+    ;
+
+parenthesizedOpaqueFormatSpec
+    : LP_ recordFormatInfo? fieldList RP_
+    ;
+
+recordFormatInfo
+    : RECORDS (FIXED INTEGER_ | DELIMITED BY STRING_)
+    ;
+
+fieldList
+    : FIELDS delimSpec? (LP_ fieldDefinition (COMMA_ fieldDefinition)* RP_)?
+    ;
+
+fieldDefinition
+    : columnName positionSpecification? dataType?
+    ;
+
+positionSpecification
+    : LP_ positionBound COLON_ positionBound RP_
+    ;
+
+positionBound
+    : ASTERISK_ (PLUS_ | MINUS_)? INTEGER_?
+    | (PLUS_ | MINUS_)? INTEGER_
     ;
 
 mappingTableClause
diff --git 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
index d3a0d54efa8..34096b6e987 100644
--- 
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
+++ 
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
@@ -1623,6 +1623,10 @@ FINISH
     : F I N I S H
     ;
 
+FIXED
+    : F I X E D
+    ;
+
 LOGICAL
     : L O G I C A L
     ;
@@ -2019,6 +2023,10 @@ FETCH
     : F E T C H
     ;
 
+FIELDS
+    : F I E L D S
+    ;
+
 PERCENT
     : P E R C E N T
     ;
@@ -3100,6 +3108,10 @@ RECORD
     : R E C O R D
     ;
 
+RECORDS
+    : R E C O R D S
+    ;
+
 CONSTANT
     : C O N S T A N T
     ;
@@ -3760,6 +3772,10 @@ DELETEXML
     :D E L E T E X M L
     ;
 
+DELIMITED
+    :D E L I M I T E D
+    ;
+
 DENSE_RANKM
     :D E N S E UL_ R A N K M
     ;
diff --git a/test/it/parser/src/main/resources/case/ddl/create-table.xml 
b/test/it/parser/src/main/resources/case/ddl/create-table.xml
index bb5bd055b1a..31e8112d5f0 100644
--- a/test/it/parser/src/main/resources/case/ddl/create-table.xml
+++ b/test/it/parser/src/main/resources/case/ddl/create-table.xml
@@ -2982,6 +2982,89 @@
         </column-definition>
     </create-table>
     
+    <create-table sql-case-id="create_table_with_clob" >
+        <table name="docs" start-index="13" stop-index="16" />
+        <column-definition type="NUMBER" start-index="19" stop-index="30">
+            <column name="docid" start-index="19" stop-index="23"/>
+        </column-definition>
+        <column-definition type="DATE" start-index="33" stop-index="45">
+            <column name="pub_date" start-index="33" stop-index="40"/>
+        </column-definition>
+        <column-definition type="VARCHAR2" start-index="48" stop-index="66">
+            <column name="author" start-index="48" stop-index="53"/>
+        </column-definition>
+        <column-definition type="VARCHAR2" start-index="69" stop-index="89">
+            <column name="category" start-index="69" stop-index="76"/>
+        </column-definition>
+        <column-definition type="CLOB" start-index="92" stop-index="104">
+            <column name="document" start-index="92" stop-index="99"/>
+        </column-definition>
+    </create-table>
+
+    <create-table sql-case-id="create_table_with_fields_rtrim" >
+        <table name="emp_load" start-index="13" stop-index="20" />
+        <column-definition type="CHAR" start-index="23" stop-index="41">
+            <column name="first_name" start-index="23" stop-index="32"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="44" stop-index="61">
+            <column name="last_name" start-index="44" stop-index="52"/>
+        </column-definition>
+        <column-definition type="INT" start-index="64" stop-index="80">
+            <column name="year_of_birth" start-index="64" stop-index="76"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="83" stop-index="96">
+            <column name="phone" start-index="83" stop-index="87"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="99" stop-index="115">
+            <column name="area_code" start-index="99" stop-index="107"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="118" stop-index="133">
+            <column name="exchange" start-index="118" stop-index="125"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="136" stop-index="152">
+            <column name="extension" start-index="136" stop-index="144"/>
+        </column-definition>
+    </create-table>
+
+    <create-table sql-case-id="create_table_with_fields_ltrim" >
+        <table name="emp_load" start-index="13" stop-index="20" />
+        <column-definition type="CHAR" start-index="23" stop-index="41">
+            <column name="first_name" start-index="23" stop-index="32"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="44" stop-index="61">
+            <column name="last_name" start-index="44" stop-index="52"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="64" stop-index="84">
+            <column name="year_of_birth" start-index="64" stop-index="76"/>
+        </column-definition>
+    </create-table>
+
+    <create-table sql-case-id="create_table_with_records_delimited_by" >
+        <table name="emp_load" start-index="13" stop-index="20" />
+        <column-definition type="CHAR" start-index="23" stop-index="41">
+            <column name="first_name" start-index="23" stop-index="32"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="44" stop-index="61">
+            <column name="last_name" start-index="44" stop-index="52"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="64" stop-index="84">
+            <column name="year_of_birth" start-index="64" stop-index="76"/>
+        </column-definition>
+    </create-table>
+
+    <create-table sql-case-id="create_table_with_records_fixed" >
+        <table name="emp_load" start-index="13" stop-index="20" />
+        <column-definition type="CHAR" start-index="23" stop-index="41">
+            <column name="first_name" start-index="23" stop-index="32"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="44" stop-index="61">
+            <column name="last_name" start-index="44" stop-index="52"/>
+        </column-definition>
+        <column-definition type="CHAR" start-index="64" stop-index="84">
+            <column name="year_of_birth" start-index="64" stop-index="76"/>
+        </column-definition>
+    </create-table>
+
     <create-table sql-case-id="create_table_with_builtin_function">
         <table name="tab" start-index="13" stop-index="15"/>
         <select>
diff --git 
a/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml 
b/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
index b97602817f6..d5bca5630c3 100644
--- a/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
+++ b/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
@@ -354,6 +354,11 @@
     <sql-case id="create_table_parallel_with_as_sub_query" value="CREATE TABLE 
hr.admin_emp_dept PARALLEL COMPRESS AS SELECT * FROM hr.employees WHERE 
department_id = 10;" db-types="Oracle"/>
     <sql-case id="create_table_with_edge_constraint" value="CREATE TABLE 
bought ( PurchaseCount INT ,CONSTRAINT EC_BOUGHT CONNECTION (Customer TO 
Product) ON DELETE NO ACTION );" db-types="SQLServer"/>
     <sql-case id="create_table_with_enclosed" value="CREATE TABLE 
emp_load(first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) 
ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS 
PARAMETERS FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '(' and ')'LRTRIM 
LOCATION (info.dat));" db-types="Oracle"/>
+    <sql-case id="create_table_with_clob" value="CREATE TABLE docs (docid 
NUMBER, pub_date DATE, author VARCHAR2(30), category VARCHAR2(30), document 
CLOB)" db-types="Oracle"/>
+    <sql-case id="create_table_with_fields_rtrim" value="CREATE TABLE emp_load 
(first_name CHAR(15), last_name CHAR(20), year_of_birth INT, phone CHAR(12), 
area_code CHAR(3), exchange CHAR(3), extension CHAR(4)) ORGANIZATION EXTERNAL 
(TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS PARAMETERS (FIELDS 
RTRIM (first_name (1:15) CHAR(15), last_name (*:+20), year_of_birth (36:39), 
phone (40:52), area_code (*-12: +3), exchange (*+1: +3), extension (*+1: +4))) 
LOCATION ('info.dat'))" db [...]
+    <sql-case id="create_table_with_fields_ltrim" value="CREATE TABLE emp_load 
(first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) ORGANIZATION 
EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS PARAMETERS 
(FIELDS LTRIM) LOCATION ('info.dat'))" db-types="Oracle"/>
+    <sql-case id="create_table_with_records_delimited_by" value="CREATE TABLE 
emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) 
ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS 
PARAMETERS (RECORDS DELIMITED BY '|' FIELDS TERMINATED BY ',' (first_name 
CHAR(7), last_name CHAR(8), year_of_birth CHAR(4))) LOCATION ('info.dat'))" 
db-types="Oracle"/>
+    <sql-case id="create_table_with_records_fixed" value="CREATE TABLE 
emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) 
ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS 
PARAMETERS (RECORDS FIXED 20 FIELDS (first_name CHAR(7), last_name CHAR(8), 
year_of_birth CHAR(4))) LOCATION ('info.dat'))" db-types="Oracle"/>
     <sql-case id="create_table_with_builtin_function" value="CREATE TABLE tab 
AS SELECT DBMS_LOB.GETLENGTH@dbs2(clob_col) len FROM tab@dbs2;" 
db-types="Oracle"/>
     <sql-case id="create_table_with_autoextend_size" value="CREATE TABLE t1 
(c1 INT) AUTOEXTEND_SIZE = 4M" db-types="MySQL"/>
     <sql-case id="create_table_with_cast_function1" value="create table 
test_schema.tb_ods_bs_class_all as

Reply via email to