From 7b192262b16b03aa543970a08f80614d14bf2047 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumarb@google.com>
Date: Tue, 28 Apr 2026 11:11:57 +0530
Subject: [PATCH v30 1/5] Include schema-qualified names in publication error
 messages.

Previously, error messages in check_publication_add_relation() only
reported the relation name when a table could not be added to a
publication or included in an EXCEPT clause. This could be ambiguous
in databases where the same relation name exists in multiple schemas.

This patch updates these error messages to use schema-qualified names,
improving the clarity of error reporting for CREATE PUBLICATION and
ALTER PUBLICATION commands.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  2 +-
 src/backend/catalog/pg_publication.c          | 22 ++++++++++++++-----
 src/backend/utils/adt/ruleutils.c             | 12 ++--------
 src/backend/utils/cache/lsyscache.c           | 20 +++++++++++++++++
 src/include/utils/lsyscache.h                 |  1 +
 src/test/regress/expected/publication.out     | 12 +++++-----
 6 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 10e87acabef..4cc7f367a6e 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -288,7 +288,7 @@ DROP SUBSCRIPTION regress_pgfdw_subscription;
 -- test error case for create publication on foreign table
 -- ===================================================================
 CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
-ERROR:  cannot add relation "ft1" to publication
+ERROR:  cannot add relation "public.ft1" to publication
 DETAIL:  This operation is not supported for foreign tables.
 -- ===================================================================
 -- simple queries
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index a43d385c605..15ca3d90ebf 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -48,6 +48,18 @@ typedef struct
 								 * table. */
 } published_rel;
 
+static char *get_relation_qualified_name(Relation rel);
+
+/*
+ * Get a palloc'd string containing the schema-qualified name of the relation.
+ */
+static char *
+get_relation_qualified_name(Relation rel)
+{
+	return get_qualified_relname(RelationGetNamespace(rel),
+								 RelationGetRelationName(rel));
+}
+
 /*
  * Check if relation can be in given publication and throws appropriate
  * error if not.
@@ -67,7 +79,7 @@ check_publication_add_relation(PublicationRelInfo *pri)
 	if (pri->except && targetrel->rd_rel->relispartition)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg(errormsg, RelationGetRelationName(targetrel)),
+				 errmsg(errormsg, get_relation_qualified_name(targetrel)),
 				 errdetail("This operation is not supported for individual partitions.")));
 
 	/* Must be a regular or partitioned table */
@@ -75,26 +87,26 @@ check_publication_add_relation(PublicationRelInfo *pri)
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg(errormsg, RelationGetRelationName(targetrel)),
+				 errmsg(errormsg, get_relation_qualified_name(targetrel)),
 				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
 
 	/* Can't be system table */
 	if (IsCatalogRelation(targetrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg(errormsg, RelationGetRelationName(targetrel)),
+				 errmsg(errormsg, get_relation_qualified_name(targetrel)),
 				 errdetail("This operation is not supported for system tables.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
 	if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg(errormsg, RelationGetRelationName(targetrel)),
+				 errmsg(errormsg, get_relation_qualified_name(targetrel)),
 				 errdetail("This operation is not supported for temporary tables.")));
 	else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg(errormsg, RelationGetRelationName(targetrel)),
+				 errmsg(errormsg, get_relation_qualified_name(targetrel)),
 				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 75b77bb39f1..71c207c2cd0 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13876,23 +13876,15 @@ generate_qualified_relation_name(Oid relid)
 {
 	HeapTuple	tp;
 	Form_pg_class reltup;
-	char	   *relname;
-	char	   *nspname;
 	char	   *result;
 
 	tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
 	if (!HeapTupleIsValid(tp))
 		elog(ERROR, "cache lookup failed for relation %u", relid);
 	reltup = (Form_pg_class) GETSTRUCT(tp);
-	relname = NameStr(reltup->relname);
-
-	nspname = get_namespace_name_or_temp(reltup->relnamespace);
-	if (!nspname)
-		elog(ERROR, "cache lookup failed for namespace %u",
-			 reltup->relnamespace);
-
-	result = quote_qualified_identifier(nspname, relname);
 
+	result = get_qualified_relname(reltup->relnamespace,
+								   NameStr(reltup->relname));
 	ReleaseSysCache(tp);
 
 	return result;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 3de10d4df7e..01eefe0ff45 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3628,6 +3628,26 @@ get_namespace_name_or_temp(Oid nspid)
 		return get_namespace_name(nspid);
 }
 
+/*
+ * get_qualified_relname
+ * 	Get a palloc'd string containing the schema-qualified name of the relation
+ *  for the given namespace ID and relation name.
+ */
+char *
+get_qualified_relname(Oid nspid, char *relname)
+{
+	char	   *nspname;
+	char	   *result;
+
+	nspname = get_namespace_name_or_temp(nspid);
+	if (!nspname)
+		elog(ERROR, "cache lookup failed for namespace %u", nspid);
+
+	result = quote_qualified_identifier(nspname, relname);
+
+	return result;
+}
+
 /*				---------- PG_RANGE CACHES ----------				 */
 
 /*
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 8d5e92e07be..261fa6a2c42 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -200,6 +200,7 @@ extern bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
 extern void free_attstatsslot(AttStatsSlot *sslot);
 extern char *get_namespace_name(Oid nspid);
 extern char *get_namespace_name_or_temp(Oid nspid);
+extern char *get_qualified_relname(Oid nspid, char *relname);
 extern Oid	get_range_subtype(Oid rangeOid);
 extern Oid	get_range_collation(Oid rangeOid);
 extern Oid	get_range_constructor2(Oid rangeOid);
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 0345f6c5e47..826310f657e 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -458,7 +458,7 @@ Excluded from publications:
 Number of partitions: 1 (Use \d+ to list them.)
 
 CREATE PUBLICATION testpub9 FOR ALL TABLES EXCEPT (TABLE testpub_part1);
-ERROR:  cannot specify relation "testpub_part1" in the publication EXCEPT clause
+ERROR:  cannot specify relation "public.testpub_part1" in the publication EXCEPT clause
 DETAIL:  This operation is not supported for individual partitions.
 CREATE TABLE tab_main (a int) PARTITION BY RANGE(a);
 -- Attaching a partition is not allowed if the partitioned table appears in a
@@ -1499,23 +1499,23 @@ UPDATE testpub_tbl4 set a = 3;
 DROP TABLE testpub_tbl4;
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
-ERROR:  cannot add relation "testpub_view" to publication
+ERROR:  cannot add relation "public.testpub_view" to publication
 DETAIL:  This operation is not supported for views.
 CREATE TEMPORARY TABLE testpub_temptbl(a int);
 -- fail - temporary table
 CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
-ERROR:  cannot add relation "testpub_temptbl" to publication
+ERROR:  cannot add relation "pg_temp.testpub_temptbl" to publication
 DETAIL:  This operation is not supported for temporary tables.
 DROP TABLE testpub_temptbl;
 CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
 -- fail - unlogged table
 CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
-ERROR:  cannot add relation "testpub_unloggedtbl" to publication
+ERROR:  cannot add relation "public.testpub_unloggedtbl" to publication
 DETAIL:  This operation is not supported for unlogged tables.
 DROP TABLE testpub_unloggedtbl;
 -- fail - system table
 CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
-ERROR:  cannot add relation "pg_publication" to publication
+ERROR:  cannot add relation "pg_catalog.pg_publication" to publication
 DETAIL:  This operation is not supported for system tables.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
@@ -1537,7 +1537,7 @@ Tables:
 
 -- fail - view
 ALTER PUBLICATION testpub_default ADD TABLE testpub_view;
-ERROR:  cannot add relation "testpub_view" to publication
+ERROR:  cannot add relation "public.testpub_view" to publication
 DETAIL:  This operation is not supported for views.
 ALTER PUBLICATION testpub_default ADD TABLE testpub_tbl1;
 ALTER PUBLICATION testpub_default SET TABLE testpub_tbl1;
-- 
2.49.0

