diff --git a/doc/src/sgml/ref/pg_recvlogical.sgml b/doc/src/sgml/ref/pg_recvlogical.sgml index eaea94d..2c638d3 100644 --- a/doc/src/sgml/ref/pg_recvlogical.sgml +++ b/doc/src/sgml/ref/pg_recvlogical.sgml @@ -199,6 +199,16 @@ PostgreSQL documentation + + + + Do not error out when or + + + + diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index 370d871..ace5372 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -686,7 +686,7 @@ main(int argc, char **argv) _("%s: dropping replication slot \"%s\"\n"), progname, replication_slot); - if (!DropReplicationSlot(conn, replication_slot)) + if (!DropReplicationSlot(conn, replication_slot, false)) disconnect_and_exit(1); disconnect_and_exit(0); } diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index 6b081bd..46ea5a3 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -33,6 +33,8 @@ /* Time to sleep between reconnection attempts */ #define RECONNECT_SLEEP_TIME 5 +#define ERRCODE_UNKNOWN_OBJECT "42704" + /* Global Options */ static char *outfile = NULL; static int verbose = 0; @@ -43,6 +45,7 @@ static XLogRecPtr startpos = InvalidXLogRecPtr; static XLogRecPtr endpos = InvalidXLogRecPtr; static bool do_create_slot = false; static bool slot_exists_ok = false; +static bool slot_not_exists_ok = false; static bool do_start_slot = false; static bool do_drop_slot = false; static char *replication_slot = NULL; @@ -84,6 +87,7 @@ usage(void) printf(_(" -f, --file=FILE receive log into this file, - for stdout\n")); printf(_(" -F --fsync-interval=SECS\n" " time between fsyncs to the output file (default: %d)\n"), (fsync_interval / 1000)); + printf(_(" --if-exists do not error if slot does not exist\n")); printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n")); printf(_(" -I, --startpos=LSN where in an existing slot should the streaming start\n")); printf(_(" -E, --endpos=LSN exit after receiving the specified LSN\n")); @@ -267,6 +271,17 @@ StreamLogicalLog(void) res = PQexec(conn, query->data); if (PQresultStatus(res) != PGRES_COPY_BOTH) { + const char* sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); + + if (slot_not_exists_ok && + sqlstate && + strcmp(sqlstate, ERRCODE_UNKNOWN_OBJECT) == 0) + { + destroyPQExpBuffer(query); + PQclear(res); + disconnect_and_exit(0); + } + fprintf(stderr, _("%s: could not send replication command \"%s\": %s"), progname, query->data, PQresultErrorMessage(res)); PQclear(res); @@ -699,6 +716,7 @@ main(int argc, char **argv) {"start", no_argument, NULL, 2}, {"drop-slot", no_argument, NULL, 3}, {"if-not-exists", no_argument, NULL, 4}, + {"if-exists", no_argument, NULL, 5}, {NULL, 0, NULL, 0} }; int c; @@ -843,6 +861,9 @@ main(int argc, char **argv) case 4: slot_exists_ok = true; break; + case 5: + slot_not_exists_ok = true; + break; default: @@ -903,6 +924,14 @@ main(int argc, char **argv) exit(1); } + if (do_create_slot && slot_not_exists_ok) + { + fprintf(stderr, _("%s: cannot use --create-slot with --if-exists\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } + if (do_drop_slot && (do_create_slot || do_start_slot)) { fprintf(stderr, _("%s: cannot use --create-slot or --start together with --drop-slot\n"), progname); @@ -967,7 +996,7 @@ main(int argc, char **argv) _("%s: dropping replication slot \"%s\"\n"), progname, replication_slot); - if (!DropReplicationSlot(conn, replication_slot)) + if (!DropReplicationSlot(conn, replication_slot, slot_not_exists_ok)) disconnect_and_exit(1); } diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index 7ea3b0f..84dd135 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -29,6 +29,7 @@ #include "datatype/timestamp.h" #define ERRCODE_DUPLICATE_OBJECT "42710" +#define ERRCODE_UNKNOWN_OBJECT "42704" const char *progname; char *connection_string = NULL; @@ -391,7 +392,7 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin, * returns true in case of success. */ bool -DropReplicationSlot(PGconn *conn, const char *slot_name) +DropReplicationSlot(PGconn *conn, const char *slot_name, bool slot_not_exists_ok) { PQExpBuffer query; PGresult *res; @@ -406,6 +407,17 @@ DropReplicationSlot(PGconn *conn, const char *slot_name) res = PQexec(conn, query->data); if (PQresultStatus(res) != PGRES_COMMAND_OK) { + const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); + + if (slot_not_exists_ok && + sqlstate && + strcmp(sqlstate, ERRCODE_UNKNOWN_OBJECT) == 0) + { + destroyPQExpBuffer(query); + PQclear(res); + return true; + } + fprintf(stderr, _("%s: could not send replication command \"%s\": %s"), progname, query->data, PQerrorMessage(conn)); diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h index 460dcb5..845e48a 100644 --- a/src/bin/pg_basebackup/streamutil.h +++ b/src/bin/pg_basebackup/streamutil.h @@ -34,7 +34,8 @@ extern PGconn *GetConnection(void); extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin, bool is_physical, bool slot_exists_ok); -extern bool DropReplicationSlot(PGconn *conn, const char *slot_name); +extern bool DropReplicationSlot(PGconn *conn, const char *slot_name, + bool slot_not_exists_ok); extern bool RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli, XLogRecPtr *startpos,