Skip to content

Add function, view, and materialized view dependency ordering#286

Open
da77a wants to merge 1 commit into
stripe:mainfrom
da77a:function-view-deps
Open

Add function, view, and materialized view dependency ordering#286
da77a wants to merge 1 commit into
stripe:mainfrom
da77a:function-view-deps

Conversation

@da77a
Copy link
Copy Markdown

@da77a da77a commented May 16, 2026

Function and view dependency ordering

This PR adds dependency tracking for functions, views, and materialized views so that pg-schema-diff (mostly) correctly orders DDL statements when these objects reference each other.

Motivation

Less cases where manual migration authoring is needed due to cascading dependencies issues involving objects other than tables.

This is the second attempt after some "working except when it doesn't" problems found using the first attempt.

Approach

This attempt created failing test cases systematically for the unsupported/failing scenarios, then fixed (most of) them.

What works

From-scratch creation — given any schema containing interdependent functions, views, and materialized views, the generated plan creates objects in the correct order:

  • Functions that reference tables/views via FROM/JOIN (qualified and unqualified)
  • Functions that use %ROWTYPE or [] composite type declarations
  • Views that call functions
  • Views that depend on other views
  • Materialized views that depend on views, functions, or other materialized views
  • Cross-schema dependencies

Incremental migration — when a table change forces a view to be recreated (column rename/delete), dependent views and materialized views are cascaded:

  • View A depends on View B, View B is recreated → View A is also recreated
  • Materialized view depends on a view being recreated → matview is also recreated
  • Materialized view depends on another matview being recreated → cascades correctly
  • Multi-level chains (A → B → C → table) propagate correctly

Identical-schema diffs — diffing a schema against itself produces an empty plan, even when views depend on other views or call functions.

Known gaps (with failing tests documenting each)

Gap Reason
Comma-separated FROM t1, t2, t3 — only first table detected Regex cannot distinguish from column lists without a parser
Function calling another function in body pg_depend does not track fn→fn for SQL functions; body-text detection only covers table/view refs
Function return type change requiring drop+create CREATE OR REPLACE is always emitted, PG rejects if return type differs

Approach

  1. pg_depend-based tracking for structural dependencies (view→table columns, view→function, matview→function) via subqueries in GetViews/GetMaterializedViews/GetProcs
  2. Body-text regex for dependencies pg_depend does not track (plpgsql %ROWTYPE, [], and FROM/JOIN references in function bodies) — best-effort, used for ordering only
  3. Cascade propagation after the initial diff pass — if a view/matview is being recreated, anything that depends on it is also marked for recreation
  4. Cycle prevention — reverse ordering edges (function must be altered before its old table dep) are only emitted for dependencies being removed, not persisting ones

Testing

Acceptance test cases covering all the above scenarios, including the documented gaps (marked with expectedPlanErrorContains).

- Track function→table/view deps via pg_depend + body-text regex
- Track view→function deps via pg_depend
- Track matview→function deps via pg_depend
- Include views and matviews in TableDependencies (relkind v,m)
- Cascade view/matview recreation when dependencies are recreated
- Fix cycle in function ordering (only emit reverse edges for removed deps)
- Add unqualified FROM/JOIN detection in function bodies
- Add --skip-privileges CLI flag
- 50+ acceptance tests
@da77a
Copy link
Copy Markdown
Author

da77a commented May 16, 2026

Fixes # 248 #282 #283 #284

Related:
PR #268 (partial fix abandoned due to cycles)
and #285 (first attempt at a better fix)

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.

1 participant