mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-05 10:39:19 +02:00
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
This commit is contained in:
parent
ccd062cfb9
commit
0e8e48b0da
@ -92,6 +92,16 @@ PostgreSQL documentation
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--if-not-exists</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Do not not error out when <option>--create-slot</option> is specified
|
||||||
|
and a slot with the specified name already exists.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-n</option></term>
|
<term><option>-n</option></term>
|
||||||
<term><option>--no-loop</option></term>
|
<term><option>--no-loop</option></term>
|
||||||
|
@ -154,6 +154,16 @@ PostgreSQL documentation
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--if-not-exists</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Do not not error out when <option>--create-slot</option> is specified
|
||||||
|
and a slot with the specified name already exists.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-n</option></term>
|
<term><option>-n</option></term>
|
||||||
<term><option>--no-loop</option></term>
|
<term><option>--no-loop</option></term>
|
||||||
|
@ -38,6 +38,7 @@ static int noloop = 0;
|
|||||||
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
||||||
static volatile bool time_to_abort = false;
|
static volatile bool time_to_abort = false;
|
||||||
static bool do_create_slot = false;
|
static bool do_create_slot = false;
|
||||||
|
static bool slot_exists_ok = false;
|
||||||
static bool do_drop_slot = false;
|
static bool do_drop_slot = false;
|
||||||
static bool synchronous = false;
|
static bool synchronous = false;
|
||||||
|
|
||||||
@ -66,6 +67,7 @@ usage(void)
|
|||||||
printf(_(" %s [OPTION]...\n"), progname);
|
printf(_(" %s [OPTION]...\n"), progname);
|
||||||
printf(_("\nOptions:\n"));
|
printf(_("\nOptions:\n"));
|
||||||
printf(_(" -D, --directory=DIR receive transaction log files into this directory\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(_(" -n, --no-loop do not loop on connection lost\n"));
|
||||||
printf(_(" -s, --status-interval=SECS\n"
|
printf(_(" -s, --status-interval=SECS\n"
|
||||||
" time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
|
" time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
|
||||||
@ -371,7 +373,8 @@ main(int argc, char **argv)
|
|||||||
/* action */
|
/* action */
|
||||||
{"create-slot", no_argument, NULL, 1},
|
{"create-slot", no_argument, NULL, 1},
|
||||||
{"drop-slot", no_argument, NULL, 2},
|
{"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}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -455,6 +458,9 @@ main(int argc, char **argv)
|
|||||||
do_drop_slot = true;
|
do_drop_slot = true;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
slot_exists_ok = true;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
synchronous = true;
|
synchronous = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -575,7 +581,8 @@ main(int argc, char **argv)
|
|||||||
_("%s: creating replication slot \"%s\"\n"),
|
_("%s: creating replication slot \"%s\"\n"),
|
||||||
progname, replication_slot);
|
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);
|
disconnect_and_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
|||||||
static int fsync_interval = 10 * 1000; /* 10 sec = default */
|
static int fsync_interval = 10 * 1000; /* 10 sec = default */
|
||||||
static XLogRecPtr startpos = InvalidXLogRecPtr;
|
static XLogRecPtr startpos = InvalidXLogRecPtr;
|
||||||
static bool do_create_slot = false;
|
static bool do_create_slot = false;
|
||||||
|
static bool slot_exists_ok = false;
|
||||||
static bool do_start_slot = false;
|
static bool do_start_slot = false;
|
||||||
static bool do_drop_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, --file=FILE receive log into this file, - for stdout\n"));
|
||||||
printf(_(" -F --fsync-interval=SECS\n"
|
printf(_(" -F --fsync-interval=SECS\n"
|
||||||
" time between fsyncs to the output file (default: %d)\n"), (fsync_interval / 1000));
|
" 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(_(" -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(_(" -n, --no-loop do not loop on connection lost\n"));
|
||||||
printf(_(" -o, --option=NAME[=VALUE]\n"
|
printf(_(" -o, --option=NAME[=VALUE]\n"
|
||||||
@ -633,6 +635,7 @@ main(int argc, char **argv)
|
|||||||
{"create-slot", no_argument, NULL, 1},
|
{"create-slot", no_argument, NULL, 1},
|
||||||
{"start", no_argument, NULL, 2},
|
{"start", no_argument, NULL, 2},
|
||||||
{"drop-slot", no_argument, NULL, 3},
|
{"drop-slot", no_argument, NULL, 3},
|
||||||
|
{"if-not-exists", no_argument, NULL, 4},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
int c;
|
int c;
|
||||||
@ -764,6 +767,9 @@ main(int argc, char **argv)
|
|||||||
case 3:
|
case 3:
|
||||||
do_drop_slot = true;
|
do_drop_slot = true;
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
slot_exists_ok = true;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
@ -891,8 +897,9 @@ main(int argc, char **argv)
|
|||||||
progname, replication_slot);
|
progname, replication_slot);
|
||||||
|
|
||||||
if (!CreateReplicationSlot(conn, replication_slot, plugin,
|
if (!CreateReplicationSlot(conn, replication_slot, plugin,
|
||||||
&startpos, false))
|
false, slot_exists_ok))
|
||||||
disconnect_and_exit(1);
|
disconnect_and_exit(1);
|
||||||
|
startpos = InvalidXLogRecPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!do_start_slot)
|
if (!do_start_slot)
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include "common/fe_memutils.h"
|
#include "common/fe_memutils.h"
|
||||||
#include "datatype/timestamp.h"
|
#include "datatype/timestamp.h"
|
||||||
|
|
||||||
|
#define ERRCODE_DUPLICATE_OBJECT "42710"
|
||||||
|
|
||||||
const char *progname;
|
const char *progname;
|
||||||
char *connection_string = NULL;
|
char *connection_string = NULL;
|
||||||
char *dbhost = NULL;
|
char *dbhost = NULL;
|
||||||
@ -314,7 +316,7 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
|
CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
|
||||||
XLogRecPtr *startpos, bool is_physical)
|
bool is_physical, bool slot_exists_ok)
|
||||||
{
|
{
|
||||||
PQExpBuffer query;
|
PQExpBuffer query;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
@ -336,12 +338,23 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
|
|||||||
res = PQexec(conn, query->data);
|
res = PQexec(conn, query->data);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
|
const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
|
||||||
progname, query->data, PQerrorMessage(conn));
|
|
||||||
|
|
||||||
destroyPQExpBuffer(query);
|
if (slot_exists_ok && strcmp(sqlstate, ERRCODE_DUPLICATE_OBJECT) == 0)
|
||||||
PQclear(res);
|
{
|
||||||
return false;
|
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)
|
if (PQntuples(res) != 1 || PQnfields(res) != 4)
|
||||||
@ -356,25 +369,6 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
|
|||||||
return false;
|
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);
|
destroyPQExpBuffer(query);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
return true;
|
return true;
|
||||||
|
@ -32,8 +32,8 @@ extern PGconn *GetConnection(void);
|
|||||||
|
|
||||||
/* Replication commands */
|
/* Replication commands */
|
||||||
extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name,
|
extern bool CreateReplicationSlot(PGconn *conn, const char *slot_name,
|
||||||
const char *plugin, XLogRecPtr *startpos,
|
const char *plugin, bool is_physical,
|
||||||
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);
|
||||||
extern bool RunIdentifySystem(PGconn *conn, char **sysid,
|
extern bool RunIdentifySystem(PGconn *conn, char **sysid,
|
||||||
TimeLineID *starttli,
|
TimeLineID *starttli,
|
||||||
|
Loading…
Reference in New Issue
Block a user