Skip to content

fix: recreate dependent views around a function DROP + CREATE (#601) - #619

Merged
tianzhou merged 2 commits into
mainfrom
fix/issue-601-function-recreate-dependent-view
Sep 20, 2026
Merged

tianzhou merged 2 commits into
mainfrom
fix/issue-601-function-recreate-dependent-view

Conversation

@tianzhou

Copy link
Copy Markdown
Contributor

Summary

A function change that CREATE OR REPLACE cannot apply (return type, parameter names, OUT parameters) is planned as DROP FUNCTION + CREATE FUNCTION (#326). Views calling that function were absent from the plan — their definition text is identical on both sides — so apply failed with cannot drop function ... because other objects depend on it (SQLSTATE 2BP01).

Changes in internal/diff:

  • View diff: a view (or materialized view) whose live definition calls a recreated function is marked RequiresRecreate, alongside the existing recreated-column trigger from GENERATED ALWAYS AS expression changes are ignored by plan #591. This also routes it through the existing privilege/comment/index/trigger restoration for recreated views.
  • Modify phase: functions recreated under views are hoisted ahead of the modify-views phase. Their calling views and transitive dependents are pre-dropped (reusing the Bug: DROP COLUMN ordered before dependent view's DROP within same group, apply fails #444 pre-drop logic, extracted into preDropViewsWithDependents), the function is dropped and created, then modify-views emits only the CREATEs. Other modified functions keep their current position.
  • Create phase: a new view calling a recreated function is held until after the recreation (same batch as Dependency ordering issue on views and functions #480), otherwise it would bind to the old function and block its drop.
  • Modify views: a view that is both marked for recreation and a dependent of another recreated view is rebuilt once, in the dependents phase after the view it reads exists. Previously its CREATE was emitted twice, the first possibly before its base view was back.

No CASCADE is used; all drops stay RESTRICT.

Known limitation (unchanged, not in scope): other dependents of a recreated function — column defaults, CHECK constraints, generated columns, expression indexes, policies — are still not handled. Matching is by function name, so an overload of a recreated function can cause a redundant view recreation.

Fixes #601

Test plan

New case testdata/diff/dependency/issue_601_function_recreate_dependent_view covering: an unchanged view with comment + grant, a stacked view that also calls the function, a materialized view with an index, a newly added view calling the function, and a recreated function with no dependents (stays on the old path).

PGSCHEMA_TEST_FILTER="dependency/issue_601" go test -v ./internal/diff -run TestDiffFromFiles
PGSCHEMA_TEST_FILTER="dependency/issue_601" go test -v ./cmd -run TestPlanAndApply

Confirmed red before the fix (apply failed with 2BP01). Also ran locally: full ./internal/diff, and TestPlanAndApply for dependency/, create_function/, create_view/, create_materialized_view/.

🤖 Generated with Claude Code

A function change that CREATE OR REPLACE cannot apply (return type,
parameter names, OUT parameters) is planned as DROP FUNCTION + CREATE
FUNCTION. Views calling the function were left out of the plan, so the
drop failed with SQLSTATE 2BP01.

Views whose live definition calls such a function now go through the
recreate cycle: the views (and their transitive dependents) are dropped,
the function is recreated, and the modify-views phase creates the views
again with comments, indexes, triggers and grants. New views calling the
function are held until it has been recreated so they do not bind to the
old one. A view that is both marked for recreation and a dependent of
another recreated view is now rebuilt once, after the view it reads.

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

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.

Copilot review overview

🟢 Approval recommended

The dependency ordering fix is coherent and covered by a focused end-to-end regression fixture.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes function recreation when existing or newly added views depend on the function, ensuring dependency-safe ordering and restoration of associated view metadata.

Changes:

  • Detects views that call functions requiring DROP + CREATE.
  • Pre-drops calling views and transitive dependents, then recreates them in dependency order.
  • Adds regression fixtures covering regular/materialized/stacked/new views, comments, grants, and indexes.
File Description
internal/​diff/​diff.go Detects function-dependent views and coordinates recreation ordering.
internal/​diff/​view.go Prevents duplicate recreation of dependent views.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​old.sql Defines the source regression schema.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​new.sql Defines the desired regression schema.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​diff.sql Records expected migration DDL.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​plan.sql Records expected SQL plan output.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​plan.json Records expected JSON plan output.
testdata/​diff/​dependency/​issue_601_function_recreate_dependent_view/​plan.txt Records expected text plan output.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@greptile-apps

greptile-apps Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

This PR is not safe to merge until modified views that newly call recreated functions and dependencies spanning the new function batches are ordered correctly.

Findings

  1. P1 New view dependency missed ▶
  2. P1 Function dependencies cross batches ▶

Summary

This PR extends migration dependency handling so views that call functions requiring DROP-and-CREATE are removed and rebuilt around the function recreation.

  • Marks unchanged calling views for recreation and preserves their attached comments, privileges, indexes, and triggers.
  • Defers newly added calling views until the recreated function is available.
  • Reuses transitive dependent-view pre-drop logic and prevents duplicate recreation of stacked views.
  • The new function partition misses newly introduced calls from modified views and does not preserve dependencies between the resulting function batches.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Classify recreated functions] --> B{Called by detected view?}
  B -->|Yes| C[Pre-drop calling views]
  C --> D[Recreate hoisted functions]
  D --> E[Recreate or modify views]
  B -->|No| E
  E --> F[Recreate remaining functions]
  F --> G[Restore privileges]
  H[Modified view newly calls function] -. missed because old definition is checked .-> B
  I[Hoisted function calls remaining function] -. dependency crosses batches .-> D
Loading

Reviews (1) · Last reviewed commit: "fix: recreate dependent views around a f..."

Comment thread internal/diff/diff.go
Comment thread internal/diff/diff.go
)

A modified view whose desired definition newly calls a function being
dropped and created again was updated first, bound to the old function,
and blocked its drop. Consider the desired definition of modified views
when deciding which recreated functions run ahead of the views.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@tianzhou
tianzhou merged commit bf67b66 into main Sep 20, 2026
1 check 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.

Function return-type change does not recreate a dependent view; apply fails with SQLSTATE 2BP01

2 participants