Skip to content

fix: order routines after relations referenced by their signature - #311

Draft
dilame wants to merge 1 commit into
stripe:mainfrom
dilame:fix/function-relation-row-type-deps
Draft

dilame wants to merge 1 commit into
stripe:mainfrom
dilame:fix/function-relation-row-type-deps

Conversation

@dilame

@dilame dilame commented Sep 26, 2026

Copy link
Copy Markdown

What changed

Adds tracking and ordering for the relations whose row type a function or procedure names in its signature.

  • New GetDependsOnRelations query reads, from pg_depend, the relations (relkind in r, p, v, m) whose row type appears in a routine's signature — an argument type, the RETURNS type, or a RETURNS TABLE column — including references through the row type's array type.
  • Function and Procedure gain DependsOnRelations; RelationDependency carries the relkind so the edge can target the generator that owns the relation.
  • The function and procedure generators order a routine after every relation it references, and order its DROP before theirs. Views and materialized views are covered too — the procedure generator's blanket "after every table" ordering never covered them.

Why

PostgreSQL resolves a routine's argument and return types at CREATE time, so a relation named there must already exist. That relation's row type is a pg_type entry, but it is not a standalone composite type, so no existing dependency query saw it. A plan that created such a routine before the relation failed plan validation with type <schema>.<relation> does not exist.

The tempting alternative — ordering every routine after every table, the best-effort approach the procedure generator already takes — is unsafe: it closes a cycle whenever a domain's CHECK calls the routine while a table column is typed with that domain (routine → table → domain → routine). Only the relations a signature actually references are ordered.

Validation

go test ./...

New acceptance cases cover a table row type as a function argument, as a RETURNS TABLE column, a view row type as an argument (function and procedure), and the matching DROP order, each asserting the exact statement order.

The domain CHECK regression case for the cycle above cannot live in this branch — it needs domains. It lives in the fork's integration branch alongside #306 as glue, the same way COMMENT ON DOMAIN does.

A function or procedure whose signature names a relation's row type — an
argument type, the RETURNS type, or a RETURNS TABLE column — is validated by
PostgreSQL at CREATE time, so that relation must exist first and must be dropped
after. Track those dependencies per relation kind (table, view, materialized
view) from pg_depend and add the matching ordering edges.

This replaces the unsafe alternative of ordering a routine after every table:
that closes a cycle whenever a domain's CHECK calls the routine while a table
column is typed with the domain (routine -> table -> domain -> routine). Only
the relations the signature actually references are ordered.
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