Skip to content

Commit ff27db5

Browse files
committed
Optionally don't error out due to preexisting slots in commandline utilities.
pg_receivexlog and pg_recvlogical error out when --create-slot is specified and a slot with the same name already exists. In some cases, especially with pg_receivexlog, that's rather annoying and requires additional scripting. Backpatch to 9.5 as slot control functions have newly been added to pg_receivexlog, and there doesn't seem much point leaving it in a less useful state. Discussion: 20150619144755.GG29350@alap3.anarazel.de
1 parent 0a0fe2f commit ff27db5

File tree

6 files changed

+58
-30
lines changed

6 files changed

+58
-30
lines changed

doc/src/sgml/ref/pg_receivexlog.sgml

+10
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ PostgreSQL documentation
9292
</listitem>
9393
</varlistentry>
9494

95+
<varlistentry>
96+
<term><option>--if-not-exists</option></term>
97+
<listitem>
98+
<para>
99+
Do not not error out when <option>--create-slot</option> is specified
100+
and a slot with the specified name already exists.
101+
</para>
102+
</listitem>
103+
</varlistentry>
104+
95105
<varlistentry>
96106
<term><option>-n</option></term>
97107
<term><option>--no-loop</option></term>

doc/src/sgml/ref/pg_recvlogical.sgml

+10
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ PostgreSQL documentation
154154
</listitem>
155155
</varlistentry>
156156

157+
<varlistentry>
158+
<term><option>--if-not-exists</option></term>
159+
<listitem>
160+
<para>
161+
Do not not error out when <option>--create-slot</option> is specified
162+
and a slot with the specified name already exists.
163+
</para>
164+
</listitem>
165+
</varlistentry>
166+
157167
<varlistentry>
158168
<term><option>-n</option></term>
159169
<term><option>--no-loop</option></term>

src/bin/pg_basebackup/pg_receivexlog.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static int noloop = 0;
3838
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
3939
static volatile bool time_to_abort = false;
4040
static bool do_create_slot = false;
41+
static bool slot_exists_ok = false;
4142
static bool do_drop_slot = false;
4243
static bool synchronous = false;
4344

@@ -66,6 +67,7 @@ usage(void)
6667
printf(_(" %s [OPTION]...\n"), progname);
6768
printf(_("\nOptions:\n"));
6869
printf(_(" -D, --directory=DIR receive transaction log files into this directory\n"));
70+
printf(_(" --if-not-exists do not treat naming conflicts as an error when creating a slot\n"));
6971
printf(_(" -n, --no-loop do not loop on connection lost\n"));
7072
printf(_(" -s, --status-interval=SECS\n"
7173
" time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
@@ -371,7 +373,8 @@ main(int argc, char **argv)
371373
/* action */
372374
{"create-slot", no_argument, NULL, 1},
373375
{"drop-slot", no_argument, NULL, 2},
374-
{"synchronous", no_argument, NULL, 3},
376+
{"if-not-exists", no_argument, NULL, 3},
377+
{"synchronous", no_argument, NULL, 4},
375378
{NULL, 0, NULL, 0}
376379
};
377380

@@ -455,6 +458,9 @@ main(int argc, char **argv)
455458
do_drop_slot = true;
456459
break;
457460
case 3:
461+
slot_exists_ok = true;
462+
break;
463+
case 4:
458464
synchronous = true;
459465
break;
460466
default:
@@ -575,7 +581,8 @@ main(int argc, char **argv)
575581
_("%s: creating replication slot \"%s\"\n"),
576582
progname, replication_slot);
577583

578-
if (!CreateReplicationSlot(conn, replication_slot, NULL, NULL, true))
584+
if (!CreateReplicationSlot(conn, replication_slot, NULL, true,
585+
slot_exists_ok))
579586
disconnect_and_exit(1);
580587
}
581588

src/bin/pg_basebackup/pg_recvlogical.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
3838
static int fsync_interval = 10 * 1000; /* 10 sec = default */
3939
static XLogRecPtr startpos = InvalidXLogRecPtr;
4040
static bool do_create_slot = false;
41+
static bool slot_exists_ok = false;
4142
static bool do_start_slot = false;
4243
static bool do_drop_slot = false;
4344

@@ -75,6 +76,7 @@ usage(void)
7576
printf(_(" -f, --file=FILE receive log into this file, - for stdout\n"));
7677
printf(_(" -F --fsync-interval=SECS\n"
7778
" time between fsyncs to the output file (default: %d)\n"), (fsync_interval / 1000));
79+
printf(_(" --if-not-exists do not treat naming conflicts as an error when creating a slot\n"));
7880
printf(_(" -I, --startpos=LSN where in an existing slot should the streaming start\n"));
7981
printf(_(" -n, --no-loop do not loop on connection lost\n"));
8082
printf(_(" -o, --option=NAME[=VALUE]\n"
@@ -633,6 +635,7 @@ main(int argc, char **argv)
633635
{"create-slot", no_argument, NULL, 1},
634636
{"start", no_argument, NULL, 2},
635637
{"drop-slot", no_argument, NULL, 3},
638+
{"if-not-exists", no_argument, NULL, 4},
636639
{NULL, 0, NULL, 0}
637640
};
638641
int c;
@@ -764,6 +767,9 @@ main(int argc, char **argv)
764767
case 3:
765768
do_drop_slot = true;
766769
break;
770+
case 4:
771+
slot_exists_ok = true;
772+
break;
767773

768774
default:
769775

@@ -891,8 +897,9 @@ main(int argc, char **argv)
891897
progname, replication_slot);
892898

893899
if (!CreateReplicationSlot(conn, replication_slot, plugin,
894-
&startpos, false))
900+
false, slot_exists_ok))
895901
disconnect_and_exit(1);
902+
startpos = InvalidXLogRecPtr;
896903
}
897904

898905
if (!do_start_slot)

src/bin/pg_basebackup/streamutil.c

+19-25
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "common/fe_memutils.h"
3232
#include "datatype/timestamp.h"
3333

34+
#define ERRCODE_DUPLICATE_OBJECT "42710"
35+
3436
const char *progname;
3537
char *connection_string = NULL;
3638
char *dbhost = NULL;
@@ -314,7 +316,7 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
314316
*/
315317
bool
316318
CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
317-
XLogRecPtr *startpos, bool is_physical)
319+
bool is_physical, bool slot_exists_ok)
318320
{
319321
PQExpBuffer query;
320322
PGresult *res;
@@ -336,12 +338,23 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
336338
res = PQexec(conn, query->data);
337339
if (PQresultStatus(res) != PGRES_TUPLES_OK)
338340
{
339-
fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
340-
progname, query->data, PQerrorMessage(conn));
341+
const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
341342

342-
destroyPQExpBuffer(query);
343-
PQclear(res);
344-
return false;
343+
if (slot_exists_ok && strcmp(sqlstate, ERRCODE_DUPLICATE_OBJECT) == 0)
344+
{
345+
destroyPQExpBuffer(query);
346+
PQclear(res);
347+
return true;
348+
}
349+
else
350+
{
351+
fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
352+
progname, query->data, PQerrorMessage(conn));
353+
354+
destroyPQExpBuffer(query);
355+
PQclear(res);
356+
return false;
357+
}
345358
}
346359

347360
if (PQntuples(res) != 1 || PQnfields(res) != 4)
@@ -356,25 +369,6 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
356369
return false;
357370
}
358371

359-
/* Get LSN start position if necessary */
360-
if (startpos != NULL)
361-
{
362-
uint32 hi,
363-
lo;
364-
365-
if (sscanf(PQgetvalue(res, 0, 1), "%X/%X", &hi, &lo) != 2)
366-
{
367-
fprintf(stderr,
368-
_("%s: could not parse transaction log location \"%s\"\n"),
369-
progname, PQgetvalue(res, 0, 1));
370-
371-
destroyPQExpBuffer(query);
372-
PQclear(res);
373-
return false;
374-
}
375-
*startpos = ((uint64) hi) << 32 | lo;
376-
}
377-
378372
destroyPQExpBuffer(query);
379373
PQclear(res);
380374
return true;

src/bin/pg_basebackup/streamutil.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ extern PGconn *GetConnection(void);
3232

3333
/* Replication commands */
3434
extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name,
35-
const char *plugin, XLogRecPtr *startpos,
36-
bool is_physical);
35+
const char *plugin, bool is_physical,
36+
bool slot_exists_ok);
3737
extern bool DropReplicationSlot(PGconn *conn, const char *slot_name);
3838
extern bool RunIdentifySystem(PGconn *conn, char **sysid,
3939
TimeLineID *starttli,

0 commit comments

Comments
 (0)