Skip to content

feat: Add PostgreSQL Extension Support#437

Open
NFUChen wants to merge 3 commits into
pgplex:mainfrom
NFUChen:feat/upstream-pr-extension-detection
Open

feat: Add PostgreSQL Extension Support#437
NFUChen wants to merge 3 commits into
pgplex:mainfrom
NFUChen:feat/upstream-pr-extension-detection

Conversation

@NFUChen
Copy link
Copy Markdown

@NFUChen NFUChen commented May 16, 2026

Summary

  • Automatically detect extensions required by schema objects (e.g., btree_gist for EXCLUDE constraints, citext/hstore for column types) by querying pg_depend catalog dependencies
  • Generate CREATE EXTENSION IF NOT EXISTS statements in migration output, ordered before all schema objects to satisfy dependencies
  • Support extension diffing (add/drop detection) between old and new schemas

Changes

IR Layer

  • ir/ir.go: Added Extensions []string field to IR struct and new Extension struct implementing DiffSource
  • ir/inspector.go: New buildExtensions() method that queries pg_catalog.pg_depend to find extensions used by constraints, classes, types, and functions in the target schema (excludes plpgsql and extension-internal objects)

Diff Layer

  • internal/diff/diff.go: New DiffTypeExtension, extension comparison logic in GenerateMigration(), and CREATE EXTENSION IF NOT EXISTS DDL generation at the top of generateCreateSQL()

Plan & Dump

  • internal/plan/schema_plan.go: Added TypeExtension to object ordering (first in dependency order)
  • internal/dump/formatter.go: Added extensions directory to multi-file output and mapping for extension type

Tests

  • ir/inspector_extension_test.go: Tests that empty schemas don't detect extensions, and schemas with EXCLUDE constraints correctly detect btree_gist
  • testdata/diff/dependency/extension_btree_gist/: New test fixture for btree_gist extension with EXCLUDE USING gist constraint
  • Updated fixtures: add_pk, add_column_cross_schema_custom_type to include expected extension output

@NFUChen NFUChen force-pushed the feat/upstream-pr-extension-detection branch from e2bef36 to 60ee1be Compare May 16, 2026 08:40
@NFUChen NFUChen changed the title feat: implement extension detection and management in schema diff feat: Add PostgreSQL Extension Support May 16, 2026
@NFUChen NFUChen marked this pull request as ready for review May 16, 2026 16:04
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 16, 2026

Greptile Summary

This PR adds PostgreSQL extension support to schema inspection and migration generation. The main changes are:

  • Extension names are added to the IR.
  • pg_depend is queried to detect extensions used by schema objects.
  • Migration output can emit CREATE EXTENSION IF NOT EXISTS before schema objects.
  • Plan and dump output now include extension object types and directories.
  • Fixtures cover btree_gist, citext, and hstore extension cases.

Confidence Score: 2/5

These extension workflows need fixes before merging.

  • Removing an extension from the desired schema is detected but never written to migration SQL.

  • Extensions installed into non-public schemas can be recreated in the wrong schema.

  • Desired-state planning can fail before extension detection runs for common extension-backed types and constraints.

  • internal/diff/diff.go

  • ir/inspector.go

  • desired-state apply flow in internal/postgres

Important Files Changed

Filename Overview
ir/inspector.go Adds dependency-based extension detection, but it runs after desired SQL application and only stores extension names.
internal/diff/diff.go Adds extension diffing and create DDL, but drops are not emitted and extension schema placement is lost.
internal/plan/plan.go Adds extension ordering to plan summaries and dependency ordering.
internal/dump/formatter.go Adds multi-file dump grouping for extension steps.

Reviews (1): Last reviewed commit: "refactor: streamline extension and colum..." | Re-trigger Greptile

Comment thread internal/diff/diff.go
Comment on lines +487 to +489
for _, ext := range oldIR.Extensions {
if !newExtSet[ext] {
diff.droppedExtensions = append(diff.droppedExtensions, ext)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Dropped extensions ignored

This records extensions that disappeared from the desired IR, but the drop generation path never reads droppedExtensions or emits DROP EXTENSION. When the last citext or hstore usage is removed, the migration can remove the dependent schema objects while leaving the extension installed, so the database does not converge to the desired state.

Comment thread internal/diff/diff.go
Source: &ir.Extension{Name: ext},
CanRunInTransaction: true,
}
collector.collect(context, fmt.Sprintf("CREATE EXTENSION IF NOT EXISTS %s;", ir.QuoteIdentifier(ext)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Extension schema lost

The IR only carries extname, so this DDL always creates the extension in the default extension schema instead of the schema where the inspected extension objects live. The updated add_column_cross_schema_custom_type fixture installs hstore with CREATE EXTENSION ... SCHEMA utils, but the generated migration emits CREATE EXTENSION IF NOT EXISTS hstore; and then adds a column of type utils.hstore. On a target database without hstore, this creates public.hstore and the later utils.hstore reference still fails.

Comment thread ir/inspector.go
Comment on lines +68 to +69
if err := i.buildExtensions(ctx, schema, targetSchema); err != nil {
return nil, fmt.Errorf("failed to build extensions: %w", err)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Detection runs too late

Extension detection only happens after the desired SQL has already been applied to the temporary plan schema. If a desired file contains CREATE TABLE users (email citext); or an EXCLUDE constraint that needs btree_gist, ApplySchema fails with the missing type/operator before BuildIR can inspect dependencies and add the CREATE EXTENSION step. This means the new auto-detection path only works when the planning database already has the needed extension installed or the desired SQL creates it manually.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants