Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions plsql/PlSqlLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,7 @@ PARTITION_LIST: 'PARTITION_LIST';
PARTITION: 'PARTITION';
PARTITION_RANGE: 'PARTITION_RANGE';
PARTITIONS: 'PARTITIONS';
PARTITIONSET: 'PARTITIONSET';
PARTNUMINST: 'PART$NUM$INST';
PASSING: 'PASSING';
PASSWORD_GRACE_TIME: 'PASSWORD_GRACE_TIME';
Expand Down Expand Up @@ -2303,9 +2304,7 @@ 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';
Expand Down
93 changes: 81 additions & 12 deletions plsql/PlSqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -3295,7 +3295,7 @@ create_table
| IMMUTABLE? BLOCKCHAIN
| IMMUTABLE
)?
TABLE (schema_name PERIOD)? table_name
TABLE (IF NOT EXISTS)? (schema_name PERIOD)? table_name
(SHARING EQUALS_OP (METADATA | EXTENDED? DATA | NONE))?
(relational_table | object_table | xmltype_table)
(MEMOPTIMIZE FOR READ)?
Expand Down Expand Up @@ -3395,19 +3395,19 @@ immutable_table_no_delete_clause
;

blockchain_table_clauses
: blockchain_drop_table_clause blockchain_row_retention_clause blockchain_hash_and_data_format_clause
: 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?)
: NO DELETE (LOCKED? | UNTIL numeric DAYS (IDLE | AFTER INSERT) LOCKED?)
Comment thread
h3n4l marked this conversation as resolved.
;

blockchain_hash_and_data_format_clause
: HASHING USING SHA2_512_Q VERSION V1_Q
: HASHING USING (CHAR_STRING | DELIMITED_ID) VERSION (CHAR_STRING | DELIMITED_ID)
;

collation_name
Expand Down Expand Up @@ -3512,6 +3512,9 @@ table_partitioning_clauses
| composite_hash_partitions
| reference_partitioning
| system_partitioning
| consistent_hash_partitions
| consistent_hash_with_subpartitions
| partitionset_clauses
;

range_partitions
Expand All @@ -3521,7 +3524,8 @@ range_partitions
;

list_partitions
: PARTITION BY LIST LEFT_PAREN column_name RIGHT_PAREN
: PARTITION BY LIST LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
AUTOMATIC?
LEFT_PAREN PARTITION partition_name? list_values_clause table_partition_description (COMMA PARTITION partition_name? list_values_clause table_partition_description )* RIGHT_PAREN
;

Expand Down Expand Up @@ -3553,7 +3557,8 @@ composite_range_partitions
;

composite_list_partitions
: PARTITION BY LIST LEFT_PAREN column_name RIGHT_PAREN
: PARTITION BY LIST LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
AUTOMATIC?
(subpartition_by_range | subpartition_by_list | subpartition_by_hash)
LEFT_PAREN list_partition_desc (COMMA list_partition_desc)* RIGHT_PAREN
;
Expand All @@ -3578,6 +3583,51 @@ system_partitioning
(PARTITIONS UNSIGNED_INTEGER | reference_partition_desc (COMMA reference_partition_desc)*)?
;

consistent_hash_partitions
: PARTITION BY CONSISTENT HASH LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
PARTITIONS AUTO
;

consistent_hash_with_subpartitions
: PARTITION BY CONSISTENT HASH LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
PARTITIONS AUTO
SUBPARTITION BY
( RANGE LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
| LIST LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
)
SUBPARTITIONS AUTO
;

partitionset_clauses
: PARTITION BY PARTITIONSET (range_partitionset_clause | list_partitionset_clause)
;

range_partitionset_clause
: RANGE LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
LEFT_PAREN range_partitionset_desc (COMMA range_partitionset_desc)* RIGHT_PAREN
;

range_partitionset_desc
: PARTITIONSET partitionset_name
VALUES LESS THAN LEFT_PAREN range_partition_value (COMMA range_partition_value)* RIGHT_PAREN
LEFT_PAREN range_partition_desc (COMMA range_partition_desc)* RIGHT_PAREN
;

list_partitionset_clause
: LIST LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN
LEFT_PAREN list_partitionset_desc (COMMA list_partitionset_desc)* RIGHT_PAREN
;

list_partitionset_desc
: PARTITIONSET partitionset_name
VALUES LEFT_PAREN (list_partition_value (COMMA list_partition_value)* | DEFAULT) RIGHT_PAREN
LEFT_PAREN list_partition_desc (COMMA list_partition_desc)* RIGHT_PAREN
;

partitionset_name
: identifier
;

range_partition_desc
: PARTITION partition_name? range_values_clause table_partition_description
( ( LEFT_PAREN ( range_subpartition_desc (COMMA range_subpartition_desc)*
Expand Down Expand Up @@ -3623,7 +3673,7 @@ subpartition_by_range
;

subpartition_by_list
: SUBPARTITION BY LIST LEFT_PAREN column_name RIGHT_PAREN subpartition_template?
: SUBPARTITION BY LIST LEFT_PAREN column_name (COMMA column_name)* RIGHT_PAREN subpartition_template?
;

subpartition_by_hash
Expand All @@ -3638,27 +3688,44 @@ subpartition_name
;

range_subpartition_desc
: SUBPARTITION subpartition_name? range_values_clause partitioning_storage_clause?
: SUBPARTITION subpartition_name? range_values_clause read_only_clause? indexing_clause? partitioning_storage_clause?
;

list_subpartition_desc
: SUBPARTITION subpartition_name? list_values_clause partitioning_storage_clause?
: SUBPARTITION subpartition_name? list_values_clause read_only_clause? indexing_clause? partitioning_storage_clause?
;

individual_hash_subparts
: SUBPARTITION subpartition_name? partitioning_storage_clause?
: SUBPARTITION subpartition_name? read_only_clause? indexing_clause? partitioning_storage_clause?
;

hash_subparts_by_quantity
: SUBPARTITIONS UNSIGNED_INTEGER (STORE IN LEFT_PAREN tablespace (COMMA tablespace)* RIGHT_PAREN )?
;

range_values_clause
: VALUES LESS THAN LEFT_PAREN literal (COMMA literal)* RIGHT_PAREN
: VALUES LESS THAN LEFT_PAREN range_partition_value (COMMA range_partition_value)* RIGHT_PAREN
;

// expression already covers MAXVALUE via constant_without_variable; kept as an explicit
// alternative purely for clarity — the intended terminals in this context are expression or MAXVALUE.
range_partition_value
: expression
| MAXVALUE
;

list_values_clause
: VALUES LEFT_PAREN (literal (COMMA literal)* | TIMESTAMP literal (COMMA TIMESTAMP literal)* | DEFAULT) RIGHT_PAREN
: VALUES LEFT_PAREN (list_partition_value (COMMA list_partition_value)* | DEFAULT) RIGHT_PAREN
;

// expression already covers NULL (and, pragmatically, DEFAULT) via constant/regular_id;
// semantic validity of `DEFAULT` mixed with other values is checked by the server,
// matching how other SQL grammars in this repo over-accept at the parser level.
// Tuple form for multi-column LIST partitioning is handled by expression -> atom
// (`LEFT_PAREN expressions RIGHT_PAREN`), so no dedicated tuple rule is needed.
list_partition_value
: expression
| NULL_
;

table_partition_description
Expand Down Expand Up @@ -5255,6 +5322,7 @@ column_definition
(DEFAULT (ON NULL_)? expression | identity_clause)?
(ENCRYPT encryption_spec)?
(inline_constraint+ | inline_ref_constraint)?
annotations_clause?
;

column_collation_name
Expand Down Expand Up @@ -9023,6 +9091,7 @@ non_reserved_keywords_pre12c
| PARTITION
| PARTITION_RANGE
| PARTITIONS
| PARTITIONSET
| PARTNUMINST
| PASSING
| PASSWORD_GRACE_TIME
Expand Down
127 changes: 127 additions & 0 deletions plsql/examples/create_table_grammar_gaps.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
-- Regression fixtures for CREATE TABLE grammar gaps closed against Oracle 19c docs.
-- Each block below previously failed to parse; see PR description for details.

--------------------------------------------------------------------------------
-- Tier 1: partition value clauses accept full expressions (fixes BYT-9302)
--------------------------------------------------------------------------------

-- DATE typed literal in RANGE bound with INTERVAL partitioning
CREATE TABLE gcp.lead_drop_mc_native_data (
txn_date DATE,
userid VARCHAR2(100),
custid VARCHAR2(100),
screenid VARCHAR2(500),
eventtime DATE,
status NUMBER
)
PARTITION BY RANGE (txn_date)
INTERVAL (NUMTODSINTERVAL(1,'DAY'))
(PARTITION p0 VALUES LESS THAN (DATE '2026-01-01'));

-- TIMESTAMP typed literal in RANGE bound
CREATE TABLE range_ts (d TIMESTAMP)
PARTITION BY RANGE (d)
(PARTITION p0 VALUES LESS THAN (TIMESTAMP '2026-01-01 00:00:00'));

-- Arithmetic expression in RANGE bound
CREATE TABLE range_expr (c NUMBER)
PARTITION BY RANGE (c)
(PARTITION p0 VALUES LESS THAN (10*10 + 5));

-- NULL in LIST values
CREATE TABLE list_null (c VARCHAR2(10))
PARTITION BY LIST (c)
(PARTITION p0 VALUES (NULL, 'a', 'b'));

-- Expression in LIST values
CREATE TABLE list_expr (c NUMBER)
PARTITION BY LIST (c)
(PARTITION p0 VALUES (1+2, 3*3));

-- Multi-column LIST partitioning with tuple form
CREATE TABLE list_multi_col (a NUMBER, b NUMBER)
PARTITION BY LIST (a, b)
(
PARTITION p0 VALUES ((1,2),(3,4)),
PARTITION p1 VALUES ((5,6))
);

--------------------------------------------------------------------------------
-- Tier 2: IF NOT EXISTS, LIST AUTOMATIC, blockchain flexibility
--------------------------------------------------------------------------------

-- IF NOT EXISTS on CREATE TABLE
CREATE TABLE IF NOT EXISTS t_ine (a NUMBER, b VARCHAR2(10));

-- AUTOMATIC list partitioning
CREATE TABLE list_auto (c NUMBER)
PARTITION BY LIST (c) AUTOMATIC
(PARTITION p0 VALUES (1));

-- Blockchain: new DAYS IDLE form on retention clause, with single-quoted algorithm/version
CREATE BLOCKCHAIN TABLE bc_idle (a NUMBER)
NO DROP UNTIL 0 DAYS IDLE
NO DELETE UNTIL 16 DAYS IDLE
HASHING USING 'SHA2_512' VERSION 'v1';

-- Blockchain: drop/retention clauses both omitted (only the hash clause is required)
CREATE BLOCKCHAIN TABLE bc_hash_only (a NUMBER)
HASHING USING "SHA2_512" VERSION "v1";

--------------------------------------------------------------------------------
-- Tier 3: CONSISTENT HASH and PARTITIONSET
--------------------------------------------------------------------------------

-- Consistent hash partitioning
CREATE TABLE ch_simple (a NUMBER)
PARTITION BY CONSISTENT HASH (a)
PARTITIONS AUTO;

-- Consistent hash with range sub-partitioning
CREATE TABLE ch_sub (a NUMBER, d DATE)
PARTITION BY CONSISTENT HASH (a)
PARTITIONS AUTO
SUBPARTITION BY RANGE (d)
SUBPARTITIONS AUTO;

-- Range partitionset
CREATE TABLE range_ps (a NUMBER, b NUMBER)
PARTITION BY PARTITIONSET RANGE (a)
(
PARTITIONSET ps1 VALUES LESS THAN (100)
(PARTITION p1 VALUES LESS THAN (10))
);

-- List partitionset
CREATE TABLE list_ps (a NUMBER, b NUMBER)
PARTITION BY PARTITIONSET LIST (a)
(
PARTITIONSET ps1 VALUES (1,2,3)
(PARTITION p1 VALUES (1))
);

--------------------------------------------------------------------------------
-- Tier 4: subpartition read_only / indexing clauses + column annotations
--------------------------------------------------------------------------------

-- read_only_clause on range_subpartition_desc (inside composite range partitioning)
CREATE TABLE comp_range_ro (a NUMBER, d DATE)
PARTITION BY RANGE (d)
SUBPARTITION BY RANGE (a)
(PARTITION p0 VALUES LESS THAN (DATE '2026-01-01')
(SUBPARTITION sp0 VALUES LESS THAN (100) READ ONLY,
SUBPARTITION sp1 VALUES LESS THAN (MAXVALUE) READ WRITE INDEXING OFF));

-- indexing_clause on individual_hash_subparts
CREATE TABLE comp_hash_idx (a NUMBER, b NUMBER)
PARTITION BY RANGE (a)
SUBPARTITION BY HASH (b)
(PARTITION p0 VALUES LESS THAN (100)
(SUBPARTITION sp0 INDEXING ON,
SUBPARTITION sp1 INDEXING OFF));

-- annotations_clause on column definition (Oracle 23c)
CREATE TABLE annotated_cols (
id NUMBER ANNOTATIONS (Display 'Identifier'),
name VARCHAR2(100) ANNOTATIONS (ADD Display 'Name', MaxLength '100')
);
Loading
Loading