Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

Started by Bharath Rupireddyalmost 5 years ago30 messages
#1Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
1 attachment(s)

Hi,

While providing thoughts on [1]/messages/by-id/CALj2ACWAxO3vSToT0o5nXL=rz5cNx90zaV-at=cvM14Tag4=cQ@mail.gmail.com, I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2]t1 is a temporary table: postgres=# CREATE PUBLICATION testpub FOR TABLE t1; ERROR: table "t1" cannot be replicated DETAIL: Temporary and unlogged relations cannot be replicated. to [3]t1 is a temporary table: postgres=# CREATE PUBLICATION testpub FOR TABLE t1; ERROR: temporary table "t1" cannot be replicated DETAIL: Temporary, unlogged and foreign relations cannot be replicated.. For instance, the
existing message when foreign table is tried to add into the
publication "f1" is not a table" looks odd. Because it says that the
foreign table is not a table at all.

Attaching a small patch. Thoughts?

[1]: /messages/by-id/CALj2ACWAxO3vSToT0o5nXL=rz5cNx90zaV-at=cvM14Tag4=cQ@mail.gmail.com
[2]: t1 is a temporary table: postgres=# CREATE PUBLICATION testpub FOR TABLE t1; ERROR: table "t1" cannot be replicated DETAIL: Temporary and unlogged relations cannot be replicated.
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR: table "t1" cannot be replicated
DETAIL: Temporary and unlogged relations cannot be replicated.

t1 is an unlogged table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR: table "t1" cannot be replicated
DETAIL: Temporary and unlogged relations cannot be replicated.

f1 is a foreign table:
postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR: "f1" is not a table
DETAIL: Only tables can be added to publications.

[3]: t1 is a temporary table: postgres=# CREATE PUBLICATION testpub FOR TABLE t1; ERROR: temporary table "t1" cannot be replicated DETAIL: Temporary, unlogged and foreign relations cannot be replicated.
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR: temporary table "t1" cannot be replicated
DETAIL: Temporary, unlogged and foreign relations cannot be replicated.

t1 is an unlogged table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR: unlogged table "t1" cannot be replicated
DETAIL: Temporary, unlogged and foreign relations cannot be replicated.

f1 is a foreign table:
postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR: foreign table "f1" cannot be replicated
DETAIL: Temporary, unlogged and foreign relations cannot be replicated.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v1-0001-Improve-error-message-while-adding-tables-to-publ.patchapplication/octet-stream; name=v1-0001-Improve-error-message-while-adding-tables-to-publ.patchDownload
From 1dca9b6887a5cb5fd96fbf115a830840ea7af97f Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 10 Mar 2021 10:38:42 +0530
Subject: [PATCH v1] Improve error message while adding tables to publication

Improve the error messages in check_publication_add_relation
from what we have [1] to bit informative as shown in [2]

[1]
t1 is a temporary table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR:  table "t1" cannot be replicated
DETAIL:  Temporary and unlogged relations cannot be replicated.

t1 is an unlogged table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR:  table "t1" cannot be replicated
DETAIL:  Temporary and unlogged relations cannot be replicated.

f1 is a foreign table:
postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR:  "f1" is not a table
DETAIL:  Only tables can be added to publications.

[2]
t1 is a temporary table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR:  temporary table "t1" cannot be replicated
DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.

t1 is an unlogged table:
postgres=# CREATE PUBLICATION testpub FOR TABLE t1;
ERROR:  unlogged table "t1" cannot be replicated
DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.

f1 is a foreign table:
postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR:  foreign table "f1" cannot be replicated
DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 +++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_publication.c          | 27 +++++++++++++++----
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 5 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 0649b6b81c..1394696e1d 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9437,3 +9437,9 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  foreign table "ft1" cannot be replicated
+DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 2b525ea44a..574b7d36df 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2928,3 +2928,8 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 84d2efcfd2..1e22921c9c 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("foreign table \"%s\" cannot be replicated",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Temporary, unlogged and foreign relations cannot be replicated.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -68,11 +76,20 @@ check_publication_add_relation(Relation targetrel)
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
 	if (targetrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+	{
+		if (RelationUsesLocalBuffers(targetrel))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("temporary table \"%s\" cannot be replicated",
+							RelationGetRelationName(targetrel)),
+					errdetail("Temporary, unlogged and foreign relations cannot be replicated.")));
+		else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("unlogged table \"%s\" cannot be replicated",
+							RelationGetRelationName(targetrel)),
+					errdetail("Temporary, unlogged and foreign relations cannot be replicated.")));
+	}
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..81ae91044b 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  temporary table "testpub_temptbl" cannot be replicated
+DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  unlogged table "testpub_unloggedtbl" cannot be replicated
+DETAIL:  Temporary, unlogged and foreign relations cannot be replicated.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#2Jeevan Ladhe
jeevan.ladhe@enterprisedb.com
In reply to: Bharath Rupireddy (#1)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Mar 10, 2021 at 10:44 AM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

Hi,

While providing thoughts on [1], I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2] to [3].

+1 for improving the error messages here.

Attaching a small patch. Thoughts?

I had a look at the patch and it looks good to me. However, I think after
you have added the specific kind of table type in the error message itself,
now the error details seem to be giving redundant information, but others
might
have different thoughts.

The patch itself looks good otherwise. Also the make check and postgres_fdw
check looking good.

Regards,
Jeevan Ladhe

#3Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Jeevan Ladhe (#2)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Mar 10, 2021 at 1:27 PM Jeevan Ladhe
<jeevan.ladhe@enterprisedb.com> wrote:

On Wed, Mar 10, 2021 at 10:44 AM Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

Hi,

While providing thoughts on [1], I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2] to [3].

+1 for improving the error messages here.

Thanks for taking a look at the patch.

Attaching a small patch. Thoughts?

I had a look at the patch and it looks good to me. However, I think after
you have added the specific kind of table type in the error message itself,
now the error details seem to be giving redundant information, but others might
have different thoughts.

The error detail is to give a bit of information of what and all
relation types are unsupported with the create publication statement.
But with the error message now showing up the type of relation, the
detail message looks redundant to me as well. If agreed, I can remove
that. Thoughts?

The patch itself looks good otherwise. Also the make check and postgres_fdw
check looking good.

Thanks.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#4Euler Taveira
euler@eulerto.com
In reply to: Bharath Rupireddy (#1)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Mar 10, 2021, at 2:14 AM, Bharath Rupireddy wrote:

While providing thoughts on [1], I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2] to [3]. For instance, the
existing message when foreign table is tried to add into the
publication "f1" is not a table" looks odd. Because it says that the
foreign table is not a table at all.

I wouldn't mix [regular|partitioned|temporary|unlogged] tables with foreign
tables. Although, they have a pg_class entry in common, foreign tables aren't
"real" tables (external storage); they even have different DDLs to handle it
(CREATE TABLE x CREATE FOREIGN TABLE).

postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR: "f1" is not a table
DETAIL: Only tables can be added to publications.

I agree that "f1 is not a table" is a confusing message at first because
foreign table has "table" as description. Maybe if we apply the negation in
both messages it would be clear (using the same wording as system tables).

ERROR: "f1" is a foreign table
DETAIL: Foreign tables cannot be added to publications.

--
Euler Taveira
EDB https://www.enterprisedb.com/

#5Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Euler Taveira (#4)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Mar 10, 2021 at 5:48 PM Euler Taveira <euler@eulerto.com> wrote:

On Wed, Mar 10, 2021, at 2:14 AM, Bharath Rupireddy wrote:

While providing thoughts on [1], I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2] to [3]. For instance, the
existing message when foreign table is tried to add into the
publication "f1" is not a table" looks odd. Because it says that the
foreign table is not a table at all.

I wouldn't mix [regular|partitioned|temporary|unlogged] tables with foreign
tables. Although, they have a pg_class entry in common, foreign tables aren't
"real" tables (external storage); they even have different DDLs to handle it
(CREATE TABLE x CREATE FOREIGN TABLE).

postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR: "f1" is not a table
DETAIL: Only tables can be added to publications.

I agree that "f1 is not a table" is a confusing message at first because
foreign table has "table" as description. Maybe if we apply the negation in
both messages it would be clear (using the same wording as system tables).

ERROR: "f1" is a foreign table
DETAIL: Foreign tables cannot be added to publications.

Thanks. Changed the error message and detail to the way we have it for
system tables presently. Attaching v2 patch for further review.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v2-0001-Improve-error-message-while-adding-tables-to-publ.patchapplication/x-patch; name=v2-0001-Improve-error-message-while-adding-tables-to-publ.patchDownload
From 885a0cc75bb167d2128f1173857a05e0972ddae7 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Thu, 11 Mar 2021 15:03:29 +0530
Subject: [PATCH v2] Improve error message while adding tables to publication

Improve the error messages in check_publication_add_relation
from what we have to a bit more informative and consistent.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 +++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_publication.c          | 27 +++++++++++++++----
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 5 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 0649b6b81c..a0cc59161e 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9437,3 +9437,9 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 2b525ea44a..574b7d36df 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2928,3 +2928,8 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 84d2efcfd2..98c77c4b9f 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -68,11 +76,20 @@ check_publication_add_relation(Relation targetrel)
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
 	if (targetrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+	{
+		if (RelationUsesLocalBuffers(targetrel))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("\"%s\" is a temporary table",
+							RelationGetRelationName(targetrel)),
+					errdetail("Temporary tables cannot be added to publications.")));
+		else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("\"%s\" is an unlogged table",
+							RelationGetRelationName(targetrel)),
+					errdetail("Unlogged tables cannot be added to publications.")));
+	}
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#6Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#5)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Thu, Mar 11, 2021 at 8:26 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Mar 10, 2021 at 5:48 PM Euler Taveira <euler@eulerto.com> wrote:

On Wed, Mar 10, 2021, at 2:14 AM, Bharath Rupireddy wrote:

While providing thoughts on [1], I observed that the error messages
that are emitted while adding foreign, temporary and unlogged tables
can be improved a bit from the existing [2] to [3]. For instance, the
existing message when foreign table is tried to add into the
publication "f1" is not a table" looks odd. Because it says that the
foreign table is not a table at all.

I wouldn't mix [regular|partitioned|temporary|unlogged] tables with foreign
tables. Although, they have a pg_class entry in common, foreign tables aren't
"real" tables (external storage); they even have different DDLs to handle it
(CREATE TABLE x CREATE FOREIGN TABLE).

postgres=# CREATE PUBLICATION testpub FOR TABLE f1;
ERROR: "f1" is not a table
DETAIL: Only tables can be added to publications.

I agree that "f1 is not a table" is a confusing message at first because
foreign table has "table" as description. Maybe if we apply the negation in
both messages it would be clear (using the same wording as system tables).

ERROR: "f1" is a foreign table
DETAIL: Foreign tables cannot be added to publications.

Thanks. Changed the error message and detail to the way we have it for
system tables presently. Attaching v2 patch for further review.

Here's the v3 patch rebased on the latest master.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v3-0001-Improve-error-message-while-adding-tables-to-publ.patchapplication/octet-stream; name=v3-0001-Improve-error-message-while-adding-tables-to-publ.patchDownload
From 518d011d1c06d78819f9adf53f4d2bc3941ae1a4 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Fri, 26 Mar 2021 09:21:45 +0530
Subject: [PATCH v3] Improve error message while adding tables to publication

Improve the error messages in check_publication_add_relation
from what we have to a bit more informative and consistent.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 +++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_publication.c          | 27 +++++++++++++++----
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 5 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 0649b6b81c..a0cc59161e 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9437,3 +9437,9 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 2b525ea44a..574b7d36df 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2928,3 +2928,8 @@ SELECT tableoid::regclass, * FROM batch_cp_upd_test;
 
 -- Clean up
 DROP TABLE batch_table, batch_cp_upd_test CASCADE;
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af89..c1ce4f31ab 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -68,11 +76,20 @@ check_publication_add_relation(Relation targetrel)
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
 	if (!RelationIsPermanent(targetrel))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+	{
+		if (RelationUsesLocalBuffers(targetrel))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is a temporary table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Temporary tables cannot be added to publications.")));
+		else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is an unlogged table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Unlogged tables cannot be added to publications.")));
+	}
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#7Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#6)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Fri, Mar 26, 2021 at 9:25 AM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Here's the v3 patch rebased on the latest master.

Here's the v4 patch reabsed on the latest master, please review it further.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v4-0001-Improve-error-message-while-adding-tables-to-publ.patchapplication/octet-stream; name=v4-0001-Improve-error-message-while-adding-tables-to-publ.patchDownload
From 1491523343fb0c38df43e727b6d4d6864998c530 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 5 Apr 2021 08:57:03 +0530
Subject: [PATCH v4] Improve error message while adding tables to publication

Improve the error messages in check_publication_add_relation
from what we have to a bit more informative and consistent.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 +++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_publication.c          | 27 +++++++++++++++----
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 5 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 59e4e27ffb..b14fd8618c 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9933,3 +9933,9 @@ DROP TABLE base_tbl4;
 DROP TABLE join_tbl;
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 107d1c0e03..561c9af23a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3138,3 +3138,8 @@ DROP TABLE join_tbl;
 
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af89..c1ce4f31ab 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -68,11 +76,20 @@ check_publication_add_relation(Relation targetrel)
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
 	if (!RelationIsPermanent(targetrel))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+	{
+		if (RelationUsesLocalBuffers(targetrel))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is a temporary table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Temporary tables cannot be added to publications.")));
+		else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is an unlogged table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Unlogged tables cannot be added to publications.")));
+	}
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#8Euler Taveira
euler@eulerto.com
In reply to: Bharath Rupireddy (#7)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Mon, Apr 5, 2021, at 12:27 AM, Bharath Rupireddy wrote:

On Fri, Mar 26, 2021 at 9:25 AM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com <mailto:bharath.rupireddyforpostgres%40gmail.com>> wrote:

Here's the v3 patch rebased on the latest master.

Here's the v4 patch reabsed on the latest master, please review it further.

/* UNLOGGED and TEMP relations cannot be part of publication. */
if (!RelationIsPermanent(targetrel))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("table \"%s\" cannot be replicated",
- RelationGetRelationName(targetrel)),
- errdetail("Temporary and unlogged relations cannot be replicated.")));
+ {
+ if (RelationUsesLocalBuffers(targetrel))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is a temporary table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Temporary tables cannot be added to publications.")));
+ else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is an unlogged table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Unlogged tables cannot be added to publications.")));
+ }

RelationIsPermanent(), RelationUsesLocalBuffers(), and
targetrel->rd_rel->relpersistence all refers to relpersistence. Hence, it is
not necessary to test !RelationIsPermanent().

I would slightly rewrite the commit message to something like:

Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.

--
Euler Taveira
EDB https://www.enterprisedb.com/

#9Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Euler Taveira (#8)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Mon, Apr 5, 2021 at 6:41 PM Euler Taveira <euler@eulerto.com> wrote:

Here's the v4 patch reabsed on the latest master, please review it further.

/* UNLOGGED and TEMP relations cannot be part of publication. */
if (!RelationIsPermanent(targetrel))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("table \"%s\" cannot be replicated",
- RelationGetRelationName(targetrel)),
- errdetail("Temporary and unlogged relations cannot be replicated.")));
+ {
+ if (RelationUsesLocalBuffers(targetrel))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is a temporary table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Temporary tables cannot be added to publications.")));
+ else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is an unlogged table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Unlogged tables cannot be added to publications.")));
+ }

RelationIsPermanent(), RelationUsesLocalBuffers(), and
targetrel->rd_rel->relpersistence all refers to relpersistence. Hence, it is
not necessary to test !RelationIsPermanent().

Done.

I would slightly rewrite the commit message to something like:

Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.

Thanks for the better wording.

Attaching v5 patch, please have a look.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v5-0001-Improve-publication-error-messages.patchapplication/x-patch; name=v5-0001-Improve-publication-error-messages.patchDownload
From c4c4efa96028fb9fe0b88e91c064a35484c6d8f0 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 5 Apr 2021 19:00:24 +0530
Subject: [PATCH v5] Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 +++++
 src/backend/catalog/pg_publication.c          | 20 ++++++++++++++++---
 src/test/regress/expected/publication.out     | 16 +++++++++++++++
 src/test/regress/sql/publication.sql          | 14 +++++++++++++
 5 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 59e4e27ffb..b14fd8618c 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9933,3 +9933,9 @@ DROP TABLE base_tbl4;
 DROP TABLE join_tbl;
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 107d1c0e03..561c9af23a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3138,3 +3138,8 @@ DROP TABLE join_tbl;
 
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af89..592d2d79e1 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -67,12 +75,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("System tables cannot be added to publications.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a temporary table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Temporary tables cannot be added to publications.")));
+	else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
+				 errmsg("\"%s\" is an unlogged table",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 errdetail("Unlogged tables cannot be added to publications.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#10vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#9)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Mon, Apr 5, 2021 at 7:19 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Mon, Apr 5, 2021 at 6:41 PM Euler Taveira <euler@eulerto.com> wrote:

Here's the v4 patch reabsed on the latest master, please review it further.

/* UNLOGGED and TEMP relations cannot be part of publication. */
if (!RelationIsPermanent(targetrel))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("table \"%s\" cannot be replicated",
- RelationGetRelationName(targetrel)),
- errdetail("Temporary and unlogged relations cannot be replicated.")));
+ {
+ if (RelationUsesLocalBuffers(targetrel))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is a temporary table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Temporary tables cannot be added to publications.")));
+ else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"%s\" is an unlogged table",
+ RelationGetRelationName(targetrel)),
+ errdetail("Unlogged tables cannot be added to publications.")));
+ }

RelationIsPermanent(), RelationUsesLocalBuffers(), and
targetrel->rd_rel->relpersistence all refers to relpersistence. Hence, it is
not necessary to test !RelationIsPermanent().

Done.

I would slightly rewrite the commit message to something like:

Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.

Thanks for the better wording.

Attaching v5 patch, please have a look.

We get the following error while adding an index:
create publication mypub for table idx_t1;
ERROR: "idx_t1" is an index

This error occurs internally from table_openrv function call, if we
could replace this with relation_openrv and then check the table kind,
we could throw a similar error message here too like the other changes
in the patch.

Regards,
Vignesh

#11Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#10)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, May 26, 2021 at 7:38 PM vignesh C <vignesh21@gmail.com> wrote:

Attaching v5 patch, please have a look.

We get the following error while adding an index:
create publication mypub for table idx_t1;
ERROR: "idx_t1" is an index

This error occurs internally from table_openrv function call, if we
could replace this with relation_openrv and then check the table kind,
we could throw a similar error message here too like the other changes
in the patch.

Do you say that we replace table_open in publication_add_relation with
relation_open and have the "\"%s\" is an index" or "\"%s\" is a
composite type" checks in check_publication_add_relation? If that is
so, I don't think it's a good idea to have the extra code in
check_publication_add_relation and I would like it to be the way it is
currently.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#12vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#11)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, May 26, 2021 at 7:55 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, May 26, 2021 at 7:38 PM vignesh C <vignesh21@gmail.com> wrote:

Attaching v5 patch, please have a look.

We get the following error while adding an index:
create publication mypub for table idx_t1;
ERROR: "idx_t1" is an index

This error occurs internally from table_openrv function call, if we
could replace this with relation_openrv and then check the table kind,
we could throw a similar error message here too like the other changes
in the patch.

Do you say that we replace table_open in publication_add_relation with
relation_open and have the "\"%s\" is an index" or "\"%s\" is a
composite type" checks in check_publication_add_relation? If that is
so, I don't think it's a good idea to have the extra code in
check_publication_add_relation and I would like it to be the way it is
currently.

Before calling check_publication_add_relation, we will call
OpenTableList to get the list of relations. In openTableList we don't
include the errordetail for the failure like you have fixed it in
check_publication_add_relation. When a user tries to add index objects
or composite types, the error will be thrown earlier itself. I didn't
mean to change check_publication_add_relation, I meant to change
table_openrv to relation_openrv in OpenTableList and include error
details in case of failure like the change attached. If you are ok,
please include the change in your patch.

Regards,
Vignesh

Attachments:

Improve_publication_error.patchtext/x-patch; charset=US-ASCII; name=Improve_publication_error.patchDownload
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 95c253c8e0..b6380d7491 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/htup_details.h"
+#include "access/relation.h"
 #include "access/table.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
@@ -523,7 +524,21 @@ OpenTableList(List *tables)
 		/* Allow query cancel in case this takes a long time */
 		CHECK_FOR_INTERRUPTS();
 
-		rel = table_openrv(rv, ShareUpdateExclusiveLock);
+		rel = relation_openrv(rv, ShareUpdateExclusiveLock);
+		if (rel->rd_rel->relkind == RELKIND_INDEX ||
+			rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+			ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is an index",
+						RelationGetRelationName(rel)),
+				 errdetail("Index objects not supported by publications.")));
+		else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(rel)),
+					errdetail("Composite type not supported by publications.")));
+
 		myrelid = RelationGetRelid(rel);
 
 		/*
#13Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#12)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Thu, May 27, 2021 at 9:02 PM vignesh C <vignesh21@gmail.com> wrote:

Do you say that we replace table_open in publication_add_relation with
relation_open and have the "\"%s\" is an index" or "\"%s\" is a
composite type" checks in check_publication_add_relation? If that is
so, I don't think it's a good idea to have the extra code in
check_publication_add_relation and I would like it to be the way it is
currently.

Before calling check_publication_add_relation, we will call
OpenTableList to get the list of relations. In openTableList we don't
include the errordetail for the failure like you have fixed it in
check_publication_add_relation. When a user tries to add index objects
or composite types, the error will be thrown earlier itself. I didn't
mean to change check_publication_add_relation, I meant to change
table_openrv to relation_openrv in OpenTableList and include error
details in case of failure like the change attached. If you are ok,
please include the change in your patch.

I don't think we need to change that. General intuition is that with
CREATE PUBLICATION ... FOR TABLE/FOR ALL TABLES one can specify only
tables and if at all an index/composite type is specified, the error
messages ""XXXX" is an index"/""XXXX" is a composite type" can imply
that they are not supported with CREATE PUBLICATION. There's no need
for a detailed error message saying "Index/Composite Type cannot be
added to publications.". Whereas foreign/unlogged/temporary/system
tables are actually tables, and we don't support them. So a detailed
error message here can state that explicitly.

I'm not taking the patch, attaching v5 again here to make cfbot happy
and for further review.

BTW, when we use relation_openrv, we have to use relation_close.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v5-0001-Improve-publication-error-messages.patchapplication/x-patch; name=v5-0001-Improve-publication-error-messages.patchDownload
From c4c4efa96028fb9fe0b88e91c064a35484c6d8f0 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 5 Apr 2021 19:00:24 +0530
Subject: [PATCH v5] Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 +++++
 src/backend/catalog/pg_publication.c          | 20 ++++++++++++++++---
 src/test/regress/expected/publication.out     | 16 +++++++++++++++
 src/test/regress/sql/publication.sql          | 14 +++++++++++++
 5 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 59e4e27ffb..b14fd8618c 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9933,3 +9933,9 @@ DROP TABLE base_tbl4;
 DROP TABLE join_tbl;
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 107d1c0e03..561c9af23a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3138,3 +3138,8 @@ DROP TABLE join_tbl;
 
 ALTER SERVER loopback OPTIONS (DROP async_capable);
 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af89..592d2d79e1 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -67,12 +75,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("System tables cannot be added to publications.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a temporary table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Temporary tables cannot be added to publications.")));
+	else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
+				 errmsg("\"%s\" is an unlogged table",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 errdetail("Unlogged tables cannot be added to publications.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#14Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#13)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Thu, May 27, 2021 at 10:28 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I'm not taking the patch, attaching v5 again here to make cfbot happy
and for further review.

Attaching v6 patch rebased onto the latest master.

Regards,
Bharath Rupireddy.

Attachments:

v6-0001-Improve-publication-error-messages.patchapplication/octet-stream; name=v6-0001-Improve-publication-error-messages.patchDownload
From 6bc0fc019a40956a5199df0dce1027582d432a30 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 7 Jul 2021 12:01:27 +0000
Subject: [PATCH v6] Improve publication error messages

Adding a foreign table into a publication prints an error saying "foo is not a
table". Although, a foreign table is not a regular table, this message could
possibly confuse users. Provide a suitable error message according to the
object class (table vs foreign table). While at it, separate unlogged/temp
table error message into 2 messages.
---
 .../postgres_fdw/expected/postgres_fdw.out    |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 +++++
 src/backend/catalog/pg_publication.c          | 20 ++++++++++++++++---
 src/test/regress/expected/publication.out     | 16 +++++++++++++++
 src/test/regress/sql/publication.sql          | 14 +++++++++++++
 5 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index b510322c4e..0b0bc33e90 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -10499,3 +10499,9 @@ ERROR:  invalid value for integer option "fetch_size": 100$%$#$#
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
 ERROR:  invalid value for integer option "batch_size": 100$%$#$#
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  "ft1" is a foreign table
+DETAIL:  Foreign tables cannot be added to publications.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 911f171d81..060fb9369c 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3355,3 +3355,8 @@ CREATE FOREIGN TABLE inv_fsz (c1 int )
 -- Invalid batch_size option
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 86e415af89..592d2d79e1 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -49,6 +49,14 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
+	/* FOREIGN table cannot be part of publication. */
+	if (RelationGetForm(targetrel)->relkind == RELKIND_FOREIGN_TABLE)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a foreign table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Foreign tables cannot be added to publications.")));
+
 	/* Must be a regular or partitioned table */
 	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
@@ -67,12 +75,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("System tables cannot be added to publications.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("\"%s\" is a temporary table",
+						RelationGetRelationName(targetrel)),
+				 errdetail("Temporary tables cannot be added to publications.")));
+	else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("table \"%s\" cannot be replicated",
+				 errmsg("\"%s\" is an unlogged table",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 errdetail("Unlogged tables cannot be added to publications.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 63d6ab7a4e..3dd31cfc84 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -160,6 +160,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
 DETAIL:  Only tables can be added to publications.
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+ERROR:  "testpub_temptbl" is a temporary table
+DETAIL:  Temporary tables cannot be added to publications.
+DROP TABLE testpub_temptbl;
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+ERROR:  "testpub_unloggedtbl" is an unlogged table
+DETAIL:  Unlogged tables cannot be added to publications.
+DROP TABLE testpub_unloggedtbl;
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+ERROR:  "pg_publication" is a system table
+DETAIL:  System tables cannot be added to publications.
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#15Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#14)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Jul 7, 2021 at 5:35 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Attaching v6 patch rebased onto the latest master.

I came across a recent commit 81d5995 and have used the same error
message for temporary and unlogged tables. Also added, test cases to
cover these error cases for foreign, temporary, unlogged and system
tables with CREATE PUBLICATION command. PSA v7.

commit 81d5995b4b78017ef9e5c6f151361d1fb949924c
Author: Peter Eisentraut <peter@eisentraut.org>
Date: Wed Jul 21 07:40:05 2021 +0200

More improvements of error messages about mismatching relkind

Regards,
Bharath Rupireddy.

Attachments:

v7-0001-Improve-publication-error-messages.patchapplication/octet-stream; name=v7-0001-Improve-publication-error-messages.patchDownload
From 4be3bdbdde9d54c2866141b3fc228ae592d8bdff Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 26 Jul 2021 07:25:47 +0000
Subject: [PATCH v7] Improve publication error messages

Instead of a combined error message for unlogged and temporary
tables, have a separate message similar to the error message the
commit 81d5995b4b has introduced.

Also, add test cases to cover the above error cases.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  5 +++++
 src/backend/catalog/pg_publication.c           | 10 ++++++++--
 src/test/regress/expected/publication.out      | 16 ++++++++++++++++
 src/test/regress/sql/publication.sql           | 14 ++++++++++++++
 5 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index ed25e7a743..f1c5ab592e 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -10519,3 +10519,9 @@ ERROR:  invalid value for integer option "fetch_size": 100$%$#$#
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
 ERROR:  invalid value for integer option "batch_size": 100$%$#$#
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
+ERROR:  cannot add relation "ft1" to publication
+DETAIL:  This operation is not supported for foreign tables.
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 02a6b15a13..56010f3f86 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3359,3 +3359,8 @@ CREATE FOREIGN TABLE inv_fsz (c1 int )
 -- Invalid batch_size option
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
+
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_foreign_tbl FOR TABLE ft1;  --ERROR
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 2a2fe03c13..2461fcd48a 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -67,12 +67,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("This operation is not supported for system tables.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 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("cannot add relation \"%s\" to publication",
+						RelationGetRelationName(targetrel)),
+				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 4a5ef0bc24..5944f62f54 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -162,6 +162,22 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index d844075368..dceb1c3d7f 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -95,6 +95,20 @@ DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#16Daniel Gustafsson
daniel@yesql.se
In reply to: Bharath Rupireddy (#15)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 26 Jul 2021, at 09:33, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

PSA v7.

This patch no longer applies on top of HEAD, please submit a rebased version.

--
Daniel Gustafsson https://vmware.com/

#17Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Daniel Gustafsson (#16)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Wed, Nov 3, 2021 at 6:21 PM Daniel Gustafsson <daniel@yesql.se> wrote:

On 26 Jul 2021, at 09:33, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

PSA v7.

This patch no longer applies on top of HEAD, please submit a rebased version.

Here's a rebased v8 patch. Please review it.

Regards,
Bharath Rupireddy.

Attachments:

v8-0001-Improve-publication-error-messages.patchapplication/octet-stream; name=v8-0001-Improve-publication-error-messages.patchDownload
From eaa84990f679e04f042feeec451f5e0687b25525 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 4 Nov 2021 04:22:21 +0000
Subject: [PATCH v8] Improve publication error messages

Instead of a combined error message for unlogged and temporary
tables, have a separate message similar to the error message the
commit 81d5995b4b has introduced.

Also, add test cases to cover the above error cases.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  5 +++++
 src/backend/catalog/pg_publication.c           | 10 ++++++++--
 src/test/regress/expected/publication.out      | 16 ++++++++++++++++
 src/test/regress/sql/publication.sql           | 14 ++++++++++++++
 5 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index fd141a0fa5..cdb8df6f27 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 43c30d492d..1d2e9d2e80 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..ec2b8f9e6e 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -70,12 +70,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("This operation is not supported for system tables.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 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("cannot add relation \"%s\" to publication",
+						RelationGetRelationName(targetrel)),
+				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 0f4fe4db8f..f141652516 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#18Daniel Gustafsson
daniel@yesql.se
In reply to: Bharath Rupireddy (#17)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 4 Nov 2021, at 05:24, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Nov 3, 2021 at 6:21 PM Daniel Gustafsson <daniel@yesql.se> wrote:

On 26 Jul 2021, at 09:33, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

PSA v7.

This patch no longer applies on top of HEAD, please submit a rebased version.

Here's a rebased v8 patch. Please review it.

This improves the user experience by increasing the granularity of error
reporting, and maps well with the precedent set in 81d5995b4. I'm marking this
Ready for Committer and will go ahead and apply this unless there are
objections.

--
Daniel Gustafsson https://vmware.com/

#19Euler Taveira
euler@eulerto.com
In reply to: Daniel Gustafsson (#18)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Fri, Nov 12, 2021, at 9:41 AM, Daniel Gustafsson wrote:

On 4 Nov 2021, at 05:24, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Nov 3, 2021 at 6:21 PM Daniel Gustafsson <daniel@yesql.se> wrote:

On 26 Jul 2021, at 09:33, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

PSA v7.

This patch no longer applies on top of HEAD, please submit a rebased version.

Here's a rebased v8 patch. Please review it.

This improves the user experience by increasing the granularity of error
reporting, and maps well with the precedent set in 81d5995b4. I'm marking this
Ready for Committer and will go ahead and apply this unless there are
objections.

Shouldn't we modify errdetail_relkind_not_supported() to include relpersistence
as a 2nd parameter and move those messages to it? I experiment this idea with
the attached patch. The idea is to provide a unique function that reports
accurate detail messages.

--
Euler Taveira
EDB https://www.enterprisedb.com/

Attachments:

v9-0001-Improve-publication-error-messages.patchtext/x-patch; name=v9-0001-Improve-publication-error-messages.patchDownload
From f068d4688a95c8e8c5a98d8d6f1847ddfafda43c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 4 Nov 2021 04:22:21 +0000
Subject: [PATCH v9] Improve publication error messages

Provide accurate messages for CREATE PUBLICATION commands. While at it,
modify errdetail_relkind_not_supported to distinguish tables based on
its persistence property. It provides accurate detail messages for
future work. It also includes tests to cover temporary, unlogged, system
and foreign tables.
---
 contrib/amcheck/verify_heapam.c                |  2 +-
 contrib/pageinspect/rawpage.c                  |  2 +-
 contrib/pg_surgery/heap_surgery.c              |  2 +-
 contrib/pg_visibility/pg_visibility.c          |  2 +-
 contrib/pgstattuple/pgstatapprox.c             |  2 +-
 contrib/pgstattuple/pgstatindex.c              |  2 +-
 contrib/pgstattuple/pgstattuple.c              |  2 +-
 contrib/postgres_fdw/expected/postgres_fdw.out |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  5 +++++
 src/backend/catalog/pg_class.c                 | 10 ++++++++--
 src/backend/catalog/pg_publication.c           | 13 +++----------
 src/backend/commands/comment.c                 |  2 +-
 src/backend/commands/indexcmds.c               |  2 +-
 src/backend/commands/lockcmds.c                |  5 +++--
 src/backend/commands/seclabel.c                |  2 +-
 src/backend/commands/sequence.c                |  2 +-
 src/backend/commands/statscmds.c               |  2 +-
 src/backend/commands/tablecmds.c               |  9 +++++----
 src/backend/commands/trigger.c                 |  6 +++---
 src/backend/executor/execReplication.c         |  2 +-
 src/backend/parser/parse_utilcmd.c             |  2 +-
 src/backend/rewrite/rewriteDefine.c            |  4 ++--
 src/include/catalog/pg_class.h                 |  2 +-
 src/test/regress/expected/publication.out      | 16 ++++++++++++++++
 src/test/regress/sql/publication.sql           | 14 ++++++++++++++
 25 files changed, 80 insertions(+), 38 deletions(-)

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index bae5340111..43854d1361 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -314,7 +314,7 @@ verify_heapam(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot check relation \"%s\"",
 						RelationGetRelationName(ctx.rel)),
-				 errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind, ctx.rel->rd_rel->relpersistence)));
 
 	/*
 	 * Sequences always use heap AM, but they don't show that in the catalogs.
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 4bfa346c24..2259068d73 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -160,7 +160,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get raw page from relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c
index 7edfe4f326..1c90c87c04 100644
--- a/contrib/pg_surgery/heap_surgery.c
+++ b/contrib/pg_surgery/heap_surgery.c
@@ -110,7 +110,7 @@ heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot operate on relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR,
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index b5362edcee..ca94f0be41 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -783,5 +783,5 @@ check_relation_relkind(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 }
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 3b836f370e..dd9a7657e1 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -291,7 +291,7 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 6c4b053dd0..4fa9eed844 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -450,7 +450,7 @@ pg_relpages_impl(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get page count of relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	/* note: this will work OK on non-local temp tables */
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index f408e6d84d..b47549ed70 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -295,7 +295,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot get tuple-level statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 	}
 
 	return 0;					/* should not happen */
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 3cee0a8c12..786781db4b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index e40112e41d..666d21962a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_class.c b/src/backend/catalog/pg_class.c
index 304c0af808..a34641fed5 100644
--- a/src/backend/catalog/pg_class.c
+++ b/src/backend/catalog/pg_class.c
@@ -21,12 +21,18 @@
  * operation.
  */
 int
-errdetail_relkind_not_supported(char relkind)
+errdetail_relkind_not_supported(char relkind, char relpersistence)
 {
 	switch (relkind)
 	{
 		case RELKIND_RELATION:
-			return errdetail("This operation is not supported for tables.");
+			if (relpersistence == RELPERSISTENCE_PERMANENT)
+				return errdetail("This operation is not supported for tables.");
+			else if (relpersistence == RELPERSISTENCE_UNLOGGED)
+				return errdetail("This operation is not supported for unlogged tables.");
+			else if (relpersistence == RELPERSISTENCE_TEMP)
+				return errdetail("This operation is not supported for temporary tables.");
+			/* fallthrough */
 		case RELKIND_INDEX:
 			return errdetail("This operation is not supported for indexes.");
 		case RELKIND_SEQUENCE:
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..b5f352cb60 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -53,13 +53,14 @@ static void
 check_publication_add_relation(Relation targetrel)
 {
 	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
+	if (!(RelationGetForm(targetrel)->relkind == RELKIND_RELATION &&
+				RelationIsPermanent(targetrel)) &&
 		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
+				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind, RelationGetForm(targetrel)->relpersistence)));
 
 	/* Can't be system table */
 	if (IsCatalogRelation(targetrel))
@@ -68,14 +69,6 @@ check_publication_add_relation(Relation targetrel)
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
 				 errdetail("This operation is not supported for system tables.")));
-
-	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot add relation \"%s\" to publication",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
 }
 
 /*
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index d4943e374a..9cb28da86f 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -100,7 +100,7 @@ CommentObject(CommentStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set comment on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_relkind_not_supported(relation->rd_rel->relkind, relation->rd_rel->relpersistence)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index c14ca27c5e..01964a626d 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -655,7 +655,7 @@ DefineIndex(Oid relationId,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot create index on relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 			break;
 	}
 
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 62465bacd8..4709a38155 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -84,6 +84,8 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 		return;					/* woops, concurrently dropped; no permissions
 								 * check */
 
+	relpersistence = get_rel_persistence(relid);
+
 	/* Currently, we only allow plain tables or views to be locked */
 	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
 		relkind != RELKIND_VIEW)
@@ -91,13 +93,12 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot lock relation \"%s\"",
 						rv->relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported(relkind, relpersistence)));
 
 	/*
 	 * Make note if a temporary relation has been accessed in this
 	 * transaction.
 	 */
-	relpersistence = get_rel_persistence(relid);
 	if (relpersistence == RELPERSISTENCE_TEMP)
 		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 53c18628a7..ded4a9050b 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -191,7 +191,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set security label on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_relkind_not_supported(relation->rd_rel->relkind, relation->rd_rel->relpersistence)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 72bfdc07a4..245ad3a9f4 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1655,7 +1655,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("sequence cannot be owned by relation \"%s\"",
 							RelationGetRelationName(tablerel)),
-					 errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(tablerel->rd_rel->relkind, tablerel->rd_rel->relpersistence)));
 
 		/* We insist on same owner and schema */
 		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 8f1550ec80..3e88ec0075 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -138,7 +138,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot define statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 		/* You must own the relation to create stats on it */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 857cc5ce6e..cb5a4be806 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3327,6 +3327,7 @@ static void
 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 {
 	char		relkind = classform->relkind;
+	char		relpersistence = classform->relpersistence;
 
 	if (classform->reloftype && !recursing)
 		ereport(ERROR,
@@ -3352,7 +3353,7 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot rename columns of relation \"%s\"",
 						NameStr(classform->relname)),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported(relkind, relpersistence)));
 
 	/*
 	 * permissions checking.  only the owner of a class can change its schema.
@@ -6192,7 +6193,7 @@ ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
 			/* translator: %s is a group of some SQL keywords */
 					 errmsg("ALTER action %s cannot be performed on relation \"%s\"",
 							action_str, RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 		else
 			/* internal error? */
 			elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
@@ -13357,7 +13358,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot change owner of relation \"%s\"",
 							NameStr(tuple_class->relname)),
-					 errdetail_relkind_not_supported(tuple_class->relkind)));
+					 errdetail_relkind_not_supported(tuple_class->relkind, tuple_class->relpersistence)));
 	}
 
 	/*
@@ -13796,7 +13797,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot set options for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 			break;
 	}
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index d8890d2c74..6a1abdd2dc 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -312,7 +312,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1289,7 +1289,7 @@ RemoveTriggerById(Oid trigOid)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(rel->rd_rel->relkind, rel->rd_rel->relpersistence)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1396,7 +1396,7 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_relkind_not_supported(form->relkind, form->relpersistence)));
 
 	/* you must own the table to rename one of its triggers */
 	if (!pg_class_ownercheck(relid, GetUserId()))
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 574d7d27fd..9cf713f540 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -613,5 +613,5 @@ CheckSubscriptionRelkind(char relkind, const char *nspname,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
 						nspname, relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported(relkind, RELPERSISTENCE_PERMANENT)));
 }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 313d7b6ff0..0ab96f4c1e 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -976,7 +976,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is invalid in LIKE clause",
 						RelationGetRelationName(relation)),
-				 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(relation->rd_rel->relkind, relation->rd_rel->relpersistence)));
 
 	cancel_parser_errposition_callback(&pcbstate);
 
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6589345ac4..8bc4869cc3 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -270,7 +270,7 @@ DefineQueryRewrite(const char *rulename,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules",
 						RelationGetRelationName(event_relation)),
-				 errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(event_relation->rd_rel->relkind, event_relation->rd_rel->relpersistence)));
 
 	if (!allowSystemTableMods && IsSystemRelation(event_relation))
 		ereport(ERROR,
@@ -937,7 +937,7 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules", rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_relkind_not_supported(form->relkind, form->relpersistence)));
 
 	if (!allowSystemTableMods && IsSystemClass(relid, form))
 		ereport(ERROR,
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index fef9945ed8..c8aac3a692 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -198,7 +198,7 @@ DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeInd
 	 (relkind) == RELKIND_TOASTVALUE || \
 	 (relkind) == RELKIND_MATVIEW)
 
-extern int errdetail_relkind_not_supported(char relkind);
+extern int errdetail_relkind_not_supported(char relkind, char relpersistence);
 
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 2ff21a7543..1feb558968 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.20.1

#20Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Euler Taveira (#19)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Sat, Nov 13, 2021 at 12:06 AM Euler Taveira <euler@eulerto.com> wrote:

Here's a rebased v8 patch. Please review it.

This improves the user experience by increasing the granularity of error
reporting, and maps well with the precedent set in 81d5995b4. I'm marking this
Ready for Committer and will go ahead and apply this unless there are
objections.

Shouldn't we modify errdetail_relkind_not_supported() to include relpersistence
as a 2nd parameter and move those messages to it? I experiment this idea with
the attached patch. The idea is to provide a unique function that reports
accurate detail messages.

Thanks. It is a good idea to use errdetail_relkind_not_supported. I
slightly modified the API to "int errdetail_relkind_not_supported(Oid
relid, Form_pg_class rd_rel);" to simplify things and increase the
usability of the function further. For instance, it can report the
specific error for the catalog tables as well. And, also added "int
errdetail_relkind_not_supported _v2(Oid relid, char relkind, char
relpersistence);" so that the callers not having Form_pg_class (there
are 3 callers exist) can pass the parameters directly.

PSA v10.

Regards,
Bharath Rupireddy.

Attachments:

v10-0001-Improve-publication-error-messages.patchapplication/x-patch; name=v10-0001-Improve-publication-error-messages.patchDownload
From 50e0570fe2c83dfddc85f3e7df0ffebb12c5ef3e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sat, 13 Nov 2021 02:33:44 +0000
Subject: [PATCH v10] Improve publication error messages

Provide accurate messages for CREATE PUBLICATION commands. Also add
tests to cover temporary, unlogged, system and foreign tables.

While at it, modify errdetail_relkind_not_supported API to distinguish
tables based on persistence property and report for system tables.
Also, introduce errdetail_relkind_not_supported_v2 so that the callers
not having Form_pg_class object can send relid, relkind, relpersistence
as direct parameters. This way, the API is more flexbile and easier
to use. It also provides accurate detail messages for future work.
---
 contrib/amcheck/verify_heapam.c               |  2 +-
 contrib/pageinspect/rawpage.c                 |  2 +-
 contrib/pg_surgery/heap_surgery.c             |  2 +-
 contrib/pg_visibility/pg_visibility.c         |  2 +-
 contrib/pgstattuple/pgstatapprox.c            |  2 +-
 contrib/pgstattuple/pgstatindex.c             |  2 +-
 contrib/pgstattuple/pgstattuple.c             |  2 +-
 .../postgres_fdw/expected/postgres_fdw.out    |  6 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_class.c                | 24 ++++++++++++++--
 src/backend/catalog/pg_publication.c          | 28 ++++++-------------
 src/backend/commands/comment.c                |  2 +-
 src/backend/commands/indexcmds.c              |  2 +-
 src/backend/commands/lockcmds.c               |  5 ++--
 src/backend/commands/seclabel.c               |  2 +-
 src/backend/commands/sequence.c               |  2 +-
 src/backend/commands/statscmds.c              |  2 +-
 src/backend/commands/subscriptioncmds.c       |  4 +--
 src/backend/commands/tablecmds.c              |  9 +++---
 src/backend/commands/trigger.c                |  6 ++--
 src/backend/executor/execReplication.c        |  5 ++--
 src/backend/parser/parse_utilcmd.c            |  2 +-
 src/backend/replication/logical/relation.c    |  2 +-
 src/backend/rewrite/rewriteDefine.c           |  4 +--
 src/include/catalog/pg_class.h                |  4 ++-
 src/include/executor/executor.h               |  2 +-
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 28 files changed, 107 insertions(+), 53 deletions(-)

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index bae5340111..f6b16c8fb0 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -314,7 +314,7 @@ verify_heapam(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot check relation \"%s\"",
 						RelationGetRelationName(ctx.rel)),
-				 errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(ctx.rel), ctx.rel->rd_rel)));
 
 	/*
 	 * Sequences always use heap AM, but they don't show that in the catalogs.
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 4bfa346c24..3173fb83d3 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -160,7 +160,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get raw page from relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c
index 7edfe4f326..043efda2f6 100644
--- a/contrib/pg_surgery/heap_surgery.c
+++ b/contrib/pg_surgery/heap_surgery.c
@@ -110,7 +110,7 @@ heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot operate on relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR,
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index b5362edcee..b180174a1c 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -783,5 +783,5 @@ check_relation_relkind(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 }
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 3b836f370e..d824d90351 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -291,7 +291,7 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 6c4b053dd0..45af621e95 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -450,7 +450,7 @@ pg_relpages_impl(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get page count of relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	/* note: this will work OK on non-local temp tables */
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index f408e6d84d..bacaaa3b9e 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -295,7 +295,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot get tuple-level statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 	}
 
 	return 0;					/* should not happen */
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 3cee0a8c12..786781db4b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index e40112e41d..666d21962a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_class.c b/src/backend/catalog/pg_class.c
index 304c0af808..e713c6bdb2 100644
--- a/src/backend/catalog/pg_class.c
+++ b/src/backend/catalog/pg_class.c
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "catalog/catalog.h"
 #include "catalog/pg_class.h"
 
 /*
@@ -21,12 +22,31 @@
  * operation.
  */
 int
-errdetail_relkind_not_supported(char relkind)
+errdetail_relkind_not_supported(Oid relid, Form_pg_class rd_rel)
+{
+	return errdetail_relkind_not_supported_v2(relid, rd_rel->relkind,
+											  rd_rel->relpersistence);
+}
+
+/*
+ * Same as errdetail_relkind_not_supported, but the input parameters are passed
+ * explicitly.
+ */
+int
+errdetail_relkind_not_supported_v2(Oid relid, char relkind, char relpersistence)
 {
 	switch (relkind)
 	{
 		case RELKIND_RELATION:
-			return errdetail("This operation is not supported for tables.");
+			if (OidIsValid(relid) && IsCatalogRelationOid(relid))
+				return errdetail("This operation is not supported for system tables.");
+			else if (relpersistence == RELPERSISTENCE_PERMANENT)
+				return errdetail("This operation is not supported for tables.");
+			else if (relpersistence == RELPERSISTENCE_UNLOGGED)
+				return errdetail("This operation is not supported for unlogged tables.");
+			else if (relpersistence == RELPERSISTENCE_TEMP)
+				return errdetail("This operation is not supported for temporary tables.");
+			break;
 		case RELKIND_INDEX:
 			return errdetail("This operation is not supported for indexes.");
 		case RELKIND_SEQUENCE:
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..82c405f245 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -52,30 +52,18 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
-	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
-		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot add relation \"%s\" to publication",
-						RelationGetRelationName(targetrel)),
-				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
-
-	/* Can't be system table */
-	if (IsCatalogRelation(targetrel))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot add relation \"%s\" to publication",
-						RelationGetRelationName(targetrel)),
-				 errdetail("This operation is not supported for system tables.")));
-
-	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	/*
+	 * Must be a regular or partitioned table. System table, UNLOGGED and TEMP
+	 * table cannot be part of publication.
+	 */
+	if ((RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
+		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE) ||
+		(IsCatalogRelation(targetrel) || !RelationIsPermanent(targetrel)))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 errdetail_relkind_not_supported(RelationGetRelid(targetrel), RelationGetForm(targetrel))));
 }
 
 /*
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index d4943e374a..a93c1a304b 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -100,7 +100,7 @@ CommentObject(CommentStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set comment on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_relkind_not_supported(RelationGetRelid(relation), relation->rd_rel)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index c14ca27c5e..0e518f2b71 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -655,7 +655,7 @@ DefineIndex(Oid relationId,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot create index on relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 			break;
 	}
 
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 62465bacd8..38d97f10a6 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -84,6 +84,8 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 		return;					/* woops, concurrently dropped; no permissions
 								 * check */
 
+	relpersistence = get_rel_persistence(relid);
+
 	/* Currently, we only allow plain tables or views to be locked */
 	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
 		relkind != RELKIND_VIEW)
@@ -91,13 +93,12 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot lock relation \"%s\"",
 						rv->relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported_v2(relid, relkind, relpersistence)));
 
 	/*
 	 * Make note if a temporary relation has been accessed in this
 	 * transaction.
 	 */
-	relpersistence = get_rel_persistence(relid);
 	if (relpersistence == RELPERSISTENCE_TEMP)
 		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 53c18628a7..9437b0ca50 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -191,7 +191,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set security label on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_relkind_not_supported(RelationGetRelid(relation), relation->rd_rel)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 72bfdc07a4..dfac3678a8 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1655,7 +1655,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("sequence cannot be owned by relation \"%s\"",
 							RelationGetRelationName(tablerel)),
-					 errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(tablerel), tablerel->rd_rel)));
 
 		/* We insist on same owner and schema */
 		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 8f1550ec80..2ad1f8d057 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -138,7 +138,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot define statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 		/* You must own the relation to create stats on it */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index c47ba26369..bbd250e012 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -533,7 +533,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 				relid = RangeVarGetRelid(rv, AccessShareLock, false);
 
 				/* Check for supported relkind. */
-				CheckSubscriptionRelkind(get_rel_relkind(relid),
+				CheckSubscriptionRelkind(relid, get_rel_relkind(relid),
 										 rv->schemaname, rv->relname);
 
 				AddSubscriptionRelState(subid, relid, table_state,
@@ -683,7 +683,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
 			relid = RangeVarGetRelid(rv, AccessShareLock, false);
 
 			/* Check for supported relkind. */
-			CheckSubscriptionRelkind(get_rel_relkind(relid),
+			CheckSubscriptionRelkind(relid, get_rel_relkind(relid),
 									 rv->schemaname, rv->relname);
 
 			pubrel_local_oids[off++] = relid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 857cc5ce6e..1763a24680 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3327,6 +3327,7 @@ static void
 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 {
 	char		relkind = classform->relkind;
+	char		relpersistence = classform->relpersistence;
 
 	if (classform->reloftype && !recursing)
 		ereport(ERROR,
@@ -3352,7 +3353,7 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot rename columns of relation \"%s\"",
 						NameStr(classform->relname)),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported_v2(myrelid, relkind, relpersistence)));
 
 	/*
 	 * permissions checking.  only the owner of a class can change its schema.
@@ -6192,7 +6193,7 @@ ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
 			/* translator: %s is a group of some SQL keywords */
 					 errmsg("ALTER action %s cannot be performed on relation \"%s\"",
 							action_str, RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 		else
 			/* internal error? */
 			elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
@@ -13357,7 +13358,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot change owner of relation \"%s\"",
 							NameStr(tuple_class->relname)),
-					 errdetail_relkind_not_supported(tuple_class->relkind)));
+					 errdetail_relkind_not_supported(relationOid, tuple_class)));
 	}
 
 	/*
@@ -13796,7 +13797,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot set options for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 			break;
 	}
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index d8890d2c74..9aa8aa2e13 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -312,7 +312,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1289,7 +1289,7 @@ RemoveTriggerById(Oid trigOid)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(rel), rel->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1396,7 +1396,7 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_relkind_not_supported(relid, form)));
 
 	/* you must own the table to rename one of its triggers */
 	if (!pg_class_ownercheck(relid, GetUserId()))
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 574d7d27fd..f8bcb98e44 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -605,7 +605,8 @@ CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
  * The nspname and relname are only needed for error reporting.
  */
 void
-CheckSubscriptionRelkind(char relkind, const char *nspname,
+CheckSubscriptionRelkind(Oid relid, char relkind,
+						 const char *nspname,
 						 const char *relname)
 {
 	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
@@ -613,5 +614,5 @@ CheckSubscriptionRelkind(char relkind, const char *nspname,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
 						nspname, relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_relkind_not_supported_v2(relid, relkind, RELPERSISTENCE_PERMANENT)));
 }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 313d7b6ff0..8b9ef9e1f8 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -976,7 +976,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is invalid in LIKE clause",
 						RelationGetRelationName(relation)),
-				 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(relation), relation->rd_rel)));
 
 	cancel_parser_errposition_callback(&pcbstate);
 
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index c37e2a7e29..ab174a48da 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -326,7 +326,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 		entry->localreloid = relid;
 
 		/* Check for supported relkind. */
-		CheckSubscriptionRelkind(entry->localrel->rd_rel->relkind,
+		CheckSubscriptionRelkind(relid, entry->localrel->rd_rel->relkind,
 								 remoterel->nspname, remoterel->relname);
 
 		/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6589345ac4..0ffb77a0cb 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -270,7 +270,7 @@ DefineQueryRewrite(const char *rulename,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules",
 						RelationGetRelationName(event_relation)),
-				 errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
+				 errdetail_relkind_not_supported(RelationGetRelid(event_relation), event_relation->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(event_relation))
 		ereport(ERROR,
@@ -937,7 +937,7 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules", rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_relkind_not_supported(relid, form)));
 
 	if (!allowSystemTableMods && IsSystemClass(relid, form))
 		ereport(ERROR,
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index fef9945ed8..aa95a2004a 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -156,6 +156,8 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_class_oid_index, 2662, ClassOidIndexId, on pg_class
 DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, ClassNameNspIndexId, on pg_class using btree(relname name_ops, relnamespace oid_ops));
 DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeIndexId, on pg_class using btree(reltablespace oid_ops, relfilenode oid_ops));
 
+extern int errdetail_relkind_not_supported(Oid relid, Form_pg_class rd_rel);
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 #define		  RELKIND_RELATION		  'r'	/* ordinary table */
@@ -198,7 +200,7 @@ DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeInd
 	 (relkind) == RELKIND_TOASTVALUE || \
 	 (relkind) == RELKIND_MATVIEW)
 
-extern int errdetail_relkind_not_supported(char relkind);
+extern int errdetail_relkind_not_supported_v2(Oid relid, char relkind, char relpersistence);
 
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index cd57a704ad..45582f896d 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -644,7 +644,7 @@ extern void ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
 									 TupleTableSlot *searchslot);
 extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
 
-extern void CheckSubscriptionRelkind(char relkind, const char *nspname,
+extern void CheckSubscriptionRelkind(Oid relid, char relkind, const char *nspname,
 									 const char *relname);
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 2ff21a7543..1feb558968 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#21Euler Taveira
euler@eulerto.com
In reply to: Bharath Rupireddy (#20)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Sat, Nov 13, 2021, at 12:00 AM, Bharath Rupireddy wrote:

On Sat, Nov 13, 2021 at 12:06 AM Euler Taveira <euler@eulerto.com> wrote:

Here's a rebased v8 patch. Please review it.

This improves the user experience by increasing the granularity of error
reporting, and maps well with the precedent set in 81d5995b4. I'm marking this
Ready for Committer and will go ahead and apply this unless there are
objections.

Shouldn't we modify errdetail_relkind_not_supported() to include relpersistence
as a 2nd parameter and move those messages to it? I experiment this idea with
the attached patch. The idea is to provide a unique function that reports
accurate detail messages.

Thanks. It is a good idea to use errdetail_relkind_not_supported. I
slightly modified the API to "int errdetail_relkind_not_supported(Oid
relid, Form_pg_class rd_rel);" to simplify things and increase the
usability of the function further. For instance, it can report the
specific error for the catalog tables as well. And, also added "int
errdetail_relkind_not_supported _v2(Oid relid, char relkind, char
relpersistence);" so that the callers not having Form_pg_class (there
are 3 callers exist) can pass the parameters directly.

Do we really need 2 functions? I don't think so. Besides that, relid is
redundant since this information is available in the Form_pg_class struct.

int errdetail_relkind_not_supported(Oid relid, Form_pg_class rd_rel);

My suggestion is to keep only the 3 parameter function:

int errdetail_relkind_not_supported(Oid relid, char relkind, char relpersistence);

Multiple functions that is just a wrapper for a central one is a good idea for
backward compatibility. That's not the case here.

--
Euler Taveira
EDB https://www.enterprisedb.com/

#22Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Euler Taveira (#21)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Sat, Nov 13, 2021 at 7:16 PM Euler Taveira <euler@eulerto.com> wrote:

Thanks. It is a good idea to use errdetail_relkind_not_supported. I
slightly modified the API to "int errdetail_relkind_not_supported(Oid
relid, Form_pg_class rd_rel);" to simplify things and increase the
usability of the function further. For instance, it can report the
specific error for the catalog tables as well. And, also added "int
errdetail_relkind_not_supported _v2(Oid relid, char relkind, char
relpersistence);" so that the callers not having Form_pg_class (there
are 3 callers exist) can pass the parameters directly.

Do we really need 2 functions? I don't think so. Besides that, relid is
redundant since this information is available in the Form_pg_class struct.

Yeah. The relid is available in Form_pg_class.

Firstly, I didn't quite like the function
errdetail_relkind_not_supported name to be too long here and adding to
it the 2 or 3 parameters, in many places we are crossing 80 char
limit. Above these, a function with one parameter is always better
than function with 3 parameters.

Having two functions isn't a big deal at all, I think we have many
functions like that in the core (although I'm not gonna spend time
finding all those functions, I'm sure there will be such functions).

I would still go with with 2 functions:

int errdetail_relkind_not_supported(Form_pg_class rd_rel);
int errdetail_relkind_not_supported_v2(Oid relid, char relkind, char
relpersistence);

int errdetail_relkind_not_supported(Oid relid, Form_pg_class rd_rel);

My suggestion is to keep only the 3 parameter function:

int errdetail_relkind_not_supported(Oid relid, char relkind, char relpersistence);

Multiple functions that is just a wrapper for a central one is a good idea for
backward compatibility. That's not the case here.

Since we are modifying it on the master, I think it is okay to have 2
functions given the code simplification advantages we get with
errdetail_relkind_not_supported(Form_pg_class rd_rel).

I would even think further to rename "errdetail_relkind_not_supported"
and have the following, because we don't have to be always descriptive
in the function names. The errdetail would tell the function is going
to give some error detail.

int errdetail_relkind(Form_pg_class rd_rel);
int errdetail_relkind_v2(Oid relid, char relkind, char relpersistence);

or

int errdetail_rel(Form_pg_class rd_rel);
int errdetail_rel_v2(Oid relid, char relkind, char relpersistence);

I prefer the above among the three function names.

Thoughts?

Regards,
Bharath Rupireddy.

#23Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#22)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Sat, Nov 13, 2021 at 7:57 PM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

On Sat, Nov 13, 2021 at 7:16 PM Euler Taveira <euler@eulerto.com> wrote:

Thanks. It is a good idea to use errdetail_relkind_not_supported. I
slightly modified the API to "int errdetail_relkind_not_supported(Oid
relid, Form_pg_class rd_rel);" to simplify things and increase the
usability of the function further. For instance, it can report the
specific error for the catalog tables as well. And, also added "int
errdetail_relkind_not_supported _v2(Oid relid, char relkind, char
relpersistence);" so that the callers not having Form_pg_class (there
are 3 callers exist) can pass the parameters directly.

Do we really need 2 functions? I don't think so. Besides that, relid is
redundant since this information is available in the Form_pg_class

struct.

Yeah. The relid is available in Form_pg_class.

Firstly, I didn't quite like the function
errdetail_relkind_not_supported name to be too long here and adding to
it the 2 or 3 parameters, in many places we are crossing 80 char
limit. Above these, a function with one parameter is always better
than function with 3 parameters.

Having two functions isn't a big deal at all, I think we have many
functions like that in the core (although I'm not gonna spend time
finding all those functions, I'm sure there will be such functions).

I would still go with with 2 functions:

int errdetail_relkind_not_supported(Form_pg_class rd_rel);
int errdetail_relkind_not_supported_v2(Oid relid, char relkind, char
relpersistence);

int errdetail_relkind_not_supported(Oid relid, Form_pg_class rd_rel);

My suggestion is to keep only the 3 parameter function:

int errdetail_relkind_not_supported(Oid relid, char relkind, char

relpersistence);

Multiple functions that is just a wrapper for a central one is a good

idea for

backward compatibility. That's not the case here.

Since we are modifying it on the master, I think it is okay to have 2
functions given the code simplification advantages we get with
errdetail_relkind_not_supported(Form_pg_class rd_rel).

I would even think further to rename "errdetail_relkind_not_supported"
and have the following, because we don't have to be always descriptive
in the function names. The errdetail would tell the function is going
to give some error detail.

int errdetail_relkind(Form_pg_class rd_rel);
int errdetail_relkind_v2(Oid relid, char relkind, char relpersistence);

or

int errdetail_rel(Form_pg_class rd_rel);
int errdetail_rel_v2(Oid relid, char relkind, char relpersistence);

I prefer the above among the three function names.

Thoughts?

PSA v11 patch with 2 APIs with much simpler parameters and small function
names:

int errdetail_rel(Form_pg_class rd_rel);
int errdetail_rel_v2(Oid relid, char relkind, char relpersistence);

Please review it.

Regards,
Bharath Rupireddy.

Attachments:

v11-0001-Improve-publication-error-messages.patchapplication/x-patch; name=v11-0001-Improve-publication-error-messages.patchDownload
From 16876bdee3dccf6ec5c2faeb93dd3c51b62dbc2e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sun, 14 Nov 2021 03:57:11 +0000
Subject: [PATCH v11] Improve publication error messages

Provide accurate messages for CREATE PUBLICATION commands. Also add
tests to cover temporary, unlogged, system and foreign tables.

While at it, modify errdetail_relkind_not_supported API to distinguish
tables based on persistence property and report for system tables.
As the function name is too long rename it to errdetail_rel.
Also, introduce errdetail_rel so that the callers not having
Form_pg_class object can send relid, relkind, relpersistence as direct
parameters. This way, the API is more flexbile and easier to use.
It also provides accurate detail messages for future work.
---
 contrib/amcheck/verify_heapam.c               |  2 +-
 contrib/pageinspect/rawpage.c                 |  2 +-
 contrib/pg_surgery/heap_surgery.c             |  2 +-
 contrib/pg_visibility/pg_visibility.c         |  2 +-
 contrib/pgstattuple/pgstatapprox.c            |  2 +-
 contrib/pgstattuple/pgstatindex.c             |  2 +-
 contrib/pgstattuple/pgstattuple.c             |  2 +-
 .../postgres_fdw/expected/postgres_fdw.out    |  6 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  5 ++++
 src/backend/catalog/pg_class.c                | 25 +++++++++++++++--
 src/backend/catalog/pg_publication.c          | 28 ++++++-------------
 src/backend/commands/comment.c                |  2 +-
 src/backend/commands/indexcmds.c              |  2 +-
 src/backend/commands/lockcmds.c               |  5 ++--
 src/backend/commands/seclabel.c               |  2 +-
 src/backend/commands/sequence.c               |  2 +-
 src/backend/commands/statscmds.c              |  2 +-
 src/backend/commands/subscriptioncmds.c       |  4 +--
 src/backend/commands/tablecmds.c              |  9 +++---
 src/backend/commands/trigger.c                |  6 ++--
 src/backend/executor/execReplication.c        |  5 ++--
 src/backend/parser/parse_utilcmd.c            |  2 +-
 src/backend/replication/logical/relation.c    |  2 +-
 src/backend/rewrite/rewriteDefine.c           |  4 +--
 src/include/catalog/pg_class.h                |  5 ++--
 src/include/executor/executor.h               |  2 +-
 src/test/regress/expected/publication.out     | 16 +++++++++++
 src/test/regress/sql/publication.sql          | 14 ++++++++++
 28 files changed, 108 insertions(+), 54 deletions(-)

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index bae5340111..a9c84913b0 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -314,7 +314,7 @@ verify_heapam(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot check relation \"%s\"",
 						RelationGetRelationName(ctx.rel)),
-				 errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
+				 errdetail_rel(ctx.rel->rd_rel)));
 
 	/*
 	 * Sequences always use heap AM, but they don't show that in the catalogs.
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 4bfa346c24..bc6aa5799a 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -160,7 +160,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get raw page from relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c
index 7edfe4f326..d38884b3fa 100644
--- a/contrib/pg_surgery/heap_surgery.c
+++ b/contrib/pg_surgery/heap_surgery.c
@@ -110,7 +110,7 @@ heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot operate on relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR,
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index b5362edcee..6d89dba47f 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -783,5 +783,5 @@ check_relation_relkind(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 }
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 3b836f370e..eef70df775 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -291,7 +291,7 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("relation \"%s\" is of wrong relation kind",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 6c4b053dd0..6779850142 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -450,7 +450,7 @@ pg_relpages_impl(Relation rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot get page count of relation \"%s\"",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	/* note: this will work OK on non-local temp tables */
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index f408e6d84d..e1890ca4a4 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -295,7 +295,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot get tuple-level statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_rel(rel->rd_rel)));
 	}
 
 	return 0;					/* should not happen */
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 3cee0a8c12..786781db4b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index e40112e41d..666d21962a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_class.c b/src/backend/catalog/pg_class.c
index 304c0af808..b4931b636d 100644
--- a/src/backend/catalog/pg_class.c
+++ b/src/backend/catalog/pg_class.c
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "catalog/catalog.h"
 #include "catalog/pg_class.h"
 
 /*
@@ -21,12 +22,30 @@
  * operation.
  */
 int
-errdetail_relkind_not_supported(char relkind)
+errdetail_rel(Form_pg_class rd_rel)
+{
+	return errdetail_rel_v2(rd_rel->oid, rd_rel->relkind,
+							rd_rel->relpersistence);
+}
+
+/*
+ * Same as errdetail_rel, but the input parameters are passed explicitly.
+ */
+int
+errdetail_rel_v2(Oid relid, char relkind, char relpersistence)
 {
 	switch (relkind)
 	{
 		case RELKIND_RELATION:
-			return errdetail("This operation is not supported for tables.");
+			if (OidIsValid(relid) && IsCatalogRelationOid(relid))
+				return errdetail("This operation is not supported for system tables.");
+			else if (relpersistence == RELPERSISTENCE_PERMANENT)
+				return errdetail("This operation is not supported for tables.");
+			else if (relpersistence == RELPERSISTENCE_UNLOGGED)
+				return errdetail("This operation is not supported for unlogged tables.");
+			else if (relpersistence == RELPERSISTENCE_TEMP)
+				return errdetail("This operation is not supported for temporary tables.");
+			break;
 		case RELKIND_INDEX:
 			return errdetail("This operation is not supported for indexes.");
 		case RELKIND_SEQUENCE:
@@ -49,4 +68,6 @@ errdetail_relkind_not_supported(char relkind)
 			elog(ERROR, "unrecognized relkind: '%c'", relkind);
 			return 0;
 	}
+
+	return 0;
 }
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..d2315e212b 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -52,30 +52,18 @@
 static void
 check_publication_add_relation(Relation targetrel)
 {
-	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
-		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot add relation \"%s\" to publication",
-						RelationGetRelationName(targetrel)),
-				 errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
-
-	/* Can't be system table */
-	if (IsCatalogRelation(targetrel))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot add relation \"%s\" to publication",
-						RelationGetRelationName(targetrel)),
-				 errdetail("This operation is not supported for system tables.")));
-
-	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	/*
+	 * Must be a regular or partitioned table. System table, UNLOGGED and TEMP
+	 * table cannot be part of publication.
+	 */
+	if ((RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
+		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE) ||
+		(IsCatalogRelation(targetrel) || !RelationIsPermanent(targetrel)))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 errdetail_rel(RelationGetForm(targetrel))));
 }
 
 /*
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index d4943e374a..783f46786b 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -100,7 +100,7 @@ CommentObject(CommentStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set comment on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_rel(relation->rd_rel)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index c14ca27c5e..05fb76368f 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -655,7 +655,7 @@ DefineIndex(Oid relationId,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot create index on relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_rel(rel->rd_rel)));
 			break;
 	}
 
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 62465bacd8..0cfe592fb5 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -84,6 +84,8 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 		return;					/* woops, concurrently dropped; no permissions
 								 * check */
 
+	relpersistence = get_rel_persistence(relid);
+
 	/* Currently, we only allow plain tables or views to be locked */
 	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
 		relkind != RELKIND_VIEW)
@@ -91,13 +93,12 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot lock relation \"%s\"",
 						rv->relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_rel_v2(relid, relkind, relpersistence)));
 
 	/*
 	 * Make note if a temporary relation has been accessed in this
 	 * transaction.
 	 */
-	relpersistence = get_rel_persistence(relid);
 	if (relpersistence == RELPERSISTENCE_TEMP)
 		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 53c18628a7..e8722af3f5 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -191,7 +191,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot set security label on relation \"%s\"",
 								RelationGetRelationName(relation)),
-						 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+						 errdetail_rel(relation->rd_rel)));
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 72bfdc07a4..9888abeb48 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1655,7 +1655,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("sequence cannot be owned by relation \"%s\"",
 							RelationGetRelationName(tablerel)),
-					 errdetail_relkind_not_supported(tablerel->rd_rel->relkind)));
+					 errdetail_rel(tablerel->rd_rel)));
 
 		/* We insist on same owner and schema */
 		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 8f1550ec80..8f94b4d215 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -138,7 +138,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot define statistics for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_rel(rel->rd_rel)));
 
 		/* You must own the relation to create stats on it */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index c47ba26369..bbd250e012 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -533,7 +533,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 				relid = RangeVarGetRelid(rv, AccessShareLock, false);
 
 				/* Check for supported relkind. */
-				CheckSubscriptionRelkind(get_rel_relkind(relid),
+				CheckSubscriptionRelkind(relid, get_rel_relkind(relid),
 										 rv->schemaname, rv->relname);
 
 				AddSubscriptionRelState(subid, relid, table_state,
@@ -683,7 +683,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
 			relid = RangeVarGetRelid(rv, AccessShareLock, false);
 
 			/* Check for supported relkind. */
-			CheckSubscriptionRelkind(get_rel_relkind(relid),
+			CheckSubscriptionRelkind(relid, get_rel_relkind(relid),
 									 rv->schemaname, rv->relname);
 
 			pubrel_local_oids[off++] = relid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 857cc5ce6e..5f3a023ba9 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3327,6 +3327,7 @@ static void
 renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 {
 	char		relkind = classform->relkind;
+	char		relpersistence = classform->relpersistence;
 
 	if (classform->reloftype && !recursing)
 		ereport(ERROR,
@@ -3352,7 +3353,7 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot rename columns of relation \"%s\"",
 						NameStr(classform->relname)),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_rel_v2(myrelid, relkind, relpersistence)));
 
 	/*
 	 * permissions checking.  only the owner of a class can change its schema.
@@ -6192,7 +6193,7 @@ ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
 			/* translator: %s is a group of some SQL keywords */
 					 errmsg("ALTER action %s cannot be performed on relation \"%s\"",
 							action_str, RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_rel(rel->rd_rel)));
 		else
 			/* internal error? */
 			elog(ERROR, "invalid ALTER action attempted on relation \"%s\"",
@@ -13357,7 +13358,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot change owner of relation \"%s\"",
 							NameStr(tuple_class->relname)),
-					 errdetail_relkind_not_supported(tuple_class->relkind)));
+					 errdetail_rel(tuple_class)));
 	}
 
 	/*
@@ -13796,7 +13797,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot set options for relation \"%s\"",
 							RelationGetRelationName(rel)),
-					 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+					 errdetail_rel(rel->rd_rel)));
 			break;
 	}
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index d8890d2c74..27a51a5fc0 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -312,7 +312,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1289,7 +1289,7 @@ RemoveTriggerById(Oid trigOid)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						RelationGetRelationName(rel)),
-				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+				 errdetail_rel(rel->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1396,7 +1396,7 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have triggers",
 						rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_rel(form)));
 
 	/* you must own the table to rename one of its triggers */
 	if (!pg_class_ownercheck(relid, GetUserId()))
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 574d7d27fd..03b99a912d 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -605,7 +605,8 @@ CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
  * The nspname and relname are only needed for error reporting.
  */
 void
-CheckSubscriptionRelkind(char relkind, const char *nspname,
+CheckSubscriptionRelkind(Oid relid, char relkind,
+						 const char *nspname,
 						 const char *relname)
 {
 	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
@@ -613,5 +614,5 @@ CheckSubscriptionRelkind(char relkind, const char *nspname,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
 						nspname, relname),
-				 errdetail_relkind_not_supported(relkind)));
+				 errdetail_rel_v2(relid, relkind, RELPERSISTENCE_PERMANENT)));
 }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 313d7b6ff0..2d3665188d 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -976,7 +976,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" is invalid in LIKE clause",
 						RelationGetRelationName(relation)),
-				 errdetail_relkind_not_supported(relation->rd_rel->relkind)));
+				 errdetail_rel(relation->rd_rel)));
 
 	cancel_parser_errposition_callback(&pcbstate);
 
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index c37e2a7e29..ab174a48da 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -326,7 +326,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
 		entry->localreloid = relid;
 
 		/* Check for supported relkind. */
-		CheckSubscriptionRelkind(entry->localrel->rd_rel->relkind,
+		CheckSubscriptionRelkind(relid, entry->localrel->rd_rel->relkind,
 								 remoterel->nspname, remoterel->relname);
 
 		/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6589345ac4..98829e78db 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -270,7 +270,7 @@ DefineQueryRewrite(const char *rulename,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules",
 						RelationGetRelationName(event_relation)),
-				 errdetail_relkind_not_supported(event_relation->rd_rel->relkind)));
+				 errdetail_rel(event_relation->rd_rel)));
 
 	if (!allowSystemTableMods && IsSystemRelation(event_relation))
 		ereport(ERROR,
@@ -937,7 +937,7 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("relation \"%s\" cannot have rules", rv->relname),
-				 errdetail_relkind_not_supported(form->relkind)));
+				 errdetail_rel(form)));
 
 	if (!allowSystemTableMods && IsSystemClass(relid, form))
 		ereport(ERROR,
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index fef9945ed8..aaeede4651 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -156,6 +156,9 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_class_oid_index, 2662, ClassOidIndexId, on pg_class
 DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, ClassNameNspIndexId, on pg_class using btree(relname name_ops, relnamespace oid_ops));
 DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeIndexId, on pg_class using btree(reltablespace oid_ops, relfilenode oid_ops));
 
+extern int errdetail_rel(Form_pg_class rd_rel);
+extern int errdetail_rel_v2(Oid relid, char relkind, char relpersistence);
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 #define		  RELKIND_RELATION		  'r'	/* ordinary table */
@@ -198,8 +201,6 @@ DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeInd
 	 (relkind) == RELKIND_TOASTVALUE || \
 	 (relkind) == RELKIND_MATVIEW)
 
-extern int errdetail_relkind_not_supported(char relkind);
-
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
 #endif							/* PG_CLASS_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index cd57a704ad..45582f896d 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -644,7 +644,7 @@ extern void ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
 									 TupleTableSlot *searchslot);
 extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
 
-extern void CheckSubscriptionRelkind(char relkind, const char *nspname,
+extern void CheckSubscriptionRelkind(Oid relid, char relkind, const char *nspname,
 									 const char *relname);
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 2ff21a7543..1feb558968 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#24Peter Eisentraut
peter.eisentraut@enterprisedb.com
In reply to: Bharath Rupireddy (#23)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 14.11.21 13:18, Bharath Rupireddy wrote:

PSA v11 patch with 2 APIs with much simpler parameters and small
function names:

int errdetail_rel(Form_pg_class rd_rel);
int errdetail_rel_v2(Oid relid, char relkind, char relpersistence);

Please review it.

I think this is not an improvement. It loses the ability of the caller
the specify exactly why a relation is not acceptable. Before, a caller
could say, it's the wrong relkind, or it's the wrong persistence, or
whatever. Now, it just spits out some details about the relation, but
you can't control which. It could easily be wrong, too: AFAICT, this
will complain that a temporary table is not supported, but it could also
be that a table in general is not supported.

In my mind, this leads us back into the mess that we have before
errdetail_relkind_not_supported(): Very detailed error messages that
didn't actually hit the point.

I think a separate errdetail_relpersistence_not_supported() would be a
better solution (assuming there are enough callers to make it worth a
separate function).

#25Daniel Gustafsson
daniel@yesql.se
In reply to: Peter Eisentraut (#24)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 15 Nov 2021, at 09:15, Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:

I think this is not an improvement. It loses the ability of the caller the
specify exactly why a relation is not acceptable.

Agreed.

I think a separate errdetail_relpersistence_not_supported() would be a better
solution (assuming there are enough callers to make it worth a separate
function).

I still think that the v8 patch posted earlier is the better option, which
increase granularity of error reporting with a small code footprint.

--
Daniel Gustafsson https://vmware.com/

#26Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Daniel Gustafsson (#25)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Mon, Nov 15, 2021 at 2:14 PM Daniel Gustafsson <daniel@yesql.se> wrote:

On 15 Nov 2021, at 09:15, Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:

I think this is not an improvement. It loses the ability of the caller the
specify exactly why a relation is not acceptable.

Agreed.

+1.

I think a separate errdetail_relpersistence_not_supported() would be a better
solution (assuming there are enough callers to make it worth a separate
function).

I still think that the v8 patch posted earlier is the better option, which
increase granularity of error reporting with a small code footprint.

Thanks. Attaching the v8 here again.

Regards,
Bharath Rupireddy.

Attachments:

v8-0001-Improve-publication-error-messages.patchapplication/octet-stream; name=v8-0001-Improve-publication-error-messages.patchDownload
From eaa84990f679e04f042feeec451f5e0687b25525 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 4 Nov 2021 04:22:21 +0000
Subject: [PATCH v8] Improve publication error messages

Instead of a combined error message for unlogged and temporary
tables, have a separate message similar to the error message the
commit 81d5995b4b has introduced.

Also, add test cases to cover the above error cases.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  5 +++++
 src/backend/catalog/pg_publication.c           | 10 ++++++++--
 src/test/regress/expected/publication.out      | 16 ++++++++++++++++
 src/test/regress/sql/publication.sql           | 14 ++++++++++++++
 5 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index fd141a0fa5..cdb8df6f27 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 43c30d492d..1d2e9d2e80 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..ec2b8f9e6e 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -70,12 +70,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("This operation is not supported for system tables.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (RelationUsesLocalBuffers(targetrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 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("cannot add relation \"%s\" to publication",
+						RelationGetRelationName(targetrel)),
+				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 0f4fe4db8f..f141652516 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#27Peter Eisentraut
peter.eisentraut@enterprisedb.com
In reply to: Bharath Rupireddy (#26)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 15.11.21 10:38, Bharath Rupireddy wrote:

I still think that the v8 patch posted earlier is the better option, which
increase granularity of error reporting with a small code footprint.

Thanks. Attaching the v8 here again.

I find the use of RelationUsesLocalBuffers() confusing in this patch.
It would be clearer to check relpersistence directly in both branches of
the if statement.

#28Daniel Gustafsson
daniel@yesql.se
In reply to: Peter Eisentraut (#27)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 15 Nov 2021, at 19:42, Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:

On 15.11.21 10:38, Bharath Rupireddy wrote:

I still think that the v8 patch posted earlier is the better option, which
increase granularity of error reporting with a small code footprint.

Thanks. Attaching the v8 here again.

I find the use of RelationUsesLocalBuffers() confusing in this patch. It would be clearer to check relpersistence directly in both branches of the if statement.

Admittedly it didn't bother me, but the more I think about it the more I agree
with Peter, so +1 on changing.

--
Daniel Gustafsson https://vmware.com/

#29Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Daniel Gustafsson (#28)
1 attachment(s)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On Tue, Nov 16, 2021 at 3:06 AM Daniel Gustafsson <daniel@yesql.se> wrote:

On 15 Nov 2021, at 19:42, Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:

On 15.11.21 10:38, Bharath Rupireddy wrote:

I still think that the v8 patch posted earlier is the better option, which
increase granularity of error reporting with a small code footprint.

Thanks. Attaching the v8 here again.

I find the use of RelationUsesLocalBuffers() confusing in this patch. It would be clearer to check relpersistence directly in both branches of the if statement.

Admittedly it didn't bother me, but the more I think about it the more I agree
with Peter, so +1 on changing.

Done. PSA v9 patch.

Regards,
Bharath Rupireddy.

Attachments:

v9-0001-Improve-publication-error-messages.patchapplication/octet-stream; name=v9-0001-Improve-publication-error-messages.patchDownload
From 94a6254010e8fb7575703ec958ef0a9e003d185d Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 16 Nov 2021 02:28:37 +0000
Subject: [PATCH v9] Improve publication error messages

Instead of a combined error message for unlogged and temporary
tables, have a separate message similar to the error message the
commit 81d5995b4b has introduced.

Also, add test cases to cover the above error cases.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  6 ++++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  5 +++++
 src/backend/catalog/pg_publication.c           | 10 ++++++++--
 src/test/regress/expected/publication.out      | 16 ++++++++++++++++
 src/test/regress/sql/publication.sql           | 14 ++++++++++++++
 5 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 3cee0a8c12..786781db4b 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -256,6 +256,12 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 -- ===================================================================
+-- 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
+DETAIL:  This operation is not supported for foreign tables.
+-- ===================================================================
 -- simple queries
 -- ===================================================================
 -- single table without alias
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index e40112e41d..666d21962a 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -247,6 +247,11 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
 ANALYZE ft1;
 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
 
+-- ===================================================================
+-- test error case for create publication on foreign table
+-- ===================================================================
+CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
+
 -- ===================================================================
 -- simple queries
 -- ===================================================================
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index fed83b89a9..63579b2f82 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -70,12 +70,18 @@ check_publication_add_relation(Relation targetrel)
 				 errdetail("This operation is not supported for system tables.")));
 
 	/* UNLOGGED and TEMP relations cannot be part of publication. */
-	if (!RelationIsPermanent(targetrel))
+	if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("cannot add relation \"%s\" to publication",
 						RelationGetRelationName(targetrel)),
-				 errdetail("Temporary and unlogged relations cannot be replicated.")));
+				 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("cannot add relation \"%s\" to publication",
+						RelationGetRelationName(targetrel)),
+				 errdetail("This operation is not supported for unlogged tables.")));
 }
 
 /*
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 2ff21a7543..1feb558968 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -258,6 +258,22 @@ DROP TABLE testpub_tbl4;
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  cannot add relation "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
+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
+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
+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;
 RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 85a5302a74..8fa0435c32 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -150,6 +150,20 @@ DROP TABLE testpub_tbl4;
 
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
+
+CREATE TEMPORARY TABLE testpub_temptbl(a int);
+-- fail - temporary table
+CREATE PUBLICATION testpub_fortemptbl FOR TABLE testpub_temptbl;
+DROP TABLE testpub_temptbl;
+
+CREATE UNLOGGED TABLE testpub_unloggedtbl(a int);
+-- fail - unlogged table
+CREATE PUBLICATION testpub_forunloggedtbl FOR TABLE testpub_unloggedtbl;
+DROP TABLE testpub_unloggedtbl;
+
+-- fail - system table
+CREATE PUBLICATION testpub_forsystemtbl FOR TABLE pg_publication;
+
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1, pub_test.testpub_nopk;
 RESET client_min_messages;
-- 
2.25.1

#30Daniel Gustafsson
daniel@yesql.se
In reply to: Bharath Rupireddy (#29)
Re: Logical Replication - improve error message while adding tables to the publication in check_publication_add_relation

On 16 Nov 2021, at 03:30, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

Done. PSA v9 patch.

Pushed with some tweaking of the commit message, thanks!

--
Daniel Gustafsson https://vmware.com/