Skip to content

Policy expressions show perpetual diff due to schema qualification mismatch #220

@asonawalla

Description

@asonawalla

Problem

When using pgschema plan against a database with RLS policies that reference functions in the public schema, pgschema reports changes even when the policies are semantically identical. This creates a perpetual diff that reappears after every apply.

Reproduction

  1. Create a function and policy:
CREATE FUNCTION public.auth_uid() RETURNS uuid AS $$
  SELECT gen_random_uuid();
$$ LANGUAGE sql;

CREATE TABLE public.users (
  id uuid PRIMARY KEY,
  org_id uuid NOT NULL
);

ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;

CREATE POLICY "select_own" ON public.users FOR SELECT
  USING (org_id IN (SELECT auth_uid()));
  1. Create a schema file with the same policy (using unqualified auth_uid()):
CREATE POLICY "select_own" ON public.users FOR SELECT
  USING (org_id IN (SELECT auth_uid()));
  1. Run pgschema plan --schema public - it shows a modification even though nothing changed.

  2. Run pgschema apply - applies the "change".

  3. Run pgschema plan again - the same modification reappears.

Root Cause

There's a mismatch between how pgschema normalizes expressions and how PostgreSQL stores them:

Stage Expression
Schema file auth_uid()
pgschema internal representation public.auth_uid() (adds schema prefix)
DDL generated by pgschema SELECT public.auth_uid() AS auth_uid
PostgreSQL stores (via pg_get_expr) auth_uid() (strips public. since it's in search_path)

When pgschema compares desired vs actual:

  • Desired (after pgschema normalization): public.auth_uid()
  • Actual (from pg_get_expr): auth_uid()
  • Result: perpetual diff

Relation to Issue #218

This is similar to #218 ("Schema qualifiers stripped from column default expressions"), but in the opposite direction and for a different object type:

Aspect #218 This Issue
Object type Column defaults Policy USING/WITH CHECK
Direction pgschema was losing qualification pgschema is adding qualification
Fix approach Normalization during comparison Same approach could work

The #218 fix added normalization logic to treat ::public.status and ::status as equivalent during comparison. A similar normalization for function calls in policy expressions would resolve this issue.

Expected Behavior

pgschema plan should show no changes when the policy expressions are semantically equivalent, regardless of whether the function reference is schema-qualified.

Environment

  • pgschema version: 1.5.1
  • PostgreSQL version: 15.x (via Supabase local)
  • Target schema: public

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions