fix: carry ON DELETE SET NULL/SET DEFAULT column list on foreign keys (#589) - #590
Conversation
…#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>
There was a problem hiding this comment.
🟡 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.
Greptile SummaryThis PR preserves PostgreSQL 15+ foreign-key delete-action column lists throughout catalog inspection, IR comparison, canonical DDL generation, and online constraint rewrites.
Confidence Score: 5/5The 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
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
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>
There was a problem hiding this comment.
🟢 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
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, andplanreported no drift in either direction.ir/queries/queries.sql: both constraint queries now returndelete_set_columnsas a JSON array of column names via a LATERAL aggregate overto_jsonb(c) -> 'confdelsetcols', which stays safe on PG14 where the attribute does not exist. sqlc code regenerated.ir/ir.go/ir/inspector.go: newConstraint.DeleteSetColumns.internal/diff/constraint.go,internal/diff/table.go,internal/plan/rewrite.go: emit the column list afterON DELETE SET NULL/SET DEFAULT;constraintsEqualnow 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 withSET NULL (col), one withSET DEFAULT (col), and an existing FK without the list that gains it (drop + re-add). Fails before the fix, passes after.Also ran locally: all
create_table/diff cases,./internal/plan,./ir, andcreate_table/add_ukon PG14 to confirm the query works withoutconfdelsetcols.🤖 Generated with Claude Code