Skip to content

View normalization from #316 does not converge through the temporary plan schema #519

Description

@hoyaaaa

Summary

First, thank you for maintaining pgschema.

The fix from #316 appears not to cover the plan-time temporary-schema path completely. With pgschema v1.12.0, a view that calls an extension function can still produce the same CREATE OR REPLACE VIEW modification on every plan, even after the plan has been applied.

This looks closely related to #314, but it is still reproducible when the desired schema is inspected through the temporary plan schema.

Environment

  • pgschema: v1.12.0
  • PostgreSQL: 17.x
  • Extension: ltree installed in public
  • Desired state validation: temporary plan schema (pgschema_tmp_*)

Minimal example

Desired schema:

CREATE EXTENSION IF NOT EXISTS ltree;

CREATE OR REPLACE VIEW categories_valid AS
SELECT id
FROM categories
WHERE nlevel(path) = 8;

After applying the generated plan, a subsequent plan still reports a view modification whose effective difference is:

- nlevel(path)
+ public.nlevel(path)

Applying that modification does not make the next plan converge.

What may be happening

From reading the v1.12.0 code, normalizeView() strips qualifiers using view.Schema:

view.Definition = StripSchemaPrefixFromBody(view.Definition, view.Schema)

For the desired state, however, view.Schema is still pgschema_tmp_* at that point. Since nlevel belongs to the public extension schema, public.nlevel(...) is not considered a same-schema reference and remains qualified.

Later, normalizeSchemaNames() changes the view schema from the temporary schema to public, but the view definition only receives replaceString():

view.Schema = toSchema
view.Definition = replaceString(view.Definition)

Unlike column expressions, policy expressions, and trigger conditions, the view definition does not appear to receive stripQualifiers() after the temporary schema is normalized. This seems to leave the comparison as:

current: nlevel(path)
desired: public.nlevel(path)

Expected behavior

Same-schema qualification of an extension function should not cause a repeated view diff, and a second plan after apply should report no changes.

Possible direction

Would it make sense to apply the same post-normalizeSchemaNames() qualifier stripping to view definitions, for example:

view.Definition = stripQualifiers(replaceString(view.Definition))

A regression test that exercises the actual temporary-schema path with an extension function in public may also help, since the unit test added in #316 starts with both the view schema and function qualifier already set to public.

I’d also be open to contributing a pull request if that would be useful, but I’m equally happy for this to be handled in whatever way works best for the project. Thank you for taking a look.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions