fix: support view options (security_invoker, security_barrier) in dump and plan#352
fix: support view options (security_invoker, security_barrier) in dump and plan#352
Conversation
…p and plan (#350) Add support for PostgreSQL view reloptions (security_invoker, security_barrier, check_option) across the entire pipeline: dump extracts them, plan detects changes, and generates appropriate ALTER VIEW SET/RESET migration DDL. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR adds first-class support for PostgreSQL view reloptions ( Key finding:
Confidence Score: 2/5
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[GenerateMigration] --> B{viewsEqual?}
B -- "false (structurallyDifferent)" --> C{needsRecreate?}
B -- "true" --> D{commentChanged or indexesChanged or triggersChanged?}
D -- "yes" --> E[Add viewDiff with OptionsChanged]
D -- "no" --> F[No diff generated]
C -- "true\n(mat. view OR column mismatch)" --> G["RequiresRecreate=true\n⚠️ OptionsChanged NOT set"]
C -- "false\n(regular view)" --> E
E --> H[generateModifyViewsSQL]
G --> I["DROP + CREATE OR REPLACE VIEW\n(includes WITH clause via generateViewSQL)"]
H --> J{optionsOnlyChange?}
J -- "yes" --> K["ALTER VIEW SET/RESET\n✓ Correct for regular views"]
J -- "no (def changed too)" --> L["CREATE OR REPLACE VIEW WITH (...)\n✓ Both definition and options updated"]
style G fill:#f99,stroke:#c00
style I fill:#f99,stroke:#c00
|
There was a problem hiding this comment.
Pull request overview
Adds end-to-end support for PostgreSQL view reloptions (e.g., security_invoker, security_barrier) so they are preserved in dumps and correctly planned/migrated via ALTER VIEW ... SET/RESET.
Changes:
- Extend IR + inspector to capture
pg_class.reloptionsfor views and parse them into a structuredOptionsmap. - Render view options in
CREATE [OR REPLACE] VIEW ... WITH (...)and emitALTER VIEW ... SET/RESETwhen options change. - Add dump and diff test fixtures + an integration test covering issue #350 scenarios.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
ir/ir.go |
Adds View.Options map[string]string to represent view reloptions in IR. |
ir/queries/queries.sql |
Extends view inspection query to include c.reloptions for views. |
ir/queries/queries.sql.go |
Updates generated scanning logic to read reloptions into ViewOptions. |
ir/inspector.go |
Parses reloptions entries (key=value) into the IR View.Options map. |
internal/diff/diff.go |
Tracks OptionsChanged in viewDiff to drive option-only migrations. |
internal/diff/view.go |
Emits WITH (...) in CREATE VIEW and generates ALTER VIEW ... SET/RESET for option diffs. |
cmd/dump/dump_integration_test.go |
Adds an integration test for dumping views with security_invoker / security_barrier. |
testdata/dump/issue_350_view_security_invoker/* |
New dump fixture validating options are preserved in dump output. |
testdata/diff/create_view/issue_350_*/* |
New diff fixtures validating SET/RESET behavior for option add/change/remove. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Resolve conflicts: adopt []string for View.Options (from main), update generateViewOptionChangesSQL to work with []string format, and regenerate test fixtures for new version. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge three separate test cases (add, alter, remove) into one that covers all scenarios: add via WITH, add via ALTER VIEW SET, and remove. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The diff test already covers all view options scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check if only options changed (e.g., security_invoker, security_barrier) | ||
| optionsOnlyChange := diff.OptionsChanged && definitionsEqual && diff.Old.Materialized == diff.New.Materialized | ||
|
|
||
| // Handle non-structural changes (comment-only, index-only, trigger-only, or options-only) | ||
| if commentOnlyChange || indexOnlyChange || triggerOnlyChange || optionsOnlyChange { |
There was a problem hiding this comment.
optionsOnlyChange is named as if only options changed, but the condition doesn’t enforce that (e.g., comment+options changes also satisfy it). Consider renaming it to reflect what it actually checks (options changed and definitions are equal) to avoid misleading future maintainers.
| // Check if only options changed (e.g., security_invoker, security_barrier) | |
| optionsOnlyChange := diff.OptionsChanged && definitionsEqual && diff.Old.Materialized == diff.New.Materialized | |
| // Handle non-structural changes (comment-only, index-only, trigger-only, or options-only) | |
| if commentOnlyChange || indexOnlyChange || triggerOnlyChange || optionsOnlyChange { | |
| // Check if options changed while definition and materialization are unchanged | |
| optionsChangeWithEqualDefinitionAndMaterialization := diff.OptionsChanged && definitionsEqual && diff.Old.Materialized == diff.New.Materialized | |
| // Handle non-structural changes (comment-only, index-only, trigger-only, or options change with equal definition/materialization) | |
| if commentOnlyChange || indexOnlyChange || triggerOnlyChange || optionsChangeWithEqualDefinitionAndMaterialization { |
| // generateViewOptionChangesSQL generates ALTER VIEW SET/RESET statements for option changes. | ||
| // Options are stored as sorted []string in "key=value" format (from pg_class.reloptions). | ||
| func generateViewOptionChangesSQL(diff *viewDiff, targetSchema string, collector *diffCollector) { |
There was a problem hiding this comment.
The PR description states View.Options is a map[string]string, but in code View.Options is a []string (and this helper/doc comment also describes it as a slice). Please update the PR description (or the code) so reviewers/users aren’t misled about the IR shape and JSON format.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if oldView, exists := oldViews[key]; exists { | ||
| structurallyDifferent := !viewsEqual(oldView, newView) | ||
| commentChanged := oldView.Comment != newView.Comment | ||
| optionsChanged := !viewOptionsEqual(oldView.Options, newView.Options) | ||
|
|
||
| // Check if indexes changed for materialized views | ||
| indexesChanged := false |
There was a problem hiding this comment.
Because structurallyDifferent is derived from !viewsEqual(oldView, newView) (and viewsEqual now includes Options), a materialized view reloptions-only change will be considered structural. Given the later needsRecreate := structurallyDifferent && newView.Materialized ... logic, this likely forces DROP+CREATE for matview option changes even though ALTER MATERIALIZED VIEW SET/RESET would suffice (and DROP may fail under RESTRICT). Consider basing the structural/recreate decision on definition/column changes only, and handle OptionsChanged separately via the ALTER SET/RESET path.
| diffType := DiffTypeView | ||
| viewKeyword := "VIEW" | ||
| if diff.New.Materialized { | ||
| diffType = DiffTypeMaterializedView | ||
| viewKeyword = "MATERIALIZED VIEW" | ||
| } |
There was a problem hiding this comment.
There doesn’t appear to be a diff fixture covering reloptions changes on materialized views (e.g., asserting ALTER MATERIALIZED VIEW ... SET/RESET and avoiding DROP+CREATE). Adding a targeted test case would help prevent regressions, especially given the new option diff logic shared between views and matviews.
…CREATE Separate definitionChanged from structurallyDifferent so that option-only changes on materialized views emit ALTER SET/RESET rather than a full DROP+CREATE cycle. Added materialized view (fillfactor) to the test fixture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…p and plan (pgplex#352) * fix: support view options (security_invoker, security_barrier) in dump and plan (pgplex#350) Add support for PostgreSQL view reloptions (security_invoker, security_barrier, check_option) across the entire pipeline: dump extracts them, plan detects changes, and generates appropriate ALTER VIEW SET/RESET migration DDL. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: consolidate issue 350 view options into single test case Merge three separate test cases (add, alter, remove) into one that covers all scenarios: add via WITH, add via ALTER VIEW SET, and remove. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: remove separate dump test case for issue 350 The diff test already covers all view options scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: materialized view option-only changes use ALTER instead of DROP+CREATE Separate definitionChanged from structurallyDifferent so that option-only changes on materialized views emit ALTER SET/RESET rather than a full DROP+CREATE cycle. Added materialized view (fillfactor) to the test fixture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
security_invoker,security_barrier,check_option) across the entire pipelinepgschema dumpnow includesWITH (option=value)inCREATE VIEWoutputpgschema plandetects option changes and generatesALTER VIEW SET/RESETmigration DDLCREATE VIEW ... WITH (security_invoker = true)andALTER VIEW ... SET (security_invoker = true)are handled correctlyFixes #350
Changes
ir/ir.goOptions []stringtoViewstructir/queries/queries.sqlc.reloptionsto view queryir/queries/queries.sql.goreloptionsir/inspector.gointernal/diff/view.gointernal/diff/diff.goOptionsChangedtoviewDiffstructTest plan
🤖 Generated with Claude Code