bdr: Prevent slot creation on output plugin if bdr ext missing
authorCraig Ringer <craig@2ndquadrant.com>
Mon, 15 Dec 2014 10:42:39 +0000 (18:42 +0800)
committerCraig Ringer <craig@2ndquadrant.com>
Wed, 4 Feb 2015 12:24:27 +0000 (23:24 +1100)
We shouldn't allow slot creation if the BDR extension is not installed
in a database.

bdr_output.c
expected/init.out
sql/init.sql

index 57cdea070985589f76cff3561b335fb63af6d22b..a9dc5051ab2a739fe35da1fc9586f15d2f6313f4 100644 (file)
@@ -219,12 +219,13 @@ bdr_req_param(const char *param)
 }
 
 /*
- * Check bdr.bdr_nodes entry in local DB and if status != r,
- * raise an error.
+ * Check bdr.bdr_nodes entry in local DB and if status != r
+ * and we're trying to begin logical replay, raise an error.
  *
- * If this function returns it's safe to begin replay.
+ * Also prevents slot creation if the BDR extension isn't installed in the
+ * local node.
  *
- * Must be called inside transaction.
+ * If this function returns it's safe to begin replay.
  */
 static void
 bdr_ensure_node_ready()
@@ -348,7 +349,7 @@ pg_decode_startup(LogicalDecodingContext * ctx, OutputPluginOptions *opt, bool i
    ListCell   *option;
    BdrOutputData *data;
    Oid schema_oid;
-   bool tx_started = true;
+   bool tx_started = false;
 
    bdr_worker_type = BDR_WORKER_WALSENDER;
 
@@ -462,6 +463,41 @@ pg_decode_startup(LogicalDecodingContext * ctx, OutputPluginOptions *opt, bool i
        }
    }
 
+   /*
+    * Ensure that the BDR extension is installed on this database.
+    *
+    * We must prevent slot creation before the BDR extension is created,
+    * otherwise the event trigger for DDL replication will record the
+    * extension's creation in bdr.bdr_queued_commands and the slot position
+    * will be before then, causing CREATE EXTENSION to be replayed. Since
+    * the other end already has the BDR extension (obviously) this will
+    * cause replay to fail.
+    *
+    * TODO: Should really test for the extension its self, but this is faster
+    * and easier...
+    */
+   if (!IsTransactionState())
+   {
+       tx_started = true;
+       StartTransactionCommand();
+   }
+
+#ifdef BUILDING_BDR
+   /*
+    * If running BDR, we expect the remote end (us) to have the BDR extension
+    * installed before we permit slot creation. This prevents replication of
+    * the CREATE EXTENSION bdr; command its self.
+    */
+   if (get_namespace_oid("bdr", true) == InvalidOid)
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("bdr extension does not exist on " BDR_LOCALID_FORMAT,
+                       BDR_LOCALID_FORMAT_ARGS),
+                errdetail("Cannot create a BDR slot without the BDR extension installed")));
+   }
+#endif
+
    /* no options are passed in during initialization, so don't complain there */
    if (!is_init)
    {
@@ -547,12 +583,6 @@ pg_decode_startup(LogicalDecodingContext * ctx, OutputPluginOptions *opt, bool i
        if (data->client_pg_version / 100 != PG_VERSION_NUM / 100)
            data->allow_sendrecv_protocol = false;
 
-       if (!IsTransactionState())
-       {
-           tx_started = false;
-           StartTransactionCommand();
-       }
-
        bdr_maintain_schema();
 
        data->bdr_schema_oid = get_namespace_oid("bdr", true);
@@ -585,13 +615,14 @@ pg_decode_startup(LogicalDecodingContext * ctx, OutputPluginOptions *opt, bool i
 
        /*
         * Make sure it's safe to begin playing changes to the remote end.
-        * This'll ERROR out if we're not ready.
+        * This'll ERROR out if we're not ready. Note that this does NOT
+        * prevent slot creation, only START_REPLICATION from the slot.
         */
        bdr_ensure_node_ready();
-
-       if (!tx_started)
-           CommitTransactionCommand();
    }
+
+   if (tx_started)
+       CommitTransactionCommand();
 }
 
 /*
index ab7045bd5d3055f359cb6fd8a155c81e77907d31..4dd05289da9cfbca97ca7c4cd8d194b73bef096e 100644 (file)
@@ -9,7 +9,7 @@ CREATE USER super SUPERUSER;
 GRANT ALL ON SCHEMA public TO nonsuper;
 \c regression
 GRANT ALL ON SCHEMA public TO nonsuper;
-SELECT pg_sleep(5);
+SELECT pg_sleep(10);
  pg_sleep 
 ----------
  
index a614cb93cc5cbe24018e3c9b75db771b7642636a..10271198731d4458481e9d7f9cb33bee084d2a21 100644 (file)
@@ -12,7 +12,7 @@ GRANT ALL ON SCHEMA public TO nonsuper;
 \c regression
 GRANT ALL ON SCHEMA public TO nonsuper;
 
-SELECT pg_sleep(5);
+SELECT pg_sleep(10);
 
 -- emulate the pg_xlog_wait_remote_apply on vanilla postgres
 DO $DO$BEGIN