diff --git a/doc/src/sgml/ref/pg_receivexlog.sgml b/doc/src/sgml/ref/pg_receivexlog.sgml
index fd787649e42..a4c98921cb8 100644
--- a/doc/src/sgml/ref/pg_receivexlog.sgml
+++ b/doc/src/sgml/ref/pg_receivexlog.sgml
@@ -92,6 +92,16 @@ PostgreSQL documentation
+
+
+
+
+ Do not not error out when is specified
+ and a slot with the specified name already exists.
+
+
+
+
diff --git a/doc/src/sgml/ref/pg_recvlogical.sgml b/doc/src/sgml/ref/pg_recvlogical.sgml
index a28dbc3f184..4eda9ebdd1f 100644
--- a/doc/src/sgml/ref/pg_recvlogical.sgml
+++ b/doc/src/sgml/ref/pg_recvlogical.sgml
@@ -154,6 +154,16 @@ PostgreSQL documentation
+
+
+
+
+ Do not not error out when is specified
+ and a slot with the specified name already exists.
+
+
+
+
diff --git a/src/bin/pg_basebackup/pg_receivexlog.c b/src/bin/pg_basebackup/pg_receivexlog.c
index 5d964e4ee6b..00536bd0972 100644
--- a/src/bin/pg_basebackup/pg_receivexlog.c
+++ b/src/bin/pg_basebackup/pg_receivexlog.c
@@ -38,6 +38,7 @@ static int noloop = 0;
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 do_drop_slot = false;
static bool synchronous = false;
@@ -66,6 +67,7 @@ usage(void)
printf(_(" %s [OPTION]...\n"), progname);
printf(_("\nOptions:\n"));
printf(_(" -D, --directory=DIR receive transaction log files into this directory\n"));
+ printf(_(" --if-not-exists do not treat naming conflicts as an error when creating a slot\n"));
printf(_(" -n, --no-loop do not loop on connection lost\n"));
printf(_(" -s, --status-interval=SECS\n"
" time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
@@ -371,7 +373,8 @@ main(int argc, char **argv)
/* action */
{"create-slot", no_argument, NULL, 1},
{"drop-slot", no_argument, NULL, 2},
- {"synchronous", no_argument, NULL, 3},
+ {"if-not-exists", no_argument, NULL, 3},
+ {"synchronous", no_argument, NULL, 4},
{NULL, 0, NULL, 0}
};
@@ -455,6 +458,9 @@ main(int argc, char **argv)
do_drop_slot = true;
break;
case 3:
+ slot_exists_ok = true;
+ break;
+ case 4:
synchronous = true;
break;
default:
@@ -575,7 +581,8 @@ main(int argc, char **argv)
_("%s: creating replication slot \"%s\"\n"),
progname, replication_slot);
- if (!CreateReplicationSlot(conn, replication_slot, NULL, NULL, true))
+ if (!CreateReplicationSlot(conn, replication_slot, NULL, true,
+ slot_exists_ok))
disconnect_and_exit(1);
}
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 50844e700d9..f189f71eff6 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -38,6 +38,7 @@ static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
static int fsync_interval = 10 * 1000; /* 10 sec = default */
static XLogRecPtr startpos = InvalidXLogRecPtr;
static bool do_create_slot = false;
+static bool slot_exists_ok = false;
static bool do_start_slot = false;
static bool do_drop_slot = false;
@@ -75,6 +76,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-not-exists do not treat naming conflicts as an error when creating a slot\n"));
printf(_(" -I, --startpos=LSN where in an existing slot should the streaming start\n"));
printf(_(" -n, --no-loop do not loop on connection lost\n"));
printf(_(" -o, --option=NAME[=VALUE]\n"
@@ -633,6 +635,7 @@ main(int argc, char **argv)
{"create-slot", no_argument, NULL, 1},
{"start", no_argument, NULL, 2},
{"drop-slot", no_argument, NULL, 3},
+ {"if-not-exists", no_argument, NULL, 4},
{NULL, 0, NULL, 0}
};
int c;
@@ -764,6 +767,9 @@ main(int argc, char **argv)
case 3:
do_drop_slot = true;
break;
+ case 4:
+ slot_exists_ok = true;
+ break;
default:
@@ -891,8 +897,9 @@ main(int argc, char **argv)
progname, replication_slot);
if (!CreateReplicationSlot(conn, replication_slot, plugin,
- &startpos, false))
+ false, slot_exists_ok))
disconnect_and_exit(1);
+ startpos = InvalidXLogRecPtr;
}
if (!do_start_slot)
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 0ed61440b09..a5cad350f8a 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -31,6 +31,8 @@
#include "common/fe_memutils.h"
#include "datatype/timestamp.h"
+#define ERRCODE_DUPLICATE_OBJECT "42710"
+
const char *progname;
char *connection_string = NULL;
char *dbhost = NULL;
@@ -314,7 +316,7 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
*/
bool
CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
- XLogRecPtr *startpos, bool is_physical)
+ bool is_physical, bool slot_exists_ok)
{
PQExpBuffer query;
PGresult *res;
@@ -336,12 +338,23 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
res = PQexec(conn, query->data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
- fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
- progname, query->data, PQerrorMessage(conn));
+ const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
- destroyPQExpBuffer(query);
- PQclear(res);
- return false;
+ if (slot_exists_ok && strcmp(sqlstate, ERRCODE_DUPLICATE_OBJECT) == 0)
+ {
+ destroyPQExpBuffer(query);
+ PQclear(res);
+ return true;
+ }
+ else
+ {
+ fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
+ progname, query->data, PQerrorMessage(conn));
+
+ destroyPQExpBuffer(query);
+ PQclear(res);
+ return false;
+ }
}
if (PQntuples(res) != 1 || PQnfields(res) != 4)
@@ -356,25 +369,6 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
return false;
}
- /* Get LSN start position if necessary */
- if (startpos != NULL)
- {
- uint32 hi,
- lo;
-
- if (sscanf(PQgetvalue(res, 0, 1), "%X/%X", &hi, &lo) != 2)
- {
- fprintf(stderr,
- _("%s: could not parse transaction log location \"%s\"\n"),
- progname, PQgetvalue(res, 0, 1));
-
- destroyPQExpBuffer(query);
- PQclear(res);
- return false;
- }
- *startpos = ((uint64) hi) << 32 | lo;
- }
-
destroyPQExpBuffer(query);
PQclear(res);
return true;
diff --git a/src/bin/pg_basebackup/streamutil.h b/src/bin/pg_basebackup/streamutil.h
index 01ab5660a14..b95f83f87e0 100644
--- a/src/bin/pg_basebackup/streamutil.h
+++ b/src/bin/pg_basebackup/streamutil.h
@@ -32,8 +32,8 @@ extern PGconn *GetConnection(void);
/* Replication commands */
extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name,
- const char *plugin, XLogRecPtr *startpos,
- bool is_physical);
+ const char *plugin, bool is_physical,
+ bool slot_exists_ok);
extern bool DropReplicationSlot(PGconn *conn, const char *slot_name);
extern bool RunIdentifySystem(PGconn *conn, char **sysid,
TimeLineID *starttli,