Sharing my thoughts:
On Mon, Jun 15, 2026 at 2:20 PM Amit Kapila <[email protected]> wrote:
>
> On Mon, Jun 15, 2026 at 11:57 AM vignesh C <[email protected]> wrote:
> >
> > While reviewing operations on the pg_conflict schema, I noticed a few
> > behaviors that I wasn't sure were intentional.
> > 1. REINDEX is allowed on conflict log tables
> > postgres=# REINDEX TABLE pg_conflict.pg_conflict_log_16404;
> > REINDEX
> >
> > I was not sure whether allowing REINDEX on conflict log tables is
> > intentional, given that these are system-managed tables.
> >
>
> I think this should be disallowed.
+1
I think REINDEX is harmless for CLT as curently there are no indexes,
so it should be okay to let it be. For toast-tables too, we have
simialr behaviour. We restrict index creation while REINDEX is
allowed:
postgres=# show allow_system_table_mods;
allow_system_table_mods
-------------------------
on
(1 row)
postgres=# create index on pg_toast.pg_toast_826 (chunk_id);
ERROR: cannot create index on relation "pg_toast_826"
DETAIL: This operation is not supported for TOAST tables.
postgres=# REINDEX TABLE pg_toast.pg_toast_826;
REINDEX
>
> > 2. Views are disallowed, but functions are allowed
> > Creating a view in the pg_conflict schema is rejected:
> > postgres=# CREATE VIEW v1 AS
> > SELECT * FROM pg_conflict.pg_conflict_log_16435;
> > ERROR: permission denied to create "pg_conflict.v1"
> > DETAIL: Conflict schema modifications are currently disallowed.
> >
Okay, I can create views outside the pg_conflict schema for CLT
tables, but creation fails inside pg_conflict irrespective of
'allow_system_table_mods '.
postgres=# CREATE VIEW public.v1 AS SELECT * FROM
pg_conflict.pg_conflict_log_24576;
CREATE VIEW
postgres=# CREATE VIEW pg_conflict.v1 AS SELECT * FROM
pg_conflict.pg_conflict_log_24576;
ERROR: permission denied to create "pg_conflict.v1"
DETAIL: Conflict schema modifications are currently disallowed.
While for toast table, behaviour is slightly different.
With allow_system_table_mods = off
postgres=# CREATE VIEW public.v2 AS select * from pg_toast.pg_toast_826;
CREATE VIEW
postgres=# CREATE VIEW pg_toast.v2 AS select * from pg_toast.pg_toast_826;
ERROR: permission denied to create "pg_toast.v2"
DETAIL: System catalog modifications are currently disallowed.
With allow_system_table_mods = on, view creation inside TOAST schema works:
postgres=# CREATE VIEW pg_toast.v2 AS select * from pg_toast.pg_toast_826;
CREATE VIEW
IMO, creating views can be allowed on CLT outside of CLT schema as it
can help DBAs to analyze the data better. For creating views inside
the CLT schema, we currently allow table creation (see my last email)
in the CLT schema as well. IMO, we can either disallow both or allow
both. The behaviour should be consistent.
> > However, creating a function in the same schema succeeds:
> > CREATE FUNCTION pg_conflict.get_conflict_count()
> > RETURNS bigint
> > LANGUAGE sql
> > AS $$
> > SELECT count(*) FROM pg_conflict.pg_conflict_log_16404;
> > $$;
> > CREATE FUNCTION
> >
>
> This is okay because the function is doing SELECT which we allow on
> these tables.
+1
>
> > I noticed similar behavior with the pg_toast schema as well, where
> > function creation is allowed:
> >
> > CREATE FUNCTION pg_toast.get_toast_1213_count()
> > RETURNS bigint
> > LANGUAGE sql
> > AS $$
> > SELECT count(*) FROM pg_toast.pg_toast_1213;
> > $$;
> > CREATE FUNCTION
> >
> > I am not sure what the rationale is for permitting some object types
> > while rejecting others.
> >
> > 3. Functions can be created, but triggers cannot:
> > Although function creation succeeds, trigger creation on a conflict
> > log table is rejected:
> > CREATE TRIGGER conflict_audit
> > AFTER INSERT
> > ON pg_conflict.pg_conflict_log_16435
> > FOR EACH ROW
> > EXECUTE FUNCTION get_conflict_count();
> > ERROR: permission denied: "pg_conflict_log_16435" is a conflict log table
> > DETAIL: Conflict log tables are system-managed tables for logical
> > replication conflicts.
> >
> > Again, I wasn't sure whether this distinction is intentional.
> >
>
> I have given the reason for functions above and this restriction is okay.
Functions are allowed while triggers are not. IMO, it is fine. Using
triggers, one can simply skip or perform other actions for conflict
insertions in CLT which should be strictly avoided.
>
> > 4. User-defined types and domains are allowed
> > CREATE TYPE pg_conflict.conflict_status AS ENUM ('ACTIVE', 'INACTIVE');
> > CREATE TYPE
> >
> > CREATE DOMAIN pg_conflict.positive_int
> > AS integer
> > CHECK (VALUE > 0);
> > CREATE DOMAIN
> >
> > I was also surprised that creating types and domains is permitted in
> > the pg_conflict schema.
> >
> > Overall, I am having some difficulty understanding the rules governing
> > which operations are allowed and which are disallowed in the
> > pg_conflict namespace. If these behaviors are intentional, would it
> > make sense to document the supported and unsupported operations more
> > clearly? That would help avoid confusion for users.
> >
>
> Ideally, we should allow only SELECT, DELETE, and TRUNCATE for
> allowing users to view and maintain the CLT tables. We are also
> planning to allow the LOCK command for the purpose of pg_dump.
Again, returning to my previous statement: table creations, view
creations, and type creations—either all should be allowed or none. I
do not see a strong use case for allowing tables inside the
pg_conflict schema. But since we allow these things inside other
system schemas, we can allow it here as well. I don't have a strong
case for or against these.
postgres=# create table pg_catalog.pg_conflict_log_16502(i int);
CREATE TABLE
postgres=# create view pg_catalog.v1 as select * from pg_conflict_log_16502
postgres-# ;
CREATE VIEW
postgres=# CREATE TYPE pg_catalog.conflict_status AS ENUM ('ACTIVE',
'INACTIVE');
CREATE TYPE
thanks
Shveta