From 7f7037ff8013072040aae80565f19ae992520fa5 Mon Sep 17 00:00:00 2001 From: Dilip Kumar Date: Mon, 6 Jul 2026 12:57:05 +0530 Subject: [PATCH v1] doc: Add catalog documentation for logical replication conflict log settings Document the pg_subscription catalog columns subconflictlogrelid and subconflictlogdest in catalogs.sgml, which were introduced as part of the configurable conflict log table feature. Also update ddl.sgml to use proper markup for the term "conflict schema". --- doc/src/sgml/catalogs.sgml | 26 ++++++++++++++++++++++++++ doc/src/sgml/ddl.sgml | 2 +- src/backend/catalog/catalog.c | 13 ++++++++++++- src/backend/commands/policy.c | 5 ----- src/backend/commands/tablecmds.c | 20 -------------------- src/backend/commands/trigger.c | 10 ---------- src/backend/rewrite/rewriteDefine.c | 10 ---------- 7 files changed, 39 insertions(+), 47 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 4b474c13917..7cdd9bd564a 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -8737,6 +8737,32 @@ SCRAM-SHA-256$<iteration count>:&l + + + subconflictlogrelid oid + (references pg_class.oid) + + + OID of the subscription conflict log table created in the + pg_conflict namespace, or zero if + conflict_log_destination + is set to log. + + + + + + subconflictlogdest text + + + The destination for conflict logging: log (server + log only), table (conflict log table only), or + all (both). See + conflict_log_destination + for details. + + + subconninfo text diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 2b08b54edf5..4d50957bd77 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -3771,7 +3771,7 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC; The pg_conflict schema (sometimes referred to as the - conflict schema) contains system-managed conflict + conflict schema) contains system-managed conflict log tables used for logical replication conflict tracking. These tables are created and maintained by the system and are not intended for direct user manipulation. Unlike pg_catalog, the diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index be8791af875..3f59e59ef9c 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -236,7 +236,9 @@ IsToastClass(Form_pg_class reltuple) * IsConflictLogTableClass * True iff pg_class tuple represents a Conflict Log Table. * - * Does not perform any catalog accesses. + * Does not perform any catalog accesses. See + * IsConflictLogTableNamespace() for why operations on these tables are + * restricted. */ bool IsConflictLogTableClass(Form_pg_class reltuple) @@ -285,6 +287,15 @@ IsToastNamespace(Oid namespaceId) * True iff namespace is pg_conflict. * * Does not perform any catalog accesses. + * + * Tables in the pg_conflict namespace are conflict log tables, created and + * maintained by the system to record logical replication conflicts. The + * apply worker's inserts depend on their fixed structure, so they are treated + * as system-managed: call sites across the backend use this (and + * IsConflictLogTableClass()) to reject operations that could disrupt logging, + * such as DDL, manual INSERT/UPDATE/MERGE, and row locking. DELETE and + * TRUNCATE are the only data operations allowed, so that users can still + * prune old conflict rows. */ bool IsConflictLogTableNamespace(Oid namespaceId) diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 4ca086bf4bb..f4bc29b9eca 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -79,11 +79,6 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid, if (!object_ownercheck(RelationRelationId, relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not be modified directly, as it could - * disrupt conflict logging. - */ if (IsConflictLogTableClass(classform)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cb93c3e935a..d2cb0376ac3 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3908,11 +3908,6 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(myrelid)), NameStr(classform->relname)); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not be modified directly, as it could - * disrupt conflict logging. - */ if (IsConflictLogTableClass(classform)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -10254,11 +10249,6 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, errmsg("referenced relation \"%s\" is not a table", RelationGetRelationName(pkrel)))); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not be referenced by foreign keys, as it - * could disrupt conflict logging. - */ if (IsConflictLogTableClass(pkrel->rd_rel)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -20271,11 +20261,6 @@ RangeVarCallbackOwnsRelation(const RangeVar *relation, aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)), relation->relname); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not be modified directly, as it could - * disrupt conflict logging. - */ if (IsConflictLogTableClass((Form_pg_class) GETSTRUCT(tuple))) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -20318,11 +20303,6 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, if (!object_ownercheck(RelationRelationId, relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not be altered directly, as it could - * disrupt conflict logging. - */ if (IsConflictLogTableClass(classform)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 401baddbfc6..fb99a017304 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -314,11 +314,6 @@ CreateTriggerFiringOn(const CreateTrigStmt *stmt, const char *queryString, RelationGetRelationName(rel)), errdetail_relkind_not_supported(rel->rd_rel->relkind))); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not have triggers, as it could disrupt - * conflict logging. - */ if (IsConflictLogTableClass(rel->rd_rel)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -1456,11 +1451,6 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid, if (!object_ownercheck(RelationRelationId, relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), rv->relname); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not have triggers, as it could disrupt - * conflict logging. - */ if (IsConflictLogTableClass(form)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 46de580cbe6..ec09a6aadeb 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -262,11 +262,6 @@ DefineQueryRewrite(const char *rulename, RelationGetRelationName(event_relation)), errdetail_relkind_not_supported(event_relation->rd_rel->relkind))); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not have rules, as it could disrupt - * conflict logging. - */ if (IsConflictLogTableClass(event_relation->rd_rel)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -769,11 +764,6 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid, errmsg("relation \"%s\" cannot have rules", rv->relname), errdetail_relkind_not_supported(form->relkind))); - /* - * Conflict log tables are used internally for logical replication - * conflict logging and should not have rules, as it could disrupt - * conflict logging. - */ if (IsConflictLogTableClass(form)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), -- 2.49.0