diff --git a/doc/src/sgml/ref/pg_receivewal.sgml b/doc/src/sgml/ref/pg_receivewal.sgml index a17082b..e70b09a 100644 --- a/doc/src/sgml/ref/pg_receivewal.sgml +++ b/doc/src/sgml/ref/pg_receivewal.sgml @@ -93,6 +93,16 @@ PostgreSQL documentation + + + + Do not error out when is specified + and a slot with the specified name does not exist. + + + + + diff --git a/doc/src/sgml/ref/pg_recvlogical.sgml b/doc/src/sgml/ref/pg_recvlogical.sgml index eaea94d..8463daa 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 are + specified and a slot with the specified name does not exist. + + + + + diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index 370d871..1096afb 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -39,6 +39,7 @@ static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static volatile bool time_to_abort = false; static bool do_create_slot = false; static bool slot_exists_ok = false; +static bool slot_not_exists_ok = false; static bool do_drop_slot = false; static bool synchronous = false; static char *replication_slot = NULL; @@ -77,6 +78,7 @@ usage(void) printf(_(" %s [OPTION]...\n"), progname); printf(_("\nOptions:\n")); printf(_(" -D, --directory=DIR receive write-ahead log files into this directory\n")); + printf(_(" --if-exists do not error if slot does not exist when dropping a slot\n")); printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n")); printf(_(" -n, --no-loop do not loop on connection lost\n")); printf(_(" -s, --status-interval=SECS\n" @@ -472,8 +474,9 @@ main(int argc, char **argv) /* action */ {"create-slot", no_argument, NULL, 1}, {"drop-slot", no_argument, NULL, 2}, - {"if-not-exists", no_argument, NULL, 3}, - {"synchronous", no_argument, NULL, 4}, + {"if-exists", no_argument, NULL, 3}, + {"if-not-exists", no_argument, NULL, 4}, + {"synchronous", no_argument, NULL, 5}, {NULL, 0, NULL, 0} }; @@ -566,9 +569,12 @@ main(int argc, char **argv) do_drop_slot = true; break; case 3: - slot_exists_ok = true; + slot_not_exists_ok = true; break; case 4: + slot_exists_ok = true; + break; + case 5: synchronous = true; break; default: @@ -603,6 +609,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 (replication_slot == NULL && (do_drop_slot || do_create_slot)) { /* translator: second %s is an option name */ @@ -686,7 +700,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); disconnect_and_exit(0); } diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index 6b081bd..3e0b506 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 +714,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 +859,9 @@ main(int argc, char **argv) case 4: slot_exists_ok = true; break; + case 5: + slot_not_exists_ok = true; + break; default: @@ -903,6 +922,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 +994,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,