Skip to content

Commit 6733846

Browse files
authored
feat(postgres): adopt the expression/dialect split and declare the probes core now gates on (#61)
* refactor(postgres): carry catalogue objects instead of parsed names Core's expression and dialect layers were reworked: a relation is split into the object it names and the source that reads it, the namespace shape became a protocol the dialect states once, and to_sql() now inspects what answers a format lookup instead of calling whatever is callable. Qualified names are carried here as schema objects rather than parsed strings, which is what made the object and the statement that acts on it able to disagree about what "the same table" meant. Six types this backend does not have were being exported. COMMENT ON now renders from the object it annotates. The round-trip matrix this branch added was reporting nothing, which the refactor made visible rather than causing. Three classes it pinned as raising AttributeError name a format_method whose formatter PostgreSQL does not have, and core now reports a missing formatter as UnsupportedFeatureError -- the spelling every other capability probe in the tree already used. The pins move with it, and each now names the formatter it is missing so the entry says which gap it is. Walking PostgresDialect.__mro__ to resolve every format_* name to the class that defines it shows none of the 411 resolving to a Protocol: the stub format_* a protocol declares in the MRO are each overridden by a real mixin ahead of it. That includes CreateRoutineSupport and DropRoutineSupport, whose presence in the base list used to answer a dispatch with a protocol body returning None; the core CreateFunctionExpression and DropFunctionExpression now render. * fix(postgres): declare the sequence probes core now gates on Core commit 9dc18ab made all three sequence DDL formatters consult supports_sequence() first and unconditionally, and added four option probes (supports_sequence_start, _increment, _minvalue, _maxvalue). PostgreSQL's sequence mixin never defined supports_sequence -- core had never asked for it -- so the master switch fell back to core's default False and CREATE SEQUENCE, DROP SEQUENCE and ALTER SEQUENCE all raised UnsupportedFeatureError. A full-support dialect had stopped rendering the statement it supports. The mixin now answers every probe those formatters consult. supports_sequence, supports_create_sequence, supports_drop_sequence, supports_alter_sequence, supports_sequence_if_not_exists, supports_sequence_if_exists, and the option probes start, increment, minvalue, maxvalue, cycle, cache and owned_by all return True. supports_sequence_order returns False: the PostgreSQL CREATE SEQUENCE synopsis has no ORDER / NO ORDER clause -- that spelling is Oracle and SQL Server -- and the live server rejects it with a syntax error, so the formatter must refuse it rather than emit a clause the engine cannot parse. PostgresSequenceSupport restates the same switches, so the protocol and the mixin agree method for method. It derives from core's CreateSequenceSupport, DropSequenceSupport and AlterSequenceSupport, which is how the non-overlap guard in the protocol conformance test recognises the restatement as the deliberate overlap it is. The dialect's three redundant direct protocol bases are dropped for the same reason: a base may not precede the subclass that restates it. The three DDL formatters remain core's; this backend only answers the capability questions they ask. * fix(postgres): declare the ALTER SEQUENCE START probe explicitly Core's format_alter_sequence_statement gated AlterSequenceExpression.start on supports_sequence_start(), the probe for the CREATE SEQUENCE ... START WITH clause. Those are two different clauses, and True for one does not imply True for the other. PostgreSQL accepts START on ALTER -- it records the start value that future RESTART calls use, while RESTART WITH sets the current value -- but Oracle, SQL Server, Firebird and Snowflake all reject it. Reusing the CREATE probe for the ALTER formatter would therefore let those four dialects emit SQL their server rejects. Add supports_alter_sequence_start() to PostgresSequenceMixin, answering True because the live server accepts the clause, and declare it on PostgresSequenceSupport so the protocol keeps mirroring the mixin. The default for the new probe is False, which is the safe side: a dialect that accepts the clause must say so explicitly, as this one does. * feat(postgres): declare the identity probes and gate identity DDL on them Core made the identity and auto-increment nodes fail-closed: IdentityClause consults supports_identity_column() plus one probe per option, and AutoIncrementClause consults supports_auto_increment_column(). PostgreSQL declared none of the new probes -- the dialect did not mix in the identity mixin at all -- so core's formatters refused every identity clause. Declare the measured boundary: supports_identity_column() is True from PostgreSQL 10 on, because PostgreSQL 9 rejects the clause with `syntax error at or near "GENERATED"` (measured) while 10 through 19 all accept it. The six option probes -- generation ALWAYS, start, increment, minvalue, maxvalue, cycle -- answer True: they are part of the same synopsis. supports_auto_increment_column() answers False: PostgreSQL has no AUTO_INCREMENT spelling, and the probe is declared explicitly rather than inherited from the fail-closed default. The legacy is_auto_increment constraint now routes through the gated identity formatter, so PostgreSQL 9 refuses an identity request instead of rendering a GENERATED clause its server rejects. There is no fallback to SERIAL: the SERIAL type family stays available for users who ask for it explicitly, and it keeps executing on every version. PostgresIdentitySupport and PostgresAutoIncrementSupport mirror the two new mixins; the protocol conformance test pairs them with the existing forward/reverse coverage. The new execution-confirmation suite renders and executes each clause against a live server: accepted where the probe says True, NOT_RENDERED on PostgreSQL 9 where it says False, with a rejected sentinel and an accepted control before each verdict. The PG9 identity example now uses the supported IdentityAttribute path instead of a keyword ColumnDefinition never accepted. * feat(postgres): consume the clause-parameter pairs and close the dialect gaps Core split every two-spelling clause into one parameter per spelling (438b7aa): unspecified means neither parameter, both means ValueError. The PostgreSQL formatters still read the pre-split fields, so this follows. Formatters consuming a pair: - format_truncate_statement: restart_identity|continue_identity (CONTINUE IDENTITY was silently dropped) and cascade|restrict (RESTRICT was silently dropped). - format_create_materialized_view_statement and format_refresh_materialized_view_pg_statement: with_data|no_data; unspecified renders no tail (the old else-branch spelled WITH NO DATA). - format_drop_materialized_view_statement: cascade|restrict (RESTRICT was silently dropped). - format_begin_transaction / format_set_transaction: deferrable|not_deferrable; [NOT] DEFERRABLE renders whenever requested, not only alongside SERIALIZABLE, and unspecified no longer spells NOT DEFERRABLE. - _format_exclude_constraint: deferrable|not_deferrable and initially_deferred|initially_immediate; INITIALLY ... renders as the independent constraint attribute it is. - format_copy_to_statement: force_array|force_array_false. - format_table_constraint: the enforced gate no longer reads a tri-state, so table constraints render again instead of refusing every state. Dialect-specific nodes split to the pair shape: - PostgresRefreshMaterializedViewExpression: with_data|no_data. - PostgresCopyToExpression: force_array|force_array_false. - PostgresCreateMaterializedViewExpression: with_data|no_data (its constructor dropped no_data and defaulted to WITH DATA). - PostgresDropMaterializedViewExpression: restrict pass-through. - PostgresExcludeConstraint: deferrable|not_deferrable and initially_deferred|initially_immediate. The audit registry did not carry this node; it was found by the sweep and measured before/after. New probes declared True (measured against live PostgreSQL 16 and 19): supports_schema_restrict, supports_restrict_view, supports_drop_function_restrict, supports_materialized_view_restrict, supports_truncate_restrict, and supports_identity_cache. The CACHE option's negative spelling, NO CACHE, has no PostgreSQL form (syntax error, measured), so no_cache is refused by name for sequences and identity while cache=n renders; ORDER/NO ORDER stay refused. The transaction manager now drives the split setters, so set_deferrable(False) renders NOT DEFERRABLE instead of raising. Behaviour changes (intended, per the round): - CREATE MATERIALIZED VIEW default no longer emits WITH NO DATA. - SET TRANSACTION with nothing requested no longer emits NOT DEFERRABLE. - BEGIN ... DEFERRABLE renders for any isolation level. - RESTRICT and CONTINUE IDENTITY become reachable where they were dropped. Guard: test_clause_pair_guard.py asserts the four states of every pair the dialect consumes are pairwise distinguishable; run red against the unmodified tree first (24 failing test ids), green after. Two mutations (one removed exclusion check, one reverted restrict branch) were each caught by the expected guard test. * feat(postgres): declare the master probes core now gates on Core's c4d6adc gave call sites to three probes that had been decorative: format_cte_expression consults supports_materialized_cte(), format_truncate_statement consults supports_truncate(), and the CTAS / CREATE MATERIALIZED VIEW / REFRESH MATERIALIZED VIEW renderers consult the new supports_with_data_clause() before spelling WITH [NO] DATA. It also added supports_transaction_wait() for the wait / no_wait pair. A dialect that leaves any of them to a core default refuses statements it used to render: this package answered the with-data probe False through core's default, and its transaction formatters dropped the wait pair entirely. Declare each from measurement or the documented grammar: - supports_materialized_cte() keeps its >= 12 gate (already declared here). Live measurement: 9.6, 10 and 11 reject AS MATERIALIZED / AS NOT MATERIALIZED with a syntax error; 12 through 19beta4 accept both. - supports_truncate() answers True explicitly. TRUNCATE is in the synopsis of every supported version and the live matrix accepts it everywhere. - supports_with_data_clause() answers True, version-independent. The clause is in all three synopses -- the CTAS form long predates materialized views, and CREATE / REFRESH MATERIALIZED VIEW ... [ WITH [ NO ] DATA ] is documented from 9.3 (the version that introduced materialized views) -- and the live matrix accepts every form. The same probe covers the REFRESH form; it needs no probe of its own. - supports_transaction_wait() answers False. BEGIN NO WAIT and SET TRANSACTION NO WAIT are syntax errors on every measured server (9.6 through 19beta4); PostgreSQL has no lock-wait clause. The PostgreSQL overrides now consume the probes the core formatters consume: format_create_materialized_view_statement and format_refresh_materialized_view_pg_statement refuse WITH [NO] DATA by name when the clause probe declines (generic REFRESH and CTAS delegate to core's gate), format_truncate_statement consults supports_truncate(), and format_begin_transaction / format_set_transaction refuse wait / no_wait by name instead of silently dropping the pair. PostgresTruncateSupport, PostgresMaterializedViewSupport and PostgresTransactionSupport restate the declarations so the protocol and the mixin stay mirrored; the conformance forward / reverse coverage tests enforce the mirror. Behaviour changes (intended, per the round): - CTAS and generic REFRESH MATERIALIZED VIEW with WITH DATA / WITH NO DATA render instead of being refused by the fail-closed default. - BEGIN / SET TRANSACTION wait=True / no_wait=True raise UnsupportedFeatureError naming the option instead of rendering a statement that dropped it. Guard: test_clause_pair_guard.py adds the wait pair and a declaration / gate class; run red against the unmodified tree first (13 failing ids of 155), green after. test_master_probe_execution.py renders each clause through the live backend and asserts acceptance against the probe, with a sentinel and a control before every verdict; green on the 11-scenario matrix (9.6 through 19beta4). * ci: pin the core dependency to the merged release line The schema-object refactor these branches depend on landed on the core's release/v1.0.0.dev30 line as PR #125, so the workflow no longer needs to install the core from the feature branch. CORE_PKG now points at the release branch; the testsuite dependency stays on its own feature branch, which is not merged yet. * chore: add changelog fragment for PR #61
1 parent 9a74cca commit 6733846

218 files changed

Lines changed: 7440 additions & 2291 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/backend_development.md‎

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -273,31 +273,80 @@ Every dialect inherits from:
273273
|----------|-------|-------------|
274274
| `WindowFunctionSupport` | `WindowFunctionMixin` | Window functions (OVER, PARTITION BY) |
275275
| `CTESupport` | `CTEMixin` | Common Table Expressions (WITH clause) |
276-
| `AdvancedGroupingSupport` | `AdvancedGroupingMixin` | ROLLUP, CUBE, GROUPING SETS |
277-
| `ReturningSupport` | `ReturningMixin` | RETURNING clause |
276+
| `AdvancedGroupingSupport` | `DQLMixin` | ROLLUP, CUBE, GROUPING SETS |
277+
| `ReturningSupport` | `DMLMixin` | RETURNING clause |
278278
| `UpsertSupport` | `UpsertMixin` | UPSERT operations (ON CONFLICT) |
279279
| `LateralJoinSupport` | `LateralJoinMixin` | LATERAL joins |
280280
| `ArraySupport` | `ArrayMixin` | Array types and operations |
281281
| `JSONSupport` | `JSONMixin` | JSON types and operations |
282282
| `ExplainSupport` | `ExplainMixin` | EXPLAIN statement |
283-
| `FilterClauseSupport` | `FilterClauseMixin` | FILTER clause for aggregates |
284-
| `OrderedSetAggregationSupport` | `OrderedSetAggregationMixin` | WITHIN GROUP (ORDER BY) |
283+
| `FilterClauseSupport` | `ExpressionMixin` | FILTER clause for aggregates |
284+
| `OrderedSetAggregationSupport` | `ExpressionMixin` | WITHIN GROUP (ORDER BY) |
285285
| `MergeSupport` | `MergeMixin` | MERGE statement |
286286
| `TemporalTableSupport` | `TemporalTableMixin` | FOR SYSTEM_TIME queries |
287-
| `QualifyClauseSupport` | `QualifyClauseMixin` | QUALIFY clause |
288-
| `LockingSupport` | `LockingMixin` | FOR UPDATE, SKIP LOCKED |
287+
| `QualifyClauseSupport` | `DQLMixin` | QUALIFY clause |
288+
| `LockingSupport` | `DQLMixin` | FOR UPDATE, SKIP LOCKED |
289289
| `GraphSupport` | `GraphMixin` | Graph queries (MATCH) |
290290
| `JoinSupport` | `JoinMixin` | JOIN operations |
291291
| `SetOperationSupport` | `SetOperationMixin` | UNION, INTERSECT, EXCEPT |
292292
| `ILIKESupport` | `ILIKEMixin` | Case-insensitive LIKE |
293-
| `TableSupport` | `TableMixin` | CREATE/DROP/ALTER TABLE |
294-
| `ViewSupport` | `ViewMixin` | CREATE/DROP VIEW |
293+
| `CreateTableSupport` | `TableMixin` | CREATE TABLE |
294+
| `DropTableSupport` | `TableMixin` | DROP TABLE |
295+
| `AlterTableSupport` | `TableMixin` | ALTER TABLE |
296+
| `CreateViewSupport` | `ViewMixin` | CREATE VIEW |
297+
| `DropViewSupport` | `ViewMixin` | DROP VIEW |
298+
| `MaterializedViewSupport` | `ViewMixin` | CREATE / DROP / REFRESH MATERIALIZED VIEW |
295299
| `TruncateSupport` | `TruncateMixin` | TRUNCATE TABLE |
296-
| `SchemaSupport` | `SchemaMixin` | CREATE/DROP SCHEMA |
297-
| `IndexSupport` | `IndexMixin` | CREATE/DROP INDEX |
298-
| `SequenceSupport` | `SequenceMixin` | CREATE/DROP/ALTER SEQUENCE |
299-
| `TriggerSupport` | `TriggerMixin` | CREATE/DROP TRIGGER (SQL:1999) |
300-
| `FunctionSupport` | `FunctionMixin` | CREATE/DROP FUNCTION (SQL/PSM) |
300+
| `CreateIndexSupport` | `IndexMixin` | CREATE INDEX |
301+
| `DropIndexSupport` | `IndexMixin` | DROP INDEX |
302+
| `FulltextIndexSupport` | `IndexMixin` | CREATE / DROP FULLTEXT INDEX |
303+
| `CreateSequenceSupport` | `SequenceMixin` | CREATE SEQUENCE |
304+
| `DropSequenceSupport` | `SequenceMixin` | DROP SEQUENCE |
305+
| `AlterSequenceSupport` | `SequenceMixin` | ALTER SEQUENCE |
306+
| `CreateTriggerSupport` | `TriggerMixin` | CREATE TRIGGER (SQL:1999) |
307+
| `DropTriggerSupport` | `TriggerMixin` | DROP TRIGGER |
308+
| `CreateRoutineSupport` | `FunctionMixin` | CREATE FUNCTION (SQL/PSM) |
309+
| `DropRoutineSupport` | `FunctionMixin` | DROP FUNCTION |
310+
| `CreateSchemaSupport` | `SchemaMixin` | CREATE SCHEMA |
311+
| `DropSchemaSupport` | `SchemaMixin` | DROP SCHEMA |
312+
| `CreateDatabaseSupport` | `DatabaseMixin` | CREATE DATABASE |
313+
| `DropDatabaseSupport` | `DatabaseMixin` | DROP DATABASE |
314+
| `AlterDatabaseSupport` | `DatabaseMixin` | ALTER DATABASE |
315+
316+
##### Naming is its own protocol
317+
318+
Naming was split out of the DDL protocols above, because "does the engine have
319+
schemas" and "may a name be qualified with one" are different questions with
320+
different owners and an engine can answer them differently.
321+
322+
| Protocol | Mixin | Description |
323+
|----------|-------|-------------|
324+
| `NamespaceSupport` | `NamespaceMixin` | Whether a name may be qualified, and how it is spelled |
325+
| `TableObjectSupport` | `TableNameMixin` | Render a `Table` as its name |
326+
| `ViewObjectSupport` | `ViewNameMixin` | Render a `View` |
327+
| `MaterializedViewObjectSupport` | `MaterializedViewNameMixin` | Render a `MaterializedView` |
328+
| `ForeignTableObjectSupport` | `ForeignTableNameMixin` | Render a `ForeignTable` |
329+
| `IndexObjectSupport` | `IndexNameMixin` | Render an `Index` |
330+
| `SequenceObjectSupport` | `SequenceNameMixin` | Render a `Sequence` |
331+
| `TriggerObjectSupport` | `TriggerNameMixin` | Render a `Trigger` |
332+
| `TypeObjectSupport` | `TypeNameMixin` | Render a `Type` |
333+
| `RoutineObjectSupport` | `FunctionNameMixin` / `ProcedureNameMixin` | Render a `Function` or `Procedure` |
334+
335+
`NamespaceSupport` declares two halves that used to be one method:
336+
337+
* `validate_namespace(expr)` -- the check. Returns `None` or raises
338+
`UnsupportedFeatureError`. It is called while *rendering*, not while
339+
constructing, because at construction the dialect may not be settled and the
340+
object's slots may not be complete.
341+
* `format_qualified_name(expr)` -- the spelling. Builds the qualified name and
342+
joins the levels with `self.separator` (a class attribute, `"."` by default).
343+
344+
A dialect's own answers go in **at most one** naming-side mixin, `<Backend>
345+
NamespaceMixin`, holding only what differs from core's default. Backends that mix
346+
in core's `NamespaceMixin` unchanged put it after the `*NameMixin` block in their
347+
base list — those subclasses it, and a subclass precedes its base, so anything
348+
listed first wins the MRO lookup. That ordering is load-bearing: getting it wrong
349+
produces a dialect that answers a question from the wrong class, silently.
301350

302351
##### Principles for Adding New Protocols/Mixins
303352

@@ -315,8 +364,8 @@ Every dialect inherits from:
315364

316365
| Feature | SQL Standard? | Location |
317366
|---------|---------------|----------|
318-
| `CREATE TRIGGER` | Yes (SQL:1999) | Main Package (`TriggerSupport`) |
319-
| `CREATE FUNCTION` | Yes (SQL/PSM) | Main Package (`FunctionSupport`) |
367+
| `CREATE TRIGGER` | Yes (SQL:1999) | Main Package (`CreateTriggerSupport`) |
368+
| `CREATE FUNCTION` | Yes (SQL/PSM) | Main Package (`CreateRoutineSupport`) |
320369
| `COMMENT ON` | No (PostgreSQL/Oracle) | PostgreSQL Extension |
321370
| `CREATE TYPE ... AS ENUM` | No (PostgreSQL-specific) | PostgreSQL Extension |
322371
| `AUTO_INCREMENT` | No (MySQL-specific) | MySQL Extension |

‎.github/workflows/test.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
- name: Install activerecord and testsuite
7070
run: |
7171
pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30"
72-
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17"
72+
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/expression-schema-object-refactor"
7373
7474
- name: Create postgres scenario config
7575
run: |
@@ -280,7 +280,7 @@ jobs:
280280
- name: Install activerecord and testsuite
281281
run: |
282282
pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30"
283-
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17"
283+
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/expression-schema-object-refactor"
284284
285285
- name: Create postgres scenario config
286286
run: |
@@ -392,7 +392,7 @@ jobs:
392392
- name: Install activerecord and testsuite
393393
run: |
394394
pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30"
395-
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17"
395+
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/expression-schema-object-refactor"
396396
397397
- name: Create postgres scenario config
398398
run: |
@@ -490,7 +490,7 @@ jobs:
490490
- name: Install activerecord and testsuite
491491
run: |
492492
pip install "rhosocial-activerecord @ git+https://github.com/rhosocial/python-activerecord.git@release/v1.0.0.dev30"
493-
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@release/v1.0.0.dev17"
493+
pip install "rhosocial-activerecord-testsuite @ git+https://github.com/rhosocial/python-activerecord-testsuite.git@feature/expression-schema-object-refactor"
494494
495495
- name: Create postgres scenario config
496496
run: |

‎changelog.d/61.added.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add the PostgreSQL capability declarations the expression/dialect split asks the backend to state: `PostgresIdentityColumnMixin`/`PostgresIdentitySupport` declare SQL-standard identity columns from PostgreSQL 10 on with one probe per generation mode and sequence option (`ALWAYS`, `START`, `INCREMENT`, `MINVALUE`, `MAXVALUE`, `CYCLE`, `CACHE`) and route the legacy `is_auto_increment` column constraint through the gated formatter, `PostgresAutoIncrementMixin`/`PostgresAutoIncrementSupport` answer the bare `AUTO_INCREMENT` marker `False` explicitly, the sequence probes now cover every `CREATE`/`ALTER SEQUENCE` option including `ALTER SEQUENCE ... START WITH`, the newly measured restrict and cache probes (`supports_schema_restrict`, `supports_restrict_view`, `supports_materialized_view_restrict`, `supports_truncate_restrict`, `supports_drop_function_restrict`, `supports_identity_cache`) and the routine probes are declared, and the master probes (`supports_materialized_cte`, `supports_truncate`, `supports_with_data_clause`, `supports_transaction_wait`) let core's formatters render `WITH [NO] DATA` on CTAS, `CREATE MATERIALIZED VIEW` and `REFRESH MATERIALIZED VIEW`; the naming side is stated once in the new `PostgresNamespaceMixin`/`PostgresNamespaceSupport`, which spells `[database.][schema.]name` level by level.

‎changelog.d/61.changed.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Change what PostgreSQL renders when no spelling was requested and how unexpressible spellings fail: `CREATE MATERIALIZED VIEW` with neither `with_data` nor `no_data` set no longer appends `WITH NO DATA`, `SET TRANSACTION` with neither deferrability parameter set no longer appends `NOT DEFERRABLE`, `BEGIN ... DEFERRABLE` renders for any isolation level instead of only alongside `SERIALIZABLE`, `WAIT`/`NO WAIT` on `BEGIN`/`SET TRANSACTION` and `NO CACHE` on sequences and identity columns now raise `UnsupportedFeatureError` naming the option instead of being silently dropped or rendered, and a PostgreSQL 9 server asked for an identity column is refused instead of being handed `GENERATED ... AS IDENTITY` (the `SERIAL` type family remains the explicit pre-10 choice).

‎changelog.d/61.fixed.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix the clauses the pre-split formatters dropped or could not reach: `TRUNCATE ... CONTINUE IDENTITY` and `TRUNCATE ... RESTRICT`, `DROP MATERIALIZED VIEW ... RESTRICT`, `COPY ... FORCE_ARRAY FALSE`, table-constraint `ENFORCED`/`NOT ENFORCED` (the tri-state gate refused every state) and the `EXCLUDE` constraint's independent `DEFERRABLE`/`INITIALLY ...` attributes now render, the transaction manager's `set_deferrable(False)` renders `NOT DEFERRABLE` instead of raising, `CreateFunctionExpression`/`DropFunctionExpression` render through the core formatters instead of resolving to a protocol stub, and the six type names that were never module attributes (`VECTOR`, `HALFVEC`, `BITVEC`, `SPARSEVEC`, `GEOMETRY`, `GEOGRAPHY`) were removed from `type_values.__all__`, where they broke star imports.

‎changelog.d/61.removed.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**BREAKING**: Remove `PostgresDialect.supports_auto_increment()` (ask `supports_identity_column()` or `supports_auto_increment_column()` instead), reshape the PostgreSQL DDL expressions to carry schema objects (`PostgresCreateMaterializedViewExpression`, `PostgresDropMaterializedViewExpression`, `PostgresRefreshMaterializedViewExpression` and `PostgresAlterMaterializedViewExpression` take a `MaterializedView` instead of `view_name`/`name` plus `schema`, `PostgresCreateIndexExpression` takes `index` and `table` instead of `index_name` and `table_name`, `PostgresDropTypeExpression` takes `type` instead of `type_name` plus `schema_name`, and `PostgresCommentExpression` takes `object` instead of `object_name` plus `schema`), replace their tri-state options with one parameter per spelling (`with_data`/`no_data` on `PostgresCreateMaterializedViewExpression` and `PostgresRefreshMaterializedViewExpression`, `force_array`/`force_array_false` on `PostgresCopyToExpression`, and `deferrable`/`not_deferrable`, `initially_deferred`/`initially_immediate`, `enforced`/`not_enforced` on `PostgresExcludeConstraint`), and return `(sql, params)` from `format_materialized_view_alter_action()` instead of a bare string; setting both sides of a pair raises `ValueError` at construction.

0 commit comments

Comments
 (0)