]> granicus.if.org Git - postgresql/commitdiff
Optionally don't error out due to preexisting slots in commandline utilities.
authorAndres Freund <andres@anarazel.de>
Sun, 12 Jul 2015 20:06:27 +0000 (22:06 +0200)
committerAndres Freund <andres@anarazel.de>
Sun, 12 Jul 2015 20:15:31 +0000 (22:15 +0200)
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

doc/src/sgml/ref/pg_receivexlog.sgml
doc/src/sgml/ref/pg_recvlogical.sgml
src/bin/pg_basebackup/pg_receivexlog.c
src/bin/pg_basebackup/pg_recvlogical.c
src/bin/pg_basebackup/streamutil.c
src/bin/pg_basebackup/streamutil.h

index fd787649e42eb70b3976e2cdc063a6eaa3f75493..a4c98921cb8bd3b136d3c596243030f7ba63f0a3 100644 (file)
@@ -92,6 +92,16 @@ PostgreSQL documentation
       </listitem>
      </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>
       <term><option>-n</option></term>
       <term><option>--no-loop</option></term>
index a28dbc3f18441b0616638cacddfeda6a0941c55f..4eda9ebdd1f42c5d5b77597cd840c660ca505e6f 100644 (file)
@@ -154,6 +154,16 @@ PostgreSQL documentation
       </listitem>
      </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>
       <term><option>-n</option></term>
       <term><option>--no-loop</option></term>
index 5d964e4ee6b27d7c35e2b4a5c9aa8ee559345254..00536bd0972a5724a98bf8f3871694cee1af6147 100644 (file)
@@ -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);
        }
 
index 50844e700d9604d0014fac5e346bbdd5a7204f8e..f189f71eff6a14a369a6a5b2893e798cfd1a9753 100644 (file)
@@ -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)
index 0ed61440b09756148afd60c769b9e168a52f3e04..a5cad350f8a498aed377da579851489de40732e8 100644 (file)
@@ -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;
index 01ab5660a14d928e03b06d99b73dfc1dec47b0a6..b95f83f87e032e9eef87f70d87c867e776c1f370 100644 (file)
@@ -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,