You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 72fa91a
Browse filesBrowse the repository at this point in the historyBrowse files
feat(schema): model LIKE and PARTITION OF tables and partition links
CREATE TABLE copies the columns of a modeled LIKE source or partition
parent in written order, models () as a table without columns, and
rejects AS SELECT, OF type, and INHERITS with their line. A partition
follows its parent's column changes, rename, and DROP TABLE until
DETACH PARTITION, and ATTACH PARTITION of a modeled table links it.
Copy file name to clipboardExpand all lines: docs/postgresql.md
+93-5Lines changed: 93 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -376,6 +376,12 @@ are recorded with their declared type; see
376
376
| Table-level `FOREIGN KEY (...) REFERENCES ...`, named or unnamed | Accepted and ignored. |
377
377
| Table-level `CHECK (...)`, named or unnamed | Accepted and ignored. |
378
378
| Table-level `EXCLUDE USING ... (...)`, named or unnamed | Accepted and ignored. |
379
+
|`LIKE t`, with any `INCLUDING` and `EXCLUDING` options | Accepted. Copies the columns, types, and nullability of the modeled table `t` at the position the clause stands in. |
380
+
|`PARTITION OF t`, with `FOR VALUES FROM ... TO ...`, `FOR VALUES IN (...)`, `FOR VALUES WITH (MODULUS ...)`, or `DEFAULT`| Accepted. Copies the columns, types, and nullability of the modeled table `t` and keeps following its column changes; see [Ordered Table DDL](#ordered-table-ddl). |
381
+
| An empty element list, `()`| Accepted and modeled as a table without columns. |
382
+
|`AS SELECT ...`| Rejected as `Unsupported CREATE TABLE clause: AS SELECT at line <n>`. |
383
+
|`OF <type>`| Rejected as `Unsupported CREATE TABLE clause: OF <type> at line <n>`. |
384
+
|`INHERITS (p)`| Rejected as `Unsupported CREATE TABLE clause: INHERITS at line <n>`. |
379
385
| A table statement sqlcj's parser cannot read, such as `ALTER FOREIGN TABLE`| Rejected; see [Ignored Statements](#ignored-statements). |
380
386
| Any other table-constraint kind | Rejected. |
381
387
| Unparsable SQL | Rejected. |
@@ -386,6 +392,36 @@ pipeline reads it, so it changes no generated type, method, parameter, or
386
392
result component. "Ignored" means the construct is accepted as valid schema
387
393
input and is not carried into the model at all.
388
394
395
+
A `CREATE TABLE` element list may state column definitions, table constraints,
396
+
and `LIKE` clauses in any order, and the table's columns are modeled in that
397
+
written order, as PostgreSQL creates them, each `LIKE` contributing its source's
398
+
columns at its own position. A partition starts with its parent's columns,
399
+
before every element of its own list. A column name that is repeated, by two
400
+
column definitions, by a `LIKE` and a column definition, or by two `LIKE`
401
+
clauses, fails as `Column already exists in table <t>: <c>`.
402
+
403
+
A `LIKE`'s `INCLUDING` and `EXCLUDING` options cannot change a copied column's
404
+
type or nullability and are ignored, and neither `LIKE` nor `PARTITION OF`
405
+
copies its source's recorded constraints: a copy records only the constraints
406
+
its own statement states. A `LIKE` copy is independent of its source afterwards,
407
+
as in PostgreSQL. A `LIKE` or `PARTITION OF` source sqlcj does not model fails
408
+
as `Table not found in schema: <t>`.
409
+
410
+
Because sqlcj models one namespace, a `LIKE` or `PARTITION OF` source and an
411
+
`ATTACH` or `DETACH PARTITION` partition resolve by their unqualified name, so
412
+
`public.t` is `t`. Until sqlcj models namespaces, such a name qualified with any
413
+
other schema names a table sqlcj leaves unmodeled and fails as
414
+
`Table not found in schema: <schema>.<t>` rather than resolving to a modeled `t`.
415
+
416
+
A `CREATE TABLE` with neither an element list, `()`, nor `PARTITION OF`, such as
417
+
`CREATE TABLE c LIKE t` without the parentheses PostgreSQL requires, states no
418
+
columns at all and is rejected as
419
+
`Unsupported schema statement: CREATE TABLE at line <n>`. A form sqlcj's parser
420
+
cannot read, such as the column options `PARTITION OF` and `OF <type>` allow
421
+
(`id WITH OPTIONS NOT NULL`) or `AS SELECT ... WITH NO DATA`, is rejected as
422
+
unreadable table DDL with the parser's reason; see
423
+
[Ignored Statements](#ignored-statements).
424
+
389
425
## Ordered Table DDL
390
426
391
427
A schema of `CREATE TABLE` statements alone is modeled exactly as it was before
@@ -397,14 +433,16 @@ statements and files before them left; the enum-type statements are listed in
397
433
| --- | --- |
398
434
|`CREATE TABLE`| Adds the table after the tables already modeled. |
399
435
|`CREATE TABLE IF NOT EXISTS`| Does nothing when the table already exists. |
400
-
|`DROP TABLE`, with one or several names | Removes each named table. |
436
+
|`DROP TABLE`, with one or several names | Removes each named table and, recursively, every partition of it, as PostgreSQL does. |
401
437
|`DROP TABLE IF EXISTS`| Does nothing for a name that is not modeled. |
402
438
|`ALTER TABLE ... ADD COLUMN`| Appends the column, typed exactly as a `CREATE TABLE` column of the same declaration, and records its column-level `PRIMARY KEY` or `UNIQUE`. |
403
439
|`ALTER TABLE ... ADD COLUMN IF NOT EXISTS`| Does nothing when the column already exists. |
404
440
|`ALTER TABLE ... DROP COLUMN`| Removes the column and every recorded constraint that lists it. |
405
441
|`ALTER TABLE ... DROP COLUMN IF EXISTS`| Does nothing when the column is not modeled. |
406
442
|`ALTER TABLE ... RENAME COLUMN`| Renames the column in its position and in the constraints that list it. |
407
-
|`ALTER TABLE ... RENAME TO`| Renames the table in its position, keeping its columns and constraints. |
443
+
|`ALTER TABLE ... RENAME TO`| Renames the table in its position, keeping its columns and constraints, and keeps every partition of it linked to the new name. |
444
+
|`ALTER TABLE ... ATTACH PARTITION`| Links a modeled table to the altered one, so it follows its column changes from then on. A partition sqlcj does not model is ignored. |
445
+
|`ALTER TABLE ... DETACH PARTITION`| Ends the link of a modeled partition. A partition sqlcj does not model is ignored. |
408
446
|`ALTER TABLE ... ALTER COLUMN ... TYPE`| Maps or records the new type as a `CREATE TABLE` column of that type is mapped or recorded, keeping the column's position and its nullability, which a type change does not state. |
409
447
|`ALTER TABLE ... ALTER COLUMN ... SET NOT NULL`| Models the column non-null. |
410
448
|`ALTER TABLE ... ALTER COLUMN ... DROP NOT NULL`| Models the column nullable. |
@@ -416,6 +454,16 @@ One `ALTER TABLE` may state several actions; they are applied in the written
416
454
order. Table and column names are matched case-insensitively, as query analysis
417
455
looks them up, after their SQL identifier delimiters are removed.
418
456
457
+
PostgreSQL applies every column change of a partitioned table to its partitions,
458
+
so a partition created by `PARTITION OF`, or attached by `ATTACH PARTITION` when
459
+
sqlcj models its table, stays linked to its parent: `ADD COLUMN`,
460
+
`DROP COLUMN`, `RENAME COLUMN`, `ALTER COLUMN ... TYPE`, `SET NOT NULL`, and
461
+
`DROP NOT NULL` on the parent are applied to its partitions as well,
462
+
recursively, so a nested partition follows too. A partition keeps its own name
463
+
when its parent is renamed, `DROP TABLE` of the parent removes it, and
464
+
`DETACH PARTITION` ends the link, after which the parent's later column changes
465
+
no longer reach it. A `LIKE` copy is never linked to its source.
466
+
419
467
Outside the `IF [NOT] EXISTS` forms above, a statement that refers to a table or
420
468
a column that is not modeled is rejected, and so is a statement that would give
421
469
two tables, or two columns of one table, the same name, as PostgreSQL rejects it:
@@ -476,6 +524,7 @@ what they would do to the schema model:
476
524
| Statement | Diagnostic |
477
525
| --- | --- |
478
526
| An `ALTER TABLE` action outside [Ordered Table DDL](#ordered-table-ddl) and the ignored actions below |`Unsupported ALTER TABLE action: <action> at line <n>`, quoting the action's own SQL |
527
+
| A `CREATE TABLE ... AS SELECT`, `OF <type>`, or `INHERITS`, whose columns sqlcj cannot determine |`Unsupported CREATE TABLE clause: <clause> at line <n>`, naming `AS SELECT`, `OF <type>`, or `INHERITS`|
479
528
| An `ALTER TYPE ... SET SCHEMA` of a modeled enum type |`Unsupported ALTER TYPE action: SET SCHEMA <schema> at line <n>`|
480
529
| A statement sqlcj's parser cannot read that opens as table or type DDL, outside the `ALTER TABLE` actions below | The parser's own reason with the line and column of the unexpected token, as in `Encountered unexpected token: "DATA" at line 18, column 41`|
481
530
| A statement sqlcj's parser reports only as opaque text, or as several statements, and that opens as table or type DDL |`Unsupported schema statement: ALTER FOREIGN TABLE at line <n>`, quoting the opening words |
@@ -505,7 +554,7 @@ statement still resolves its table:
505
554
|`ALTER [COLUMN] c DROP EXPRESSION`| Only the readable spelling; `DROP EXPRESSION IF EXISTS` is unreadable. |
506
555
|`ALTER [COLUMN] c ADD GENERATED ... AS IDENTITY`, `SET GENERATED ...`, a sequence option such as `SET INCREMENT BY 2`, `RESTART`, and `DROP IDENTITY [IF EXISTS]`| PostgreSQL requires the column to be `NOT NULL` already, so an identity never changes nullability. |
507
556
|`ENABLE`, `DISABLE`, `FORCE`, and `NO FORCE ROW LEVEL SECURITY`||
508
-
|`ATTACH PARTITION` and `DETACH PARTITION`| The partition's own table is modeled by its own statements. |
557
+
|`ATTACH PARTITION` and `DETACH PARTITION`of a table sqlcj does not model | A modeled partition is linked or unlinked instead, as [Ordered Table DDL](#ordered-table-ddl) states. |
509
558
|`OWNER TO`||
510
559
|`ENABLE TRIGGER`, `DISABLE TRIGGER`, `ENABLE REPLICA TRIGGER`, and `ENABLE ALWAYS TRIGGER`, and the same four for `RULE`||
511
560
|`VALIDATE CONSTRAINT`||
@@ -701,6 +750,8 @@ and recorded type:
701
750
```text
702
751
sqlcj: Invalid schema source /home/dev/project/schema.sql: Unsupported schema statement: ALTER FOREIGN TABLE at line 12
703
752
sqlcj: Invalid schema source /home/dev/project/schema.sql: Unsupported ALTER TABLE action: SET SCHEMA archive at line 18
753
+
sqlcj: Invalid schema source /home/dev/project/schema.sql: Unsupported CREATE TABLE clause: AS SELECT at line 24
754
+
sqlcj: Invalid schema source /home/dev/project/schema.sql: Table not found in schema: reporting.events
704
755
sqlcj: Invalid schema source /home/dev/project/schema.sql: Encountered unexpected token: ";" at line 4, column 1
705
756
sqlcj: Invalid query 'ListTags' in /home/dev/project/queries.sql at line 5: Column 'tags' has unsupported type JSONB[]
706
757
```
@@ -857,6 +908,29 @@ Enum types:
857
908
-`DefaultSchemaParserTest.shouldRejectUnsupportedSchemaStatement` and
0 commit comments