Skip to content

fix: carry ON DELETE SET NULL/SET DEFAULT column list on foreign keys (#589) - #590

Merged
tianzhou merged 2 commits into
mainfrom
fix/issue-589-fk-delete-set-columns
Sep 9, 2026
Merged

fix: carry ON DELETE SET NULL/SET DEFAULT column list on foreign keys (#589)#590
tianzhou merged 2 commits into
mainfrom
fix/issue-589-fk-delete-set-columns

Conversation

@tianzhou

@tianzhou tianzhou commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

ON DELETE SET NULL (cols) / ON DELETE SET DEFAULT (cols) (PG15+, pg_constraint.confdelsetcols) was never read by the inspector, so the column list was dropped from generated DDL and ignored by constraint comparison. A composite FK meant to clear one column cleared all of them, and plan reported no drift in either direction.

  • ir/queries/queries.sql: both constraint queries now return delete_set_columns as a JSON array of column names via a LATERAL aggregate over to_jsonb(c) -> 'confdelsetcols', which stays safe on PG14 where the attribute does not exist. sqlc code regenerated.
  • ir/ir.go / ir/inspector.go: new Constraint.DeleteSetColumns.
  • internal/diff/constraint.go, internal/diff/table.go, internal/plan/rewrite.go: emit the column list after ON DELETE SET NULL/SET DEFAULT; constraintsEqual now compares it, so a database lacking the list gets the constraint recreated.

Fixes #589

Test plan

Folded into testdata/diff/create_table/add_fk: a composite FK with SET NULL (col), one with SET DEFAULT (col), and an existing FK without the list that gains it (drop + re-add). Fails before the fix, passes after.

PGSCHEMA_TEST_FILTER="create_table/add_fk" go test ./internal/diff -run TestDiffFromFiles
PGSCHEMA_TEST_FILTER="create_table/add_fk" go test ./cmd -run TestPlanAndApply

Also ran locally: all create_table/ diff cases, ./internal/plan, ./ir, and create_table/add_uk on PG14 to confirm the query works without confdelsetcols.

🤖 Generated with Claude Code

…#589)

Read pg_constraint.confdelsetcols (PG15+) in the constraint query, store it
on ir.Constraint as DeleteSetColumns, emit it after ON DELETE SET NULL /
SET DEFAULT in all three FK DDL generators, and include it in constraint
comparison so a database missing the column list is recreated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 9, 2026 03:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Delete-action column lists need order-independent comparison to avoid unnecessary constraint recreation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Preserves PostgreSQL foreign-key column lists for ON DELETE SET NULL/SET DEFAULT during inspection, comparison, and DDL generation.

Changes:

  • Safely reads and stores confdelsetcols.
  • Compares and renders delete-action column lists.
  • Adds regression fixtures for creation and drift detection.

A moderate issue remains: delete-action columns are compared in order, causing unnecessary constraint recreation when semantically equivalent lists are reordered.

File summaries
File Description
testdata/diff/create_table/add_fk/plan.txt Updates text plan fixture.
testdata/diff/create_table/add_fk/plan.sql Updates SQL plan fixture.
testdata/diff/create_table/add_fk/plan.json Updates JSON plan fixture.
testdata/diff/create_table/add_fk/old.sql Adds source FK scenarios.
testdata/diff/create_table/add_fk/new.sql Adds desired column-list definitions.
testdata/diff/create_table/add_fk/diff.sql Records expected migration DDL.
ir/queries/queries.sql.go Regenerates sqlc bindings.
ir/queries/queries.sql Extracts delete-set column names.
ir/ir.go Adds DeleteSetColumns to constraints.
ir/inspector.go Decodes inspected column lists.
internal/plan/rewrite.go Preserves lists during online FK rewrites.
internal/diff/table.go Uses shared delete-clause rendering.
internal/diff/constraint.go Compares and renders lists; comparison must ignore column order.
Review details

Files not reviewed (1)

  • ir/queries/queries.sql.go: Generated file
  • Files reviewed: 12/13 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/diff/constraint.go Outdated
@greptile-apps

greptile-apps Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR preserves PostgreSQL 15+ foreign-key delete-action column lists throughout catalog inspection, IR comparison, canonical DDL generation, and online constraint rewrites.

  • Reads pg_constraint.confdelsetcols through PostgreSQL-version-compatible catalog queries.
  • Adds the inspected column list to the constraint IR and drift comparison.
  • Quotes and renders the list for both ordinary and rewritten foreign-key creation.
  • Extends the foreign-key fixtures to cover SET NULL, SET DEFAULT, and constraint recreation when the list changes.

Confidence Score: 5/5

The PR appears safe to merge; the new foreign-key metadata remains aligned across inspection, comparison, SQL rendering, rewrites, and regression fixtures.

No actionable correctness, security, compatibility, or repository-rule violation remains after reviewing the changed catalog contract and all downstream consumers.

Important Files Changed

Filename Overview
ir/queries/queries.sql Adds compatibility-safe extraction of delete-action column names to both constraint queries while preserving catalog order.
ir/queries/queries.sql.go Regenerates the typed query rows and scan order consistently with the updated SQL.
ir/inspector.go Decodes the query's JSON column-name array into the constraint IR and returns contextual errors for malformed data.
ir/ir.go Adds the PostgreSQL 15+ delete-action column list to the shared constraint representation.
internal/diff/constraint.go Compares the new field and centralizes quoted rendering of foreign-key ON DELETE clauses.
internal/diff/table.go Reuses the shared ON DELETE renderer for foreign keys emitted during table diff generation.
internal/plan/rewrite.go Preserves and quotes delete-action column lists when foreign-key additions are rewritten through NOT VALID and validation steps.
testdata/diff/create_table/add_fk/new.sql Adds desired-state coverage for SET NULL, SET DEFAULT, and changing an existing foreign key's delete column list.
testdata/diff/create_table/add_fk/old.sql Defines the corresponding source states used to verify additions and recreation.
testdata/diff/create_table/add_fk/diff.sql Captures expected canonical DDL including quoted-capable delete-action column-list rendering.
testdata/diff/create_table/add_fk/plan.json Updates structured plan expectations for staged creation and validation of the new foreign keys.
testdata/diff/create_table/add_fk/plan.sql Updates executable plan SQL expectations with the preserved column lists.
testdata/diff/create_table/add_fk/plan.txt Updates human-readable plan output and transaction-group numbering for the added cases.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    PG[(pg_constraint.confdelsetcols)] --> Q[Catalog queries]
    Q --> I[Inspector]
    I --> IR[Constraint.DeleteSetColumns]
    IR --> C[Constraint comparison]
    IR --> D[Canonical FK DDL]
    IR --> R[Online FK rewrite]
    C -->|Drift detected| D
    D --> P[Migration plan]
    R --> P
Loading

Reviews (1): Last reviewed commit: "fix: carry ON DELETE SET NULL/SET DEFAUL..." | Re-trigger Greptile

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The reviewed changes have regression coverage and no unresolved issues.

Review details

Files not reviewed (1)

  • ir/queries/queries.sql.go: Generated file
  • Files reviewed: 12/13 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@tianzhou
tianzhou merged commit 738a3bb into main Sep 9, 2026
2 checks passed
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.

ON DELETE SET NULL (column) column list is dropped, and the difference is invisible to plan

2 participants