On 12/10/16 2:48 AM, Petr Jelinek wrote:
> Attached new version with your updates and rebased on top of the current
> HEAD (the partitioning patch produced quite a few conflicts).

I have attached a few more "fixup" patches, mostly with some editing of
documentation and comments and some compiler warnings.

In 0006 in the protocol documentation I have left a "XXX ???" where I
didn't understand what it was trying to say.

All issues from (my) previous reviews appear to have been addressed.

Comments besides that:


0003-Add-SUBSCRIPTION-catalog-and-DDL-v12.patch

Still wondering about the best workflow with pg_dump, but it seems all
the pieces are there right now, and the interfaces can be tweaked later.

DROP SUBSCRIPTION requires superuser, but should perhaps be owner check
only?

DROP SUBSCRIPTION IF EXISTS crashes if the subscription does not in fact
exist.

Maybe write the grammar so that SLOT does not need to be a new key word.
 The changes you made for CREATE PUBLICATION should allow that.

The tests are not added to serial_schedule.  Intentional?  If so, document?


0004-Define-logical-replication-protocol-and-output-plugi-v12.patch

Not sure why pg_catalog is encoded as a zero-length string.  I guess it
saves some space.  Maybe that could be explained in a brief code comment?


0005-Add-logical-replication-workers-v12.patch

The way the executor stuff is organized now looks better to me.

The subscriber crashes if max_replication_slots is 0:

TRAP: FailedAssertion("!(max_replication_slots > 0)", File: "origin.c",
Line: 999)

The documentation says that replication slots are required on the
subscriber, but from a user's perspective, it's not clear why that is.

Dropping a table that is part of a live subscription results in log
messages like

WARNING:  leaked hash_seq_search scan for hash table 0x7f9d2a807238

I was testing replicating into a temporary table, which failed like this:

FATAL:  the logical replication target public.test1 not found
LOG:  worker process:  (PID 2879) exited with exit code 1
LOG:  starting logical replication worker for subscription 16392
LOG:  logical replication apply for subscription mysub started

That's okay, but those messages were repeated every few seconds or so
and would create quite some log volume.  I wonder if that needs to be
reigned in somewhat.


I think this is getting very close to the point where it's committable.
So if anyone else has major concerns about the whole approach and
perhaps the way the new code in 0005 is organized, now would be the time ...

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From df169d3fec6d67c3daf301d9ed9903545358dd7e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Mon, 12 Dec 2016 12:00:00 -0500
Subject: [PATCH 2/8] fixup! Add PUBLICATION catalogs and DDL

---
 src/backend/commands/publicationcmds.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 954b2bd65d..f1d7404ffe 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -389,7 +389,6 @@ AlterPublication(AlterPublicationStmt *stmt)
 {
 	Relation		rel;
 	HeapTuple		tup;
-	AclResult		aclresult;
 
 	rel = heap_open(PublicationRelationId, RowExclusiveLock);
 
@@ -564,12 +563,11 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists,
 	foreach(lc, rels)
 	{
 		Relation	rel = (Relation) lfirst(lc);
-		AclResult	aclresult;
 		ObjectAddress	obj;
 
 		/* Must be owner of the table or superuser. */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
-			aclcheck_error(aclresult, ACL_KIND_CLASS,
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 						   RelationGetRelationName(rel));
 
 		obj = publication_add_relation(pubid, rel, if_not_exists);
-- 
2.11.0

From 2cab724505487663b53f8af09c8e16a70c52014d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Fri, 9 Dec 2016 12:00:00 -0500
Subject: [PATCH 4/8] fixup! Add SUBSCRIPTION catalog and DDL

---
 doc/src/sgml/catalogs.sgml                         | 28 ++++++-------
 doc/src/sgml/ref/alter_subscription.sgml           | 25 +++++-------
 doc/src/sgml/ref/create_subscription.sgml          | 47 ++++++++++------------
 doc/src/sgml/ref/drop_subscription.sgml            | 23 ++++++-----
 doc/src/sgml/ref/psql-ref.sgml                     |  6 +--
 src/backend/catalog/pg_subscription.c              |  2 +-
 src/backend/commands/subscriptioncmds.c            |  6 +--
 src/backend/parser/gram.y                          |  2 +-
 .../libpqwalreceiver/libpqwalreceiver.c            |  2 +-
 src/backend/tcop/utility.c                         |  5 +++
 src/bin/pg_dump/pg_dump.c                          |  7 +---
 src/test/regress/parallel_schedule                 |  2 +-
 12 files changed, 75 insertions(+), 80 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 51f062ef70..7b3e95bc9f 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -6216,19 +6216,18 @@ <title><structname>pg_subscription</structname></title>
   </indexterm>
 
   <para>
-   The <structname>pg_subscription</structname> catalog contains
-   all existing logical replication subscriptions.
+   The catalog <structname>pg_subscription</structname> contains all existing
+   logical replication subscriptions.
   </para>
 
   <para>
-   Unlike most system catalogs, <structname>pg_subscription</structname>
-   is shared across all databases of a cluster: there is only one
-   copy of <structname>pg_subscription</structname> per cluster, not
-   one per database.
+   Unlike most system catalogs, <structname>pg_subscription</structname> is
+   shared across all databases of a cluster: There is only one copy
+   of <structname>pg_subscription</structname> per cluster, not one per
+   database.
   </para>
 
   <table>
-
    <title><structname>pg_subscription</structname> Columns</title>
 
    <tgroup cols="4">
@@ -6252,16 +6251,15 @@ <title><structname>pg_subscription</structname> Columns</title>
      <row>
       <entry><structfield>subdbid</structfield></entry>
       <entry><type>oid</type></entry>
-      <entry></entry>
-      <entry>Oid of the database which the subscription resides in.</entry>
+      <entry><literal><link linkend="catalog-pg-database"><structname>pg_database</structname></link>.oid</literal></entry>
+      <entry>OID of the database which the subscription resides in</entry>
      </row>
 
      <row>
       <entry><structfield>subname</structfield></entry>
-      <entry><type>Name</type></entry>
+      <entry><type>name</type></entry>
       <entry></entry>
-      <entry>A unique, database-wide identifier for the replication
-      subscription.</entry>
+      <entry>Name of the subscription</entry>
      </row>
 
      <row>
@@ -6275,16 +6273,14 @@ <title><structname>pg_subscription</structname> Columns</title>
       <entry><structfield>subenabled</structfield></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
-      <entry>If true, the subscription is enabled and should be replicating.
-      </entry>
+      <entry>If true, the subscription is enabled and should be replicating.</entry>
      </row>
 
      <row>
       <entry><structfield>subconninfo</structfield></entry>
       <entry><type>text</type></entry>
       <entry></entry>
-      <entry>Connection string to the upstream database.
-      </entry>
+      <entry>Connection string to the upstream database</entry>
      </row>
 
      <row>
diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml
index 29e1a24a2f..a7cbdb85fa 100644
--- a/doc/src/sgml/ref/alter_subscription.sgml
+++ b/doc/src/sgml/ref/alter_subscription.sgml
@@ -39,8 +39,8 @@ <title>Description</title>
 
   <para>
    <command>ALTER SUBSCRIPTION</command> can change most of the subscription
-   attributes that can be specified in
-   <xref linkend="sql-createsubscription">.
+   properties that can be specified
+   in <xref linkend="sql-createsubscription">.
   </para>
  </refsect1>
 
@@ -52,26 +52,26 @@ <title>Parameters</title>
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
-      The name of a subscription whose attributes are to be altered.
+      The name of a subscription whose properties are to be altered.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term>CONNECTION '<replaceable class="parameter">conninfo</replaceable>'</term>
-    <term>SET PUBLICATION <replaceable class="parameter">publication_name</replaceable></term>
-    <term>SLOT NAME = <replaceable class="parameter">slot_name</replaceable></term>
+    <term><literal>CONNECTION '<replaceable class="parameter">conninfo</replaceable>'</literal></term>
+    <term><literal>SET PUBLICATION <replaceable class="parameter">publication_name</replaceable></literal></term>
+    <term><literal>SLOT NAME = <replaceable class="parameter">slot_name</replaceable></literal></term>
     <listitem>
      <para>
-      These clauses alter attributes originally set by
-      <xref linkend="SQL-CREATESUBSCRIPTION">. For more information, see the
-      <command>CREATE SUBSCRIPTION</command> reference page.
+      These clauses alter properties originally set by
+      <xref linkend="SQL-CREATESUBSCRIPTION">.  See there for more
+      information.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term>ENABLE</term>
+    <term><literal>ENABLE</literal></term>
     <listitem>
      <para>
       Enables the previously disabled subscription, starting the logical
@@ -81,7 +81,7 @@ <title>Parameters</title>
    </varlistentry>
 
    <varlistentry>
-    <term>DISABLE</term>
+    <term><literal>DISABLE</literal></term>
     <listitem>
      <para>
       Disables the running subscription, stopping the logical replication
@@ -89,7 +89,6 @@ <title>Parameters</title>
      </para>
     </listitem>
    </varlistentry>
-
   </variablelist>
  </refsect1>
 
@@ -110,7 +109,6 @@ <title>Examples</title>
 ALTER SUBSCRIPTION mysub DISABLE;
 </programlisting>
   </para>
-
  </refsect1>
 
  <refsect1>
@@ -132,5 +130,4 @@ <title>See Also</title>
    <member><xref linkend="sql-alterpublication"></member>
   </simplelist>
  </refsect1>
-
 </refentry>
diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml
index 3ae4cd89b6..a5cd0a16ff 100644
--- a/doc/src/sgml/ref/create_subscription.sgml
+++ b/doc/src/sgml/ref/create_subscription.sgml
@@ -16,7 +16,7 @@
 
  <refnamediv>
   <refname>CREATE SUBSCRIPTION</refname>
-  <refpurpose>define new subscription</refpurpose>
+  <refpurpose>define a new subscription</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
@@ -35,23 +35,21 @@
   <title>Description</title>
 
   <para>
-   <command>CREATE SUBSCRIPTION</command> adds a new subscription for
-   a current database. The subscription name must be distinct from
-   the name of any existing subscription in the database cluster.
+   <command>CREATE SUBSCRIPTION</command> adds a new subscription for a
+   current database.  The subscription name must be distinct from the name of
+   any existing subscription in the database.
   </para>
 
   <para>
-   The subscription represents a replication connection to the publisher.
-   As such this command does not only add definition in the local catalogs
-   but also creates a replication slot on the publisher.
+   The subscription represents a replication connection to the publisher.  As
+   such this command does not only add definitions in the local catalogs but
+   also creates a replication slot on the publisher.
   </para>
 
   <para>
-   A logical replication worker will be started to replicate data for the
-   new subscription at the commit of the transaction where this command
-   was run.
+   A logical replication worker will be started to replicate data for the new
+   subscription at the commit of the transaction where this command is run.
   </para>
-
  </refsect1>
 
  <refsect1>
@@ -68,7 +66,7 @@ <title>Parameters</title>
    </varlistentry>
 
    <varlistentry>
-    <term>CONNECTION '<replaceable class="parameter">conninfo</replaceable>'</term>
+    <term><literal>CONNECTION '<replaceable class="parameter">conninfo</replaceable>'</literal></term>
     <listitem>
      <para>
       The connection string to the publisher.
@@ -77,7 +75,7 @@ <title>Parameters</title>
    </varlistentry>
 
    <varlistentry>
-    <term>PUBLICATION <replaceable class="parameter">publication_name</replaceable></term>
+    <term><literal>PUBLICATION <replaceable class="parameter">publication_name</replaceable></literal></term>
     <listitem>
      <para>
       Name(s) of the publications on the publisher to subscribe to.
@@ -86,11 +84,11 @@ <title>Parameters</title>
    </varlistentry>
 
    <varlistentry>
-    <term>ENABLED</term>
-    <term>DISABLED</term>
+    <term><literal>ENABLED</literal></term>
+    <term><literal>DISABLED</literal></term>
     <listitem>
      <para>
-      Specifies if the subscription should be actively replicating or
+      Specifies whether the subscription should be actively replicating or
       if it should be just setup but not started yet.  Note that the
       replication slot as described above is created in either case.
       <literal>ENABLED</literal> is the default.
@@ -99,18 +97,18 @@ <title>Parameters</title>
    </varlistentry>
 
    <varlistentry>
-    <term>CREATE SLOT</term>
-    <term>NOCREATE SLOT</term>
+    <term><literal>CREATE SLOT</literal></term>
+    <term><literal>NOCREATE SLOT</literal></term>
     <listitem>
      <para>
-      Specifies if the command should create the replication slot on the
+      Specifies whether the command should create the replication slot on the
       publisher. <literal>CREATE SLOT</literal> is the default.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term>SLOT NAME = <replaceable class="parameter">slot_name</replaceable></term>
+    <term><literal>SLOT NAME = <replaceable class="parameter">slot_name</replaceable></literal></term>
     <listitem>
      <para>
       Name of the replication slot to use. The default behavior is to use
@@ -118,7 +116,6 @@ <title>Parameters</title>
      </para>
     </listitem>
    </varlistentry>
-
   </variablelist>
  </refsect1>
 
@@ -126,7 +123,7 @@ <title>Parameters</title>
   <title>Examples</title>
 
   <para>
-   Create a subscription to a different server which replicates tables in
+   Create a subscription to a remote server that replicates tables in
    the publications <literal>mypubclication</literal> and
    <literal>insert_only</literal> and starts replicating immediately on
    commit:
@@ -138,8 +135,8 @@ <title>Examples</title>
   </para>
 
   <para>
-   Create a subscription to a different server which replicates tables in
-   the <literal>insert_only</literal> publication and does not replicate
+   Create a subscription to a remote server that replicates tables in
+   the <literal>insert_only</literal> publication and does not start replicating
    until enabled at a later time.
 <programlisting>
 CREATE SUBSCRIPTION mysub
@@ -148,7 +145,6 @@ <title>Examples</title>
                WITH (DISABLED);
 </programlisting>
   </para>
-
  </refsect1>
 
  <refsect1>
@@ -170,5 +166,4 @@ <title>See Also</title>
    <member><xref linkend="sql-alterpublication"></member>
   </simplelist>
  </refsect1>
-
 </refentry>
diff --git a/doc/src/sgml/ref/drop_subscription.sgml b/doc/src/sgml/ref/drop_subscription.sgml
index de40a7660f..9f2fb93275 100644
--- a/doc/src/sgml/ref/drop_subscription.sgml
+++ b/doc/src/sgml/ref/drop_subscription.sgml
@@ -16,7 +16,7 @@
 
  <refnamediv>
   <refname>DROP SUBSCRIPTION</refname>
-  <refpurpose>remove an existing subscription</refpurpose>
+  <refpurpose>remove a subscription</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
@@ -29,8 +29,8 @@
   <title>Description</title>
 
   <para>
-   <command>DROP SUBSCRIPTION</command> removes subscriptions from the
-   cluster.
+   <command>DROP SUBSCRIPTION</command> removes a subscription from the
+   database cluster.
   </para>
 
   <para>
@@ -38,11 +38,9 @@ <title>Description</title>
   </para>
 
   <para>
-   The replication worker associated with the subscription will not stop
-   until after <command>COMMIT</command> of the transaction which issued
-   this command.
+   The replication worker associated with the subscription will not stop until
+   after the transaction that issued this command has committed.
   </para>
-
  </refsect1>
 
  <refsect1>
@@ -63,9 +61,17 @@ <title>Parameters</title>
     <term><replaceable class="parameter">NODROP SLOT</replaceable></term>
     <listitem>
      <para>
-      Specifies if to drop slot on the publisher. The default is
+      Specifies whether to drop the replication slot on the publisher.  The
+      default is
       <literal>DROP SLOT</literal>.
      </para>
+
+     <para>
+      If the publisher is not reachable when the subscription is to be
+      dropped, then it is useful to specify <literal>NODROP SLOT</literal>.
+      But the replication slot on the publisher will then have to be removed
+      manually.
+     </para>
     </listitem>
    </varlistentry>
 
@@ -101,5 +107,4 @@ <title>See Also</title>
    <member><xref linkend="sql-altersubscription"></member>
   </simplelist>
  </refsect1>
-
 </refentry>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 48ff9b95dc..640fe12bbf 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1618,12 +1618,12 @@ <title>Meta-Commands</title>
         <term><literal>\dRs[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
         <listitem>
         <para>
-        List replication subscriptions.
+        Lists replication subscriptions.
         If <replaceable class="parameter">pattern</replaceable> is
-        specified, only subscriptions whose names match the pattern are
+        specified, only those subscriptions whose names match the pattern are
         listed.
         If <literal>+</literal> is appended to the command name, additional
-        parameters of the subscriptions are shown.
+        properties of the subscriptions are shown.
         </para>
         </listitem>
       </varlistentry>
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index d5078fca2d..fe94779ef2 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -3,7 +3,7 @@
  * pg_subscription.c
  *		replication subscriptions
  *
- * Copyright (c) 2015, PostgreSQL Global Development Group
+ * Copyright (c) 2016, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
  *		src/backend/catalog/pg_subscription.c
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 1b8d589d1b..5a7312c0c4 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -57,7 +57,7 @@
  * Common option parsing function for CREATE and ALTER SUBSCRIPTION commands.
  *
  * Since not all options can be specified in both commands, this function
- * will report error on options if the target output pointer is NULL to
+ * will report an error on options if the target output pointer is NULL to
  * accomodate that.
  */
 static void
@@ -160,7 +160,7 @@ parse_subscription_options(List *options, char **conninfo,
 }
 
 /*
- * Auxiliary function to return a TEXT array out of a list of String nodes.
+ * Auxiliary function to return a text array out of a list of String nodes.
  */
 static Datum
 publicationListToArray(List *publist)
@@ -309,7 +309,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt)
 		if (server_version / 100 > PG_VERSION_NUM / 100)
 			ereport(WARNING,
 					(errmsg("publisher major version %d is higher than subscriber "
-							"major version %d,  the logical replicatiion might "
+							"major version %d, logical replication might "
 							"not work correctly",
 							server_version/10000, PG_VERSION_NUM/10000)));
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5baf580af9..95f68b6a3e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -9019,7 +9019,7 @@ AlterPublicationStmt:
 
 /*****************************************************************************
  *
- * CREATE SUBSCRIPTION name [ WITH ] options
+ * CREATE SUBSCRIPTION name ...
  *
  *****************************************************************************/
 
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 41a0ac1275..f99158e251 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -104,7 +104,7 @@ _PG_init(void)
 /*
  * Establish the connection to the primary server for XLOG streaming
  *
- * Return NULL on error and fills the err with palloced error message.
+ * Returns NULL on error and fills the err with palloc'ed error message.
  */
 static WalReceiverConn *
 libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index ce98420ff0..2273405426 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -216,6 +216,7 @@ check_xact_readonly(Node *parsetree)
 		case T_AlterPublicationStmt:
 		case T_CreateSubscriptionStmt:
 		case T_AlterSubscriptionStmt:
+		case T_DropSubscriptionStmt:
 			PreventCommandIfReadOnly(CreateCommandTag(parsetree));
 			PreventCommandIfParallelMode(CreateCommandTag(parsetree));
 			break;
@@ -3211,6 +3212,10 @@ GetCommandLogLevel(Node *parsetree)
 			lev = LOGSTMT_DDL;
 			break;
 
+		case T_DropSubscriptionStmt:
+			lev = LOGSTMT_DDL;
+			break;
+
 			/* already-planned queries */
 		case T_PlannedStmt:
 			{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e20e5e423a..4968c27ded 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -919,7 +919,7 @@ help(const char *progname)
 	printf(_("  --no-security-labels         do not dump security label assignments\n"));
 	printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
 	printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
-	printf(_("  --no-create-subsription-slot do not create replication slot for dumped subscriptions\n"));
+	printf(_("  --no-create-subscription-slot do not create replication slot for dumped subscriptions\n"));
 	printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
 	printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
 	printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
@@ -3600,9 +3600,6 @@ getSubscriptions(Archive *fout)
 
 	query = createPQExpBuffer();
 
-	if (g_verbose)
-		write_msg(NULL, "reading subscriptions\n");
-
 	resetPQExpBuffer(query);
 
 	/* Get the subscriptions in current database. */
@@ -3621,7 +3618,7 @@ getSubscriptions(Archive *fout)
 	if (ntups == 0)
 	{
 		/*
-		 * There are no publications defined. Clean up and return.
+		 * There are no subscriptions defined. Clean up and return.
 		 */
 		PQclear(res);
 		return;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 0de902eb7a..e9b2bad6fd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -97,7 +97,7 @@ test: rules psql_crosstab amutils
 # run by itself so it can run parallel workers
 test: select_parallel
 
-# no relation related tests can be put in thi group
+# no relation related tests can be put in this group
 test: publication subscription
 
 # ----------
-- 
2.11.0

From 00b5c7896ffce14ca62f92670b485ba2e9ccba61 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Mon, 12 Dec 2016 12:00:00 -0500
Subject: [PATCH 6/8] fixup! Define logical replication protocol and output
 plugin

---
 doc/src/sgml/protocol.sgml              | 92 ++++++++++++++-------------------
 src/backend/replication/logical/proto.c | 12 ++---
 src/include/replication/pgoutput.h      |  2 +-
 3 files changed, 43 insertions(+), 63 deletions(-)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 4026687220..368d86c126 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2126,7 +2126,7 @@ <title>Streaming Replication Protocol</title>
  <title>Logical Streaming Replication Protocol</title>
 
  <para>
-  This section describes the logical replication protocol which is the message
+  This section describes the logical replication protocol, which is the message
   flow started by the <literal>START_REPLICATION</literal>
   <literal>SLOT</literal> <replaceable class="parameter">slot_name</>
   <literal>LOGICAL</literal> replication command.
@@ -2134,14 +2134,14 @@ <title>Logical Streaming Replication Protocol</title>
 
  <para>
   The logical streaming replication protocol builds on the primitives of
-  physical streaming replication protocol.
+  the physical streaming replication protocol.
  </para>
 
  <sect2 id="protocol-logical-replication-params">
   <title>Logical Streaming Replication Parameters</title>
 
   <para>
-   The logical replication  <literal>START_REPLICATION</literal> command
+   The logical replication <literal>START_REPLICATION</literal> command
    accepts following parameters:
 
    <variablelist>
@@ -2164,7 +2164,7 @@ <title>Logical Streaming Replication Parameters</title>
      <listitem>
       <para>
        Comma separated list of publication names for which to subscribe
-       (receive changes). The invidividual publication names are treated
+       (receive changes). The individual publication names are treated
        as standard objects names and can be quoted the same as needed.
       </para>
      </listitem>
@@ -2179,7 +2179,7 @@ <title>Logical Replication Protocol Messages</title>
 
   <para>
    The individual protocol messages are discussed in the following
-   sub-sections. Individual messages are describer in
+   subsections. Individual messages are describer in
    <xref linkend="protocol-logicalrep-message-formats"> section.
   </para>
 
@@ -2208,36 +2208,31 @@ <title>Logical Replication Protocol Message Flow</title>
 
   <para>
    The logical replication protocol sends individual transactions one by one.
-   This means that all messages between two Begin and Commit messages all
+   This means that all messages between a pair of Begin and Commit messages
    belong to the same transaction.
   </para>
 
   <para>
    Every sent transaction contains zero or more DML messages (Insert,
-   Update, Delete) and in case of cascaded setup it can also contain Origin
+   Update, Delete). In case of a cascaded setup it can also contain Origin
    messages. The origin message indicated that the transaction originated on
-   different replication node. Since replication node in the scope of logical
+   different replication node. Since a replication node in the scope of logical
    replication protocol can be pretty much anything, the only identifier
-   is the origin name. It's downstream responsibility to handle this as
+   is the origin name. It's downstream's responsibility to handle this as
    needed (if needed). The Origin message is always sent before any DML
    messages in the transaction.
   </para>
 
   <para>
-   Every DML message contains arbitrary relation id, which can be mapped to
-   an id in the Relation messages. The Relation describe the schema of the
+   Every DML message contains an arbitrary relation ID, which can be mapped to
+   an ID in the Relation messages. The Relation messages describe the schema of the
    given relation. The Relation message is sent for a given relation either
-   because it's the first time we send DML message for given relation in
+   because it is the first time we send a DML message for given relation in the
    current session or because the relation definition has changed since the
    last Relation message was sent for it. The protocol assumes that the client
    is capable of caching the metadata for as many relations as needed.
   </para>
-
-  <para>
-  </para>
-
  </sect2>
-
 </sect1>
 
 <sect1 id="protocol-message-types">
@@ -5272,10 +5267,10 @@ <title>Logical Replication Message Formats</title>
 
 <para>
 This section describes the detailed format of each logical replication message.
-These messages are returned either by replication slot SQL interface or by
-WalSender. In case of WalSender they are encapsulated inside the replication
+These messages are returned either by the replication slot SQL interface or are
+sent by a walsender. In case of a walsender they are encapsulated inside the replication
 protocol WAL messages as described in <xref linkend="protocol-replication">
-section and generaly obey same message flow as physical replication.
+and generally obey same message flow as physical replication.
 </para>
 
 <variablelist>
@@ -5420,17 +5415,6 @@ <title>Logical Replication Message Formats</title>
 </varlistentry>
 <varlistentry>
 <term>
-        Int8
-</term>
-<listitem>
-<para>
-                Length of the origin name (including the NULL-termination
-                character).
-</para>
-</listitem>
-</varlistentry>
-<varlistentry>
-<term>
         String
 </term>
 <listitem>
@@ -5444,7 +5428,7 @@ <title>Logical Replication Message Formats</title>
 </para>
 
 <para>
-  Note that there can be mutiple Origin messages inside single transaction.
+  Note that there can be multiple Origin messages inside a single transaction.
 </para>
 
 </listitem>
@@ -5464,7 +5448,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Identifies the message as an relation message.
+                Identifies the message as a relation message.
 </para>
 </listitem>
 </varlistentry>
@@ -5474,7 +5458,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Id of the relation.
+                ID of the relation.
 </para>
 </listitem>
 </varlistentry>
@@ -5484,7 +5468,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Namespace (empty string for pg_catalog).
+                Namespace (empty string for <literal>pg_catalog</literal>).
 </para>
 </listitem>
 </varlistentry>
@@ -5506,7 +5490,7 @@ <title>Logical Replication Message Formats</title>
 <listitem>
 <para>
                 Replica identity setting for the relation (same as
-                relreplident in pg_class).
+                <structfield>relreplident</structfield> in <structname>pg_class</structname>).
 </para>
 </listitem>
 </varlistentry>
@@ -5575,7 +5559,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Id of the relation corresponding to the id in the relation
+                ID of the relation corresponding to the ID in the relation
                 message.
 </para>
 </listitem>
@@ -5593,11 +5577,11 @@ <title>Logical Replication Message Formats</title>
 
 <varlistentry>
 <term>
-        TableData
+        TupleData
 </term>
 <listitem>
 <para>
-                TableData message part representing the contents of new tuple.
+                TupleData message part representing the contents of new tuple.
 </para>
 </listitem>
 </varlistentry>
@@ -5631,7 +5615,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Id of the relation corresponding to the id in the relation
+                ID of the relation corresponding to the ID in the relation
                 message.
 </para>
 </listitem>
@@ -5643,9 +5627,9 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Identifies the following TupleData sub message as a key.
-                This field is optional and is only present if table in which
-                the update changed the REPLICA IDENTITY index.
+                Identifies the following TupleData submessage as a key.
+                This field is optional and is only present if
+                the update changed the REPLICA IDENTITY index. XXX???
 </para>
 </listitem>
 </varlistentry>
@@ -5656,7 +5640,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Identifies the following TupleData message as a old tuple.
+                Identifies the following TupleData submessage as an old tuple.
                 This field is optional and is only present if table in which
                 the update happened has REPLICA IDENTITY set to FULL.
 </para>
@@ -5665,11 +5649,11 @@ <title>Logical Replication Message Formats</title>
 
 <varlistentry>
 <term>
-        TableData
+        TupleData
 </term>
 <listitem>
 <para>
-                TableData message part representing the contents of old tuple
+                TupleData message part representing the contents of the old tuple
                 or primary key. Only present if the previous 'O' or 'K' part
                 is present.
 </para>
@@ -5689,11 +5673,11 @@ <title>Logical Replication Message Formats</title>
 
 <varlistentry>
 <term>
-        TableData
+        TupleData
 </term>
 <listitem>
 <para>
-                TableData message part representing the contents of a new tuple.
+                TupleData message part representing the contents of a new tuple.
 </para>
 </listitem>
 </varlistentry>
@@ -5702,7 +5686,7 @@ <title>Logical Replication Message Formats</title>
 </para>
 
 <para>
-    The Update message may contain either 'K' message part or 'O' message part
+    The Update message may contain either a 'K' message part or an 'O' message part
     or neither of them, but never both of them.
 </para>
 
@@ -5733,7 +5717,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Id of the relation corresponding to the id in the relation
+                ID of the relation corresponding to the ID in the relation
                 message.
 </para>
 </listitem>
@@ -5745,7 +5729,7 @@ <title>Logical Replication Message Formats</title>
 </term>
 <listitem>
 <para>
-                Identifies the following TupleData sub message as a key.
+                Identifies the following TupleData submessage as a key.
                 This field is present if the table in which the delete has
                 happened uses an index as REPLICA IDENTITY.
 </para>
@@ -5767,11 +5751,11 @@ <title>Logical Replication Message Formats</title>
 
 <varlistentry>
 <term>
-        TableData
+        TupleData
 </term>
 <listitem>
 <para>
-                TableData message part representing the contents of old tuple
+                TupleData message part representing the contents of the old tuple
                 or primary key, depending on the previous field.
 </para>
 </listitem>
@@ -5780,7 +5764,7 @@ <title>Logical Replication Message Formats</title>
 </para>
 
 <para>
-    The Delete message may contain either 'K' message part or 'O' message,
+    The Delete message may contain either a 'K' message part or an 'O' message part,
     but never both of them.
 </para>
 
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index 56790c859e..9a2a168b40 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -200,7 +200,6 @@ logicalrep_write_origin(StringInfo out, const char *origin,
 	pq_sendstring(out, origin);
 }
 
-
 /*
  * Read ORIGIN from the output stream.
  */
@@ -214,7 +213,6 @@ logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn)
 	return pstrdup(pq_getmsgstring(in));
 }
 
-
 /*
  * Write INSERT to the output stream.
  */
@@ -487,7 +485,7 @@ logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple)
 	}
 	pq_sendint(out, nliveatts, 2);
 
-	/* try to allocate enough memory from the get go */
+	/* try to allocate enough memory from the get-go */
 	enlargeStringInfo(out, tuple->t_len +
 					  nliveatts * (1 + 4));
 
@@ -499,7 +497,7 @@ logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple)
 		HeapTuple	typtup;
 		Form_pg_type typclass;
 		Form_pg_attribute att = desc->attrs[i];
-		char   	   *outputstr;
+		char	   *outputstr;
 		int			len;
 
 		/* skip dropped columns */
@@ -584,9 +582,8 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	}
 }
 
-
 /*
- * Write relation attributes to the outputstream.
+ * Write relation attributes to the stream.
  */
 static void
 logicalrep_write_attrs(StringInfo out, Relation rel)
@@ -644,9 +641,8 @@ logicalrep_write_attrs(StringInfo out, Relation rel)
 	bms_free(idattrs);
 }
 
-
 /*
- * Read relation attribute names from the outputstream.
+ * Read relation attribute names from the stream.
  */
 static void
 logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel)
diff --git a/src/include/replication/pgoutput.h b/src/include/replication/pgoutput.h
index 7083cd7e76..c20451d1f2 100644
--- a/src/include/replication/pgoutput.h
+++ b/src/include/replication/pgoutput.h
@@ -16,7 +16,7 @@
 
 typedef struct PGOutputData
 {
-	MemoryContext	context;			/* pricate memory context for transient
+	MemoryContext	context;			/* private memory context for transient
 										 * allocations */
 
 	/* client info */
-- 
2.11.0

From cdc02919f9d1b2c2d1c5cdf7eb15e1c9a0b38f09 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Mon, 12 Dec 2016 12:00:00 -0500
Subject: [PATCH 8/8] fixup! Add logical replication workers

---
 doc/src/sgml/logical-replication.sgml      | 136 ++++++++++++++---------------
 doc/src/sgml/monitoring.sgml               |  10 +--
 doc/src/sgml/ref/create_publication.sgml   |   2 +-
 src/backend/catalog/system_views.sql       |  16 ++--
 src/backend/executor/execReplication.c     |  28 +++---
 src/backend/postmaster/postmaster.c        |   6 +-
 src/backend/replication/logical/apply.c    |   4 +-
 src/backend/replication/logical/launcher.c |  13 ++-
 src/include/catalog/pg_subscription.h      |   9 +-
 9 files changed, 109 insertions(+), 115 deletions(-)

diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index bf5966e5ac..6603533ba6 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -6,7 +6,7 @@ <title>Logical Replication</title>
   <para>
     Logical replication is a method of replicating data objects and their
     changes, based upon their replication identity (usually a primary key).
-    We use the term logical in contrast to physical replication which
+    We use the term logical in contrast to physical replication, which
     uses exact block addresses and byte-by-byte replication.
     PostgreSQL supports both mechanisms concurrently, see
     <xref linkend="high-availability">. Logical replication allows
@@ -37,7 +37,7 @@ <title>Logical Replication</title>
     <listitem>
       <para>
         Sending incremental changes in a single database or a subset of
-        a database to Subscribers as they occur.
+        a database to subscribers as they occur.
       </para>
     </listitem>
     <listitem>
@@ -54,7 +54,7 @@ <title>Logical Replication</title>
     </listitem>
     <listitem>
       <para>
-        Replicating between different major versions of PostgreSQL
+        Replicating between different major versions of PostgreSQL.
       </para>
     </listitem>
     <listitem>
@@ -74,7 +74,7 @@ <title>Logical Replication</title>
     PostgreSQL instance and can be used as a publisher for other
     databases by defining its own publications. When the subscriber is
     treated as read-only by application, there will be no conflicts from
-    a single subscription. On the other hand if there are other writes
+    a single subscription. On the other hand, if there are other writes
     done either by application or other subscribers to the same set of
     tables conflicts can arise.
   </para>
@@ -84,14 +84,13 @@ <title>Publication</title>
   <para>
     A <firstterm>publication</> object can be defined on any physical
     replication master. The node where a publication is defined is referred
-    to as <firstterm>publisher</>. Only superusers or members of the
-    <literal>REPLICATION</> role can define a publication. A publication is
+    to as <firstterm>publisher</>. A publication is
     a set of changes generated from a group of tables, and might also be
     described as a <firstterm>change set</> or <firstterm>replication set</>.
     Each publication exists in only one database.
   </para>
   <para>
-    Publications are different from table schema and do not affect
+    Publications are different from schemas and do not affect
     how the table is accessed. Each table can be added to multiple
     publications if needed.  Publications may currently only contain
     tables. Objects must be added explicitly, except when a publication
@@ -99,38 +98,35 @@ <title>Publication</title>
   </para>
   <para>
     Publications can choose to limit the changes they produce to show
-    any combination of <command>INSERT</>, <command>UPDATE</> and
+    any combination of <command>INSERT</>, <command>UPDATE</>, and
     <command>DELETE</> in a similar way to the way triggers are fired by
-    particular event types. If a table with without a
-    <literal>REPLICA IDENTITY</> is added to a publication which replicates
+    particular event types. If a table without a
+    <literal>REPLICA IDENTITY</> is added to a publication that replicates
     <command>UPDATE</> or <command>DELETE</> operations then subsequent
     <command>UPDATE</> or <command>DELETE</> operations will fail on the
     publisher.
    </para>
   <para>
-    The definition of a publication object will be included within
-    pg_dump.
-  </para>
-  <para>
     Every publication can have multiple subscribers.
   </para>
   <para>
-    Publication is created using the <xref linkend="sql-createpublication">
+    A publication is created using the <xref linkend="sql-createpublication">
     command and may be later altered or dropped using corresponding commands.
   </para>
   <para>
     The individual tables can be added and removed dynamically using
     <xref linkend="sql-alterpublication">. Both the <literal>ADD TABLE</>
-    and <literal>DROP TABLE</> operations are transactional so the table
+    and <literal>DROP TABLE</> operations are transactional; so the table
     will start or stop replicating at the correct snapshot once the
     transaction has committed.
   </para>
 </sect1>
+
 <sect1 id="logical-replication-subscription">
   <title>Subscription</title>
   <para>
     A <firstterm>subscription</> is the downstream side of logical
-    replication. The node where subscription is defined is referred to as
+    replication. The node where a subscription is defined is referred to as
     the <firstterm>subscriber</>. Subscription defines the connection to
     another database and set of publications (one or more) to which it
     wants to be subscribed.
@@ -141,7 +137,7 @@ <title>Subscription</title>
     databases by defining its own publications.
   </para>
   <para>
-    A subscriber may have multiple subscriptions if desired. It is
+    A subscriber node may have multiple subscriptions if desired. It is
     possible to define multiple subscriptions between a single
     publisher-subscriber pair, in which case extra care must be taken
     to ensure that the subscribed publication objects don't overlap.
@@ -153,32 +149,33 @@ <title>Subscription</title>
     of pre-existing table data.
   </para>
   <para>
-    Subscriptions are not dumped by pg_dump by default but can be
-    requested using the --subscriptions parameter.
+    Subscriptions are not dumped by <command>pg_dump</command> by default but can be
+    requested using the command-line option <option>--subscriptions</option>.
   </para>
   <para>
     The subscription is added using <xref linkend="sql-createsubscription">
     and can be stopped/resumed at any time using the
-    <xref linkend="sql-altersubscription"> command or removed using
+    <xref linkend="sql-altersubscription"> command and removed using
     <xref linkend="sql-dropsubscription">.
   </para>
   <para>
-    When subscription is dropped and recreated, the synchronization
+    When a subscription is dropped and recreated, the synchronization
     information is lost. This means that the data has to be
     resynchronized afterwards.
   </para>
   <para>
     The schema definitions are not replicated and the published tables
     must exist on the subsriber for replication to work. Only regular
-    tables may be the target of replication (ie, you can't replicate
+    tables may be the target of replication (i.e., you can't replicate
     to a view).
   </para>
   <para>
-    The tables are matched using fully qualified table name. Replication
-    to differently named tables on subscriber is not supported.
+    The tables are matched between the publisher and the subscriber using
+    the fully qualified table name. Replication
+    to differently-named tables on the subscriber is not supported.
   </para>
   <para>
-    Columns of a table are also matched by name. The different order of
+    Columns of a table are also matched by name. A different order of
     columns in the target table is allowed, but the column types have to
     match.
   </para>
@@ -197,11 +194,11 @@ <title>Conflicts</title>
   <para>
     A conflict will produce an error and will stop the replication; it
     must be resolved manually by the user. Details about the conflict can
-    be found in the subscribers PostgreSQL log.
+    be found in the subscriber's server log.
   </para>
   <para>
     The resolution can be done either by changing data on the subscriber
-    so that it does not conflict with incoming change or by skipping the
+    so that it does not conflict with the incoming change or by skipping the
     transaction that conflicts with the existing data. The transaction
     can be skipped by calling the
     <link linkend="pg-replication-origin-advance">
@@ -217,42 +214,42 @@ <title>Architecture</title>
   <para>
     Logical replication starts by copying a snapshot of the data on
     the publisher database. Once that is done, changes on the publisher
-    are sent to the subscriber as they occur in real-time. The subscriber
+    are sent to the subscriber as they occur in real time. The subscriber
     applies data in the order in which commits were made on the
     publisher so that transactional consistency is guaranteed for the
-    publications within any single Subscription.
+    publications within any single subscription.
   </para>
   <para>
     Logical replication is built with an architecture similar to
     physical streaming replication
     (see <xref linkend="streaming-replication">). It is implemented by
-    WalSender and the Apply processes. The WalSender starts logical
+    <quote>walsender</quote> and the <quote>apply</quote> processes. The walsender starts logical
     decoding (described in <xref linkend="logicaldecoding">) of the WAL and
     loads the standard logical decoding plugin (pgoutput). The plugin
     transforms the changes read from WAL to the logical replication protocol
     (see <xref linkend="protocol-logical-replication">) and filters the data
-    according to publication specification. The data is then continuously
-    transferred using the streaming replication protocol to the Apply worker
+    according to the publication specification. The data is then continuously
+    transferred using the streaming replication protocol to the apply worker,
     which maps the data to local tables and applies the individual changes as
     they are received in exact transactional order.
   </para>
   <para>
-    The Apply process on the subscriber database always runs with
-    session_replication_role set to replica, which produces the usual effects
+    The apply process on the subscriber database always runs with
+    <varname>session_replication_role</varname> set to <literal>replica</literal>, which produces the usual effects
     on triggers and constraints.
   </para>
   <sect2 id="logical-replication-snapshot">
-    <title>Initial snapshot</title>
+    <title>Initial Snapshot</title>
     <para>
       The initial data in existing subscribed tables are snapshotted and
-      copied in a parallel instance of a special kind of Apply process.
+      copied in a parallel instance of a special kind of apply process.
       This process will create its own temporary replication slot and
       copy the existing data. Once existing data is copied, the worker
-      enters synchronization mode which ensures that the table is brought
-      up to synchronized state with the main Apply process by streaming
-      any changes which happened during the initial data copy using standard
+      enters synchronization mode, which ensures that the table is brought
+      up to a synchronized state with the main apply process by streaming
+      any changes that happened during the initial data copy using standard
       logical replication. Once the synchronization is done, the control
-      of the replication of the table is given back to the main Apply
+      of the replication of the table is given back to the main apply
       process where the replication continues as normal.
     </para>
   </sect2>
@@ -262,81 +259,82 @@ <title>Monitoring</title>
   <para>
     Because logical replication is based on similar architecture as
     <link linkend="streaming-replication">physical streaming
-    replication</link> the monitoring on publication is very similar to
+    replication</link> the monitoring on a publication node is very similar to
     monitoring of physical replication master (see
     <xref linkend="streaming-replication-monitoring">).
   </para>
   <para>
     The monitoring information about subscription is visible in
     <link linkend="pg-stat-subscription"><literal>pg_stat_subscription</></link>.
-    This view contains one row for every subscription worker. Subscription
+    This view contains one row for every subscription worker. A subscription
     can have zero or more active subscription workers depending on its state.
   </para>
   <para>
-    Normally there is a single Apply process running for the enabled
-    subscription. The disabled subscription of crashed subscription will
+    Normally, there is a single apply process running for an enabled
+    subscription. A disabled subscription or a crashed subscription will
     have zero rows in this view. If the initial data synchronization of
-    any table is in progress there will be additional worker(s) for the
-    table(s) being synchronized.
+    any table is in progress there will be additional workers for the
+    tables being synchronized.
   </para>
 </sect1>
 <sect1 id="logical-replication-security">
   <title>Security</title>
   <para>
-    Replication connection can occur in the same way as physical streaming
+    Logical replication connections occur in the same way as physical streaming
     replication. It requires access to be specifically given using
-    pg_hba.conf. The role used for the replication must have
-    <literal>REPLICATION</literal> privilege <command>GRANT</command>ED.
+    <filename>pg_hba.conf</filename>. The role used for the replication connection must have
+    the <literal>REPLICATION</literal> attribute.
     This gives a role access to both logical and physical replication.
   </para>
   <para>
-    To create a publication the user must have the REPLICATION role, or be
-    a superuser.
+    To create a publication, the user must have the <literal>CREATE</literal>
+    privilege in the database.
   </para>
   <para>
-    To create a subscription the user must be a superuser.
+    To create a subscription, the user must be a superuser.
   </para>
   <para>
     The subscription apply process will run in the local database
     with the privileges of a superuser.
   </para>
   <para>
-    In particular, note that privileges are not re-checked as each change
+    Privileges are only checked once at the start of a replication connection.
+    They are not re-checked as each change
     record is read from the publisher, nor are they re-checked for each change
-    when applied. Security is checked once at startup.
+    when applied.
   </para>
 </sect1>
 <sect1 id="logical-replication-gucs">
   <title>Logical replication related configuration parameters</title>
   <para>
-    The Logical Replication requires several configuration options to be
+    Logical replication requires several configuration options to be
     set.
   </para>
   <para>
-    On the publisher side the <varname>wal_level</> must be set to
+    On the publisher side, <varname>wal_level</> must be set to
     <literal>logical</>, and <varname>max_replication_slots</> has to be set to
-    at least the number of Subscriptions expected to connect with some reserve
-    for table synchronization as well. And <varname>max_wal_senders</>
+    at least the number of subscriptions expected to connect with some reserve
+    for table synchronization. And <varname>max_wal_senders</>
     should be set to at least the same as <varname>max_replication_slots</> plus
     the number of physical replicas that are connected at the same time.
   </para>
   <para>
-    The Subscriber also requires the <varname>max_replication_slots</> to
+    The subscriber also requires the <varname>max_replication_slots</> to
     be set. In this case it should be set to at least the number of
-    Subscriptions that will be added to the Subscriber. The
+    subscriptions that will be added to the subscriber.
     <varname>max_logical_replication_workers</> has to be set to at least
-    the number of Subscriptions again with some reserve for the table
+    the number of subscriptions, again with some reserve for the table
     synchronization. Additionally the <varname>max_worker_processes</> may
     need to be adjusted to accommodate for replication workers, at least
-    (<varname>max_logical_replication_workers</> + <literal>1</>). Please
-    note that some extensions and parallel queries also take worker slots
+    (<varname>max_logical_replication_workers</> + <literal>1</>).
+    Note that some extensions and parallel queries also take worker slots
     from <varname>max_worker_processes</>.
   </para>
 </sect1>
 <sect1 id="logical-replication-quick-setup">
   <title>Quick setup</title>
   <para>
-    First set the configuration options in the postgresql.conf:
+    First set the configuration options in <filename>postgresql.conf</filename>:
 <programlisting>
 wal_level = logical
 max_worker_processes = 10 # one per subscription + one per instance needed on subscriber
@@ -346,7 +344,7 @@ <title>Quick setup</title>
 </programlisting>
   </para>
   <para>
-    The pg_hba.conf needs to be adjusted to allow replication (the
+    <filename>pg_hba.conf</filename> needs to be adjusted to allow replication (the
     values here depend on your actual network configuration and user you
     want to use for connecting):
 <programlisting>
@@ -360,13 +358,13 @@ <title>Quick setup</title>
 </programlisting>
   </para>
   <para>
-    And on the Subscriber database:
+    And on the subscriber database:
 <programlisting>
-CREATE SUBSCRIPTION mysub WITH CONNECTION 'dbname=foo host=bar user=repuser' PUBLICATION mypub;
+CREATE SUBSCRIPTION mysub CONNECTION 'dbname=foo host=bar user=repuser' PUBLICATION mypub;
 </programlisting>
   </para>
   <para>
-    The above will start the replication process which synchronizes the
+    The above will start the replication process, which synchronizes the
     initial table contents of <literal>users</literal> and
     <literal>departments</literal> tables and then starts replicating
     incremental changes to those tables.
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4d04330776..5c61ac785e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -310,7 +310,7 @@ <title>Dynamic Statistics Views</title>
 
      <row>
       <entry><structname>pg_stat_subscription</><indexterm><primary>pg_stat_subscription</primary></indexterm></entry>
-      <entry>At least one row per subscription, showing statistics about
+      <entry>At least one row per subscription, showing information about
        the subscription workers.
        See <xref linkend="pg-stat-subscription"> for details.
       </entry>
@@ -1564,8 +1564,8 @@ <title><structname>pg_stat_subscription</structname> View</title>
    <tbody>
     <row>
      <entry><structfield>subid</></entry>
-     <entry><type>Oid</></entry>
-     <entry>Oid of the subscription</entry>
+     <entry><type>oid</></entry>
+     <entry>OID of the subscription</entry>
     </row>
     <row>
      <entry><structfield>subname</></entry>
@@ -1612,8 +1612,8 @@ <title><structname>pg_stat_subscription</structname> View</title>
 
   <para>
    The <structname>pg_stat_subscription</structname> view will contain one
-   row per subscription for main worker (with NULL pid if the worker is
-   not running) and then additional rows for workers handling initial data
+   row per subscription for main worker (with null PID if the worker is
+   not running), and additional rows for workers handling the initial data
    copy of the subscribed tables.
   </para>
 
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 2a0da598f3..995f2bcf3c 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -47,7 +47,7 @@ <title>Description</title>
    A publication is essentially a group of tables whose data changes are
    intended to be replicated through logical replication.  See
    <xref linkend="logical-replication-publication"> for details about how
-   publications fit into logical replication setup.
+   publications fit into the logical replication setup.
    </para>
  </refsect1>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index acfeeee27a..ff1ac75a90 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -719,14 +719,14 @@ CREATE VIEW pg_stat_wal_receiver AS
 
 CREATE VIEW pg_stat_subscription AS
     SELECT
-			su.oid as subid,
-			su.subname,
-			st.pid,
-			st.received_lsn,
-			st.last_msg_send_time,
-			st.last_msg_receipt_time,
-			st.latest_end_lsn,
-			st.latest_end_time
+            su.oid AS subid,
+            su.subname,
+            st.pid,
+            st.received_lsn,
+            st.last_msg_send_time,
+            st.last_msg_receipt_time,
+            st.latest_end_lsn,
+            st.latest_end_time
     FROM pg_subscription su
             LEFT JOIN pg_stat_get_subscription(NULL) st
                       ON (st.subid = su.oid);
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 44248a49f1..897118f52a 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -72,8 +72,8 @@ build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel,
 		Oid			optype = get_opclass_input_type(opclass->values[attoff]);
 
 		/*
-		 * Load the operator info, we need this to get the equality operator
-		 * function for the scankey.
+		 * Load the operator info.  We need this to get the equality operator
+		 * function for the scan key.
 		 */
 		opfamily = get_opclass_family(opclass->values[attoff]);
 
@@ -109,8 +109,8 @@ build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel,
 /*
  * Search the relation 'rel' for tuple using the index.
  *
- * If a matching tuple is found lock it with lockmode, fill the slot with its
- * contents and return true, return false is returned otherwise.
+ * If a matching tuple is found, lock it with lockmode, fill the slot with its
+ * contents, and return true.  Return false otherwise.
  */
 bool
 RelationFindReplTupleByIndex(Relation rel, Oid idxoid,
@@ -258,8 +258,8 @@ tuple_equals_slot(TupleDesc	desc, HeapTuple tup, TupleTableSlot *slot)
 /*
  * Search the relation 'rel' for tuple using the sequential scan.
  *
- * If a matching tuple is found lock it with lockmode, fill the slot with its
- * contents and return true, return false is returned otherwise.
+ * If a matching tuple is found, lock it with lockmode, fill the slot with its
+ * contents, and return true.  Return false otherwise.
  *
  * Note that this stops on the first matching tuple.
  *
@@ -357,10 +357,10 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
 }
 
 /*
- * Insert tuple represented in the slot to the relation, update the indexes
- * and execute any constraints and per row triggers.
+ * Insert tuple represented in the slot to the relation, update the indexes,
+ * and execute any constraints and per-row triggers.
  *
- * Caller is repsonsible for opening the indexes.
+ * Caller is responsible for opening the indexes.
  */
 void
 ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
@@ -412,12 +412,11 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
 	}
 }
 
-
 /*
  * Find the searchslot tuple and update it with data in the slot,
- * update the indexes and execute any constraints and per row triggers.
+ * update the indexes, and execute any constraints and per-row triggers.
  *
- * Caller is repsonsible for opening the indexes.
+ * Caller is responsible for opening the indexes.
  */
 void
 ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
@@ -475,12 +474,11 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
 	}
 }
 
-
 /*
  * Find the searchslot tuple and delete it, and execute any constraints
- * and per row triggers.
+ * and per-row triggers.
  *
- * Caller is repsonsible for opening the indexes.
+ * Caller is responsible for opening the indexes.
  */
 void
 ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 9069a43e1d..8212db3b9f 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -935,9 +935,9 @@ PostmasterMain(int argc, char *argv[])
 #endif
 
 	/*
-	 * Register the apply launcher. Since it registers background worker,
-	 * it needs to be called before InitializeMaxBackends() and it's probably
-	 * good idea to call it before aby modules had chance to take the
+	 * Register the apply launcher.  Since it registers a background worker,
+	 * it needs to be called before InitializeMaxBackends(), and it's probably
+	 * a good idea to call it before any modules had chance to take the
 	 * background worker slots.
 	 */
 	ApplyLauncherRegister();
diff --git a/src/backend/replication/logical/apply.c b/src/backend/replication/logical/apply.c
index de50f1dde6..3f78b30797 100644
--- a/src/backend/replication/logical/apply.c
+++ b/src/backend/replication/logical/apply.c
@@ -568,7 +568,7 @@ check_relation_updatable(LogicalRepRelMapEntry *rel)
 	ereport(ERROR,
 			(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 			 errmsg("the logical replication target %s has "
-					"neither REPLICA IDENTIY index or PRIMARY "
+					"neither REPLICA IDENTIY index nor PRIMARY "
 					"KEY and published relation does not have "
 					"REPLICA IDENTITY FULL",
 					quote_qualified_identifier(rel->remoterel.nspname,
@@ -1163,7 +1163,7 @@ reread_subscription(void)
 	if (!equal(newsub->publications, MySubscription->publications))
 	{
 		elog(LOG, "logical replication worker for subscription %s will "
-			 "restart because ssubscription's publications were changed",
+			 "restart because subscription's publications were changed",
 			 MySubscription->name);
 
 		walrcv_disconnect(wrconn);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 7d5a233580..f5b5ebcd06 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -251,9 +251,8 @@ logicalrep_worker_launch(Oid dbid, Oid subid)
 	{
 		ereport(WARNING,
 				(errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
-				 errmsg("logical replication worker registration failed, "
-						"you might want to increase "
-						"max_logical_replication_workers setting")));
+				 errmsg("out of logical replication workers slots"),
+				 errhint("You might need to increase max_logical_replication_workers.")));
 		return;
 	}
 
@@ -293,7 +292,7 @@ logicalrep_worker_launch(Oid dbid, Oid subid)
  * slot.
  *
  * Note it's caller's job to ensure that new workers are not being started
- * during this functiion call. That can be achieven by holding exclusive
+ * during this function call. That can be achieven by holding exclusive
  * lock on LogicalRepLauncherLock.
  */
 void
@@ -567,7 +566,7 @@ ApplyLauncherMain(Datum main_arg)
 									   ALLOCSET_DEFAULT_MAXSIZE);
 		oldctx = MemoryContextSwitchTo(subctx);
 
-		/* Block any concurrent DROPs. */
+		/* Block any concurrent DROP SUBSCRIPTION. */
 		LWLockAcquire(LogicalRepLauncherLock, LW_EXCLUSIVE);
 
 		/* search for subscriptions to start or stop. */
@@ -605,8 +604,8 @@ ApplyLauncherMain(Datum main_arg)
 					   started ? 5000L : 180000L,
 					   WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
 
-        /* emergency bailout if postmaster has died */
-        if (rc & WL_POSTMASTER_DEATH)
+		/* emergency bailout if postmaster has died */
+		if (rc & WL_POSTMASTER_DEATH)
 			proc_exit(1);
 
 		ResetLatch(&MyProc->procLatch);
diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h
index b337d6dc7c..342066f17f 100644
--- a/src/include/catalog/pg_subscription.h
+++ b/src/include/catalog/pg_subscription.h
@@ -21,12 +21,11 @@
 #define SubscriptionRelationId			6100
 #define SubscriptionRelation_Rowtype_Id	6101
 
-/* ----------------
- * Technicaly, the subscriptions live inside the database so shared catalog
+/*
+ * Technicaly, the subscriptions live inside the database, so a shared catalog
  * seems weird, but the replication launcher process needs to access all of
- * then to be able to start the workers so we have to put them in a shared,
- * nailed catalogs.
- * ----------------
+ * them to be able to start the workers, so we have to put them in a shared,
+ * nailed catalog.
  */
 CATALOG(pg_subscription,6100) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6101) BKI_SCHEMA_MACRO
 {
-- 
2.11.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to