GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(postgres): types, domains and partitions as real schemas use them by jasdeepkhalsa · Pull Request #285 · DBDiff/DBDiff

Conversation

@jasdeepkhalsa

@jasdeepkhalsa jasdeepkhalsa commented Nov 3, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Running DBDiff against widely used public schemas (AdventureWorks, Pagila, GitLab's structure.sql, a pgvector table) turned up eight PostgreSQL shapes that generated wrong or unrunnable migrations. None of them is in the synthetic corpus. Four were silent: the migration ran, and a re-diff called the result identical.

Shape Before After
varchar(20)[], numeric(10,2)[], timestamptz(3)[], bit(4)[] _varchar, _numeric, … — modifier lost, and the re-diff saw no difference character varying(20)[], … spelled by format_type
Array of a mixed-case or non-public type ("Mood"[], app.status[]) _Mood, _status — type does not exist "Mood"[], app.status[]
vector(1536) (any extension type with a modifier) vector — an HNSW index on it then fails vector(1536)
Domain "Name" in public Name, which folds to the built-in name type "Name"
Domain gains a CHECK … NOT VALID DROP DOMAIN + CREATE DOMAIN … NOT VALID — a syntax error, and the drop fails while columns use it ALTER DOMAIN … ADD CONSTRAINT … NOT VALID
Column added to a partitioned table ADD COLUMN on the parent and every partition — refused on the parent only
Partition in another schema than its parent parent named in the partition's schema — does not exist parent named in its own schema
Partitioned table whose id comes from a sequence it owns (each partition carrying the default) sequence created and the column written bigserial, so a second …_seq1 sequence fed every partition one sequence, as on the source
PostgreSQL 18 virtual generated column written STORED, and stored vs virtual compared as identical VIRTUAL; a change between them drops and re-adds the column

The array and domain spellings matter for the built-in renderer, which runs whenever no pg_dump at least as new as the server is installed. Domain changes and partitioned tables were wrong under both renderers.

A domain is still replaced when its base type or collation changes, since ALTER DOMAIN can't do that.

Tests

  • tests/RealWorldShapesPostgresTest.php covers each shape as a live round trip (UP, re-diff empty, DOWN restores). It runs under both renderers. Because the re-diff was itself blind to the lost modifiers, each case also compares the catalog directly: format_type per column, domain constraints with convalidated, and partition parents.
  • tests/Unit/PostgresColumnTypeTest.php covers type spelling.
  • In ObjectKindsSQLTest, the domain cases now pin ALTER DOMAIN, and a separate case keeps the base-type change as a replacement.
  • The virtual-column cases run on PostgreSQL 18 and skip on older servers.
  • DBDiff's Corpus suite passes on PostgreSQL 17 and 18 against the six matching new pg-conformance migration cases.
  • Against master, 9 of the 11 new round-trip cases and 7 of the 11 new unit cases fail. The two round-trip cases that pass on master are the pg_dump-renderer variants of the domain and array tests, which pg_dump already rendered correctly.
  • The Unit and Postgres suites pass locally on PostgreSQL 17 and 18 (PHP 8.3): 347 Postgres and 165 Corpus tests on each, and the new unit tests pass on PHP 8.4.

MySQL, SQLite and Dolt are unaffected. Every change is in PostgreSQL-only code. The shared TableSchema path only skips columns PostgreSQL reports as inherited, which the other engines never report. The MySQL matrix in CI confirms it.

🤖 Generated with Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@jasdeepkhalsa @claude
fix(postgres): types, domains and partitions as real schemas use them
8acd4d2
Run against widely used public schemas (AdventureWorks, Pagila, GitLab's
structure.sql, pgvector), PostgreSQL migrations were wrong in six ways the
synthetic corpus had no case for.

- An array column was written as the catalog's internal name, `_varchar`:
  varchar(20)[] became varchar[], numeric(10,2)[] numeric[], bit(4)[]
  bit(1)[], and an array of a mixed-case or non-public type (`_Mood`,
  `_status`) did not resolve. The re-diff then compared the same internal
  names and called the columns identical. Arrays are now spelled by the
  server, format_type(atttypid, atttypmod).
- A type modifier on an extension type was dropped: vector(1536) became
  vector, on which an HNSW index fails ("column does not have dimensions").
- A domain in `public` was written bare. `"Name"` folded to PostgreSQL's own
  `name` type, so its columns were created with a different type, and
  `"Flag"` failed as unknown. It is quoted wherever it needs to be.
- A changed domain was dropped and recreated, which fails while any column
  uses it. A default, NOT NULL or CHECK change is now made with ALTER DOMAIN;
  only a new base type or collation still replaces it.
- A NOT VALID check was written into CREATE DOMAIN, which does not accept
  it. It is added after the domain exists, still unvalidated.
- A column added to a partitioned table was also added to every partition,
  which PostgreSQL refuses ("cannot add column to a partition"); a column a
  table only inherits is no longer added or dropped on it. And a partition in
  another schema than its parent named the parent in its own schema.

MySQL, SQLite and Dolt are unaffected: every change is in PostgreSQL-only
code, and the shared TableSchema path only skips columns PostgreSQL reports
as inherited, which other engines never do.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions github-actions Bot added bug mysql Related to Mysql php Pull requests that update php code postgres Related to Postgres sqlite Related to Sqlite labels Nov 3, 2026
@jasdeepkhalsa jasdeepkhalsa mentioned this pull request Nov 3, 2026
corpus: six migration shapes from real-world schemas akalsoftware/pg-conformance#19
Merged
jasdeepkhalsa and others added 2 commits November 3, 2026 01:38
@jasdeepkhalsa @claude
fix(postgres): a virtual generated column stays virtual
df8f9b7
PostgreSQL 18 adds virtual generated columns, and makes them the default.
Every generated column was written STORED, so a virtual one was created
stored, and the comparison could not tell them apart: the kind was not in
the pre-scan hash, the column definition parser skipped the keyword, and a
change between the two was not a regeneration.

The kind is now read from attgenerated, written as VIRTUAL or STORED, hashed,
and compared; a change between them drops and re-adds the column, as
PostgreSQL cannot switch it in place. A generated column recreated around a
dependency's retype keeps its kind.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jasdeepkhalsa @claude
fix(postgres): a partitioned table's own sequence is created once
a19e9df
GitLab's `uploads` takes its id from a sequence it owns, and every partition
carries a copy of the default. Counted as further uses, those copies made the
sequence look shared, so it was modelled standalone and created — while the
column was still written bigserial, which made a second sequence
(`uploads_id_seq1`) that every partition's default then pointed at. A default
on a column the table inherits is no longer counted.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jasdeepkhalsa jasdeepkhalsa mentioned this pull request Nov 3, 2026
ci: SupaForge on real-world sample databases akalsoftware/supaforge#161
Merged
@jasdeepkhalsa @claude
refactor(postgres): inline the generated-column kind into columnSuffix
4298174
Keeps PostgresSchemaHelper within the 20-method limit; no behaviour change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Nov 3, 2026

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
0.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jasdeepkhalsa
jasdeepkhalsa merged commit 7a81510 into master Nov 4, 2026
78 checks passed

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

bug mysql Related to Mysql php Pull requests that update php code postgres Related to Postgres sqlite Related to Sqlite

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@jasdeepkhalsa
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.