From c092a3cf55085725924417af1bb5c11dbcba31e2 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Wed, 10 Feb 2021 13:02:06 +1100
Subject: [PATCH v2] ReplicationSlotDropAtPubNode detect slot does not exist.

A new sqlstate member was added to WalRcvExecResult.

This allows walrcv_exec calling code to know the detailed cause of any error. Specifically, here it means the ReplicationSlotDropAtPubNode function can now identify the "slot does not exist error", and so can handle "missing_ok" more correctly.

Also, minor updates to PG docs now that ALTER SUBSCRIPTION may give ERROR instead of WARNING.
---
 doc/src/sgml/ref/alter_subscription.sgml                    | 7 +------
 src/backend/commands/subscriptioncmds.c                     | 3 ++-
 src/backend/replication/libpqwalreceiver/libpqwalreceiver.c | 8 ++++++++
 src/include/replication/walreceiver.h                       | 1 +
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml
index 1ca2437..bd81ea4 100644
--- a/doc/src/sgml/ref/alter_subscription.sgml
+++ b/doc/src/sgml/ref/alter_subscription.sgml
@@ -55,12 +55,7 @@ ALTER SUBSCRIPTION <replaceable class="parameter">name</replaceable> RENAME TO <
    any. It is necessary to remove tablesync slots so that the resources
    allocated for the subscription on the remote host are released. If due to
    network breakdown or some other error, <productname>PostgreSQL</productname>
-   is unable to remove the slots, a WARNING will be reported. The user needs to
-   manually remove such slots later or the
-   <xref linkend="guc-max-slot-wal-keep-size"/> should be configured on the
-   remote host as otherwise, they will continue to reserve WAL and might
-   eventually cause the disk to fill up. See also
-   <xref linkend="logical-replication-subscription-slot"/>.
+   is unable to remove the slots, an ERROR will be reported.
   </para>
 
   <para>
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 8046153..ff295c7 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -1314,7 +1314,8 @@ ReplicationSlotDropAtPubNode(WalReceiverConn *wrconn, char *slotname, bool missi
 					(errmsg("dropped replication slot \"%s\" on publisher",
 							slotname)));
 		}
-		else if (res->status == WALRCV_ERROR && missing_ok)
+		else if (res->status == WALRCV_ERROR &&
+				 missing_ok && res->sqlstate == ERRCODE_UNDEFINED_OBJECT)
 		{
 			/* WARNING. Error, but missing_ok = true. */
 			ereport(WARNING,
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index e958274..7714696 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -982,6 +982,7 @@ libpqrcv_exec(WalReceiverConn *conn, const char *query,
 {
 	PGresult   *pgres = NULL;
 	WalRcvExecResult *walres = palloc0(sizeof(WalRcvExecResult));
+	char	   *diag_sqlstate;
 
 	if (MyDatabaseId == InvalidOid)
 		ereport(ERROR,
@@ -1025,6 +1026,13 @@ libpqrcv_exec(WalReceiverConn *conn, const char *query,
 		case PGRES_BAD_RESPONSE:
 			walres->status = WALRCV_ERROR;
 			walres->err = pchomp(PQerrorMessage(conn->streamConn));
+			diag_sqlstate = PQresultErrorField(pgres, PG_DIAG_SQLSTATE);
+			if (diag_sqlstate)
+				walres->sqlstate = MAKE_SQLSTATE(diag_sqlstate[0],
+												 diag_sqlstate[1],
+												 diag_sqlstate[2],
+												 diag_sqlstate[3],
+												 diag_sqlstate[4]);
 			break;
 	}
 
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 4313f51..a97a59a 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -210,6 +210,7 @@ typedef enum
 typedef struct WalRcvExecResult
 {
 	WalRcvExecStatus status;
+	int			sqlstate;
 	char	   *err;
 	Tuplestorestate *tuplestore;
 	TupleDesc	tupledesc;
-- 
1.8.3.1

