fix: strip extension-owned type schema qualifiers to prevent false-positive diffs#517
Conversation
…sitive diffs pgschema was emitting spurious ALTER COLUMN TYPE / CREATE TABLE diffs for columns typed with extension-owned types (e.g. pgvector's `vector`) whenever the extension resolved to a different schema between the live database and the plan-time comparison environment. The type itself hadn't changed - only the schema it happened to be installed in - but the schema-unaware qualifier comparison treated `public.vector` and `domain.vector` as different types. - ir: added ExtensionName (Column, TypeColumn, Type) and HasOwnedSequence (Column) / IsOwned (Sequence), sourced from pg_depend/pg_extension joins in the schema-scoped column/domain/composite-type/sequence queries. - internal/diff: columnsEqual, typesEqual, and the CREATE-path type/column SQL generators now strip schema qualifiers unconditionally when both sides are owned by the same extension, while still catching genuine changes (e.g. a vector dimension bump). Ordinary cross-schema types (domains, enums, contrib types installed at a fixed location) are unaffected. - internal/diff: isSerialColumn and generateSequenceSQL's OWNED BY emission now require genuine sequence ownership (HasOwnedSequence/IsOwned) rather than pattern-matching on column type + nextval() default text, fixing a related false-positive where a column merely referencing another table's sequence was treated as SERIAL. - internal/diff/topological: added a dependency edge for columns whose nextval() default targets a sequence owned by a different table, so that owner is always emitted first. - testdata/dump/sakila: restored missing ALTER SEQUENCE ... OWNED BY statements that a real pg_dump would emit; their absence was masking the ownership-detection gap above. Fixes the false-positive/false-negative pair end-to-end: a plan-time schema difference for an extension-owned type produces no diff, while a genuine change (dimension, real cross-schema move of a non-extension type) still does.
|
@ayusssmaan please create an issue first and reference it from the PR. Thx |
Greptile SummaryThis PR enriches schema introspection with extension and sequence ownership metadata, normalizes extension-owned type comparisons and DDL, and adds shared-sequence dependency ordering.
Confidence Score: 2/5The PR should not be merged until extension type identity, modified standalone sequence handling, and schema-aware shared-sequence ordering are corrected. Generated DDL can fail or bind the wrong type outside the configured search_path, structural changes to referenced-but-unowned sequences can be silently omitted, and same-named sequences across schemas can produce an incorrect table creation order. internal/diff/table.go, internal/diff/type.go, internal/diff/diff.go, internal/diff/topological.go
|
| Filename | Overview |
|---|---|
| internal/diff/table.go | Extension-aware column generation fixes false diffs but emits bare extension types that may not resolve to the intended target type. |
| internal/diff/diff.go | Added and dropped sequence handling uses real ownership, while modified sequences retain the fallback owner-name heuristic and can lose structural changes. |
| internal/diff/topological.go | Adds shared-sequence ordering, but schema-less sequence keys collide across schemas. |
| internal/diff/type.go | Composite and domain comparisons account for extension ownership, while composite DDL shares the unqualified-type resolution issue. |
| ir/queries/queries.sql | Adds coordinated catalog queries for extension and sequence dependency metadata. |
| ir/inspector.go | Maps the new catalog-derived ownership fields into the IR consistently. |
| ir/ir.go | Extends columns, sequences, and types with ownership metadata consumed by diff generation. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Catalog[PostgreSQL catalogs] --> Inspector[IR Inspector]
Inspector --> Metadata[Extension and sequence ownership metadata]
Metadata --> Compare[Schema comparison]
Compare --> DDL[DDL generation]
Metadata --> Ordering[Sequence dependency ordering]
Ordering --> DDL
DDL --> Apply[Apply migration with target search_path]
Comments Outside Diff (1)
-
internal/diff/diff.go, line 1109-1110 (link)Referenced sequences remain misclassified
When a standalone or shared sequence is referenced by a column default without a real ownership dependency, the fallback owner names make this branch treat it as owned and skip structural comparison, causing requested increment, bounds, cycle, or cache changes to be silently omitted.
Context Used: CLAUDE.md (source)
Knowledge Base Used:
Reviews (1): Last reviewed commit: "fix: strip extension-owned type schema q..." | Re-trigger Greptile
| if column.ExtensionName != "" { | ||
| columnType = stripAnySchemaPrefix(columnType) | ||
| } else { | ||
| columnType = stripSchemaPrefix(columnType, targetSchema) |
There was a problem hiding this comment.
Extension type identity is lost
When an extension-owned type is installed outside the target schema and public, stripping its schema makes PostgreSQL resolve the bare name through search_path, causing the migration to fail with a missing type or bind the column to an unintended same-named type.
Context Used: CLAUDE.md (source)
Knowledge Base Used:
| sequenceOwnerTable := make(map[string]string) | ||
| for key, table := range tableMap { | ||
| for _, col := range table.Columns { | ||
| if col.HasOwnedSequence { | ||
| if seqName := nextvalTargetSequenceName(col); seqName != "" { | ||
| sequenceOwnerTable[seqName] = key | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Sequence owner keys lose schema
When two managed schemas contain same-named owned sequences, this bare-name map overwrites one owner and a qualified nextval reference can receive an edge to the wrong table, causing the referencing table to be created before the table whose SERIAL definition creates the actual sequence.
Knowledge Base Used: Diff Engine
Fixes #518
pgschema was emitting spurious ALTER COLUMN TYPE / CREATE TABLE diffs for columns typed with extension-owned types (e.g. pgvector's
vector) whenever the extension resolved to a different schema between the live database and the plan-time comparison environment. The type itself hadn't changed - only the schema it happened to be installed in - but the schema-unaware qualifier comparison treatedpublic.vectoranddomain.vectoras different types.Fixes the false-positive/false-negative pair end-to-end: a plan-time schema difference for an extension-owned type produces no diff, while a genuine change (dimension, real cross-schema move of a non-extension type) still does.