pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Petr Jelinek <petr.jelinek@2ndquadrant.com>
To: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: Robert Haas <robertmhaas@gmail.com>
Cc: Michael Paquier <michael.paquier@gmail.com>
Cc: PostgreSQL mailing lists <pgsql-hackers@postgresql.org>
Subject: Re: logical replication syntax (was DROP SUBSCRIPTION, query cancellations and slot handling)
Date: Tue, 9 May 2017 17:43:21 +0200
Message-ID: <20856826-de0f-f630-4c67-36dca21037ad@2ndquadrant.com> (raw)
In-Reply-To: <b54076fd-67d4-cc80-d5a6-ee8db2528e17@2ndquadrant.com>
References: <CA+TgmoZmkbpAWRzVKDVcHnTBkYjJEFS8=09RL-G3zgdozCLFHQ@mail.gmail.com>
	<27478.1493727233@sss.pgh.pa.us>
	<29431.1493730652@sss.pgh.pa.us>
	<360a1932-7af4-609b-94f1-2ad419430869@2ndquadrant.com>
	<9174dc31-787a-a2f6-818f-cb4a5c1dfddb@2ndquadrant.com>
	<30166.1493731904@sss.pgh.pa.us>
	<daf9909a-7033-9cfe-a8cc-a606025820fc@2ndquadrant.com>
	<2b931e0e-d9f2-c79e-b74b-91df2f915e66@2ndquadrant.com>
	<96e95255-94d9-0881-16ba-bdb6d05bb307@2ndquadrant.com>
	<52a1f160-db1f-49c6-9832-498dbea58ae8@2ndquadrant.com>
	<35f3592b-8582-e348-1823-f8edfcf03ba3@2ndquadrant.com>
	<5f6ad263-af87-2aee-b86b-8bf7e3260b73@2ndquadrant.com>
	<b54076fd-67d4-cc80-d5a6-ee8db2528e17@2ndquadrant.com>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>

On 09/05/17 16:28, Peter Eisentraut wrote:
> On 5/9/17 04:39, Petr Jelinek wrote:
>>>> What we want to simulate instead is an "auto" dependency of the slot on
>>>> the subscription.  So you can drop the slot separately (subject to other
>>>> restrictions), and it is dropped automatically when the subscription is
>>>> dropped.  To avoid that, you can disassociate the slot from the
>>>> subscription, which you have implemented.
>>>>
>>>> I think we can therefore do without RESTRICT/CASCADE here.  If a slot is
>>>> associated with the subscription, it should be there when we drop the
>>>> subscription.  Otherwise, the user has to disassociate the slot and take
>>>> care of it manually.  So just keep the "cascade" behavior.
>>>>
>>>> Similarly, I wouldn't check first whether the slot exists.  If the
>>>> subscription is associated with the slot, it should be there.
>>>
>>> Here is your patch amended for that.
>>
>> I am fine with this mechanism as well.
> 
> Committed.
> 
> I also wrote a bit of documentation about slot handling for
> subscriptions, covering some of what was discussed in this thread.
> 

Great, thanks.

Here is rebased version of the other patch (the interface rework). I
also fixed the tab completion there.

-- 
  Petr Jelinek                  http://www.2ndQuadrant.com/
  PostgreSQL Development, 24x7 Support, Training & Services

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

Attachments:

Rework-the-options-for-logical-replication-v2.patch (binary/octet-stream, 60.3K) download From 30dc7544919c97610e1c22ef711ccbfd1873b921 Mon Sep 17 00:00:00 2001 From: Petr Jelinek <pjmodos@pjmodos.net> Date: Wed, 3 May 2017 11:39:22 +0200 Subject: [PATCH] Rework the options for logical replication Use similar option style as other statements which use WITH clause for options. --- doc/src/sgml/ref/alter_publication.sgml | 25 +-- doc/src/sgml/ref/alter_subscription.sgml | 72 +++++-- doc/src/sgml/ref/create_publication.sgml | 57 ++--- doc/src/sgml/ref/create_subscription.sgml | 229 +++++++++++---------- src/backend/commands/publicationcmds.c | 133 +++++------- src/backend/commands/subscriptioncmds.c | 42 +--- src/backend/parser/gram.y | 8 +- src/bin/pg_dump/pg_dump.c | 36 ++-- src/bin/pg_dump/t/002_pg_dump.pl | 12 +- src/bin/psql/tab-complete.c | 16 +- src/include/parser/kwlist.h | 1 - .../dummy_seclabel/expected/dummy_seclabel.out | 2 +- .../modules/dummy_seclabel/sql/dummy_seclabel.sql | 2 +- src/test/regress/expected/object_address.out | 2 +- src/test/regress/expected/publication.out | 10 +- src/test/regress/expected/subscription.out | 22 +- src/test/regress/sql/object_address.sql | 2 +- src/test/regress/sql/publication.sql | 10 +- src/test/regress/sql/subscription.sql | 20 +- src/test/subscription/t/001_rep_changes.pl | 8 +- src/test/subscription/t/002_types.pl | 2 +- src/test/subscription/t/003_constraints.pl | 2 +- src/test/subscription/t/004_sync.pl | 2 +- 23 files changed, 328 insertions(+), 387 deletions(-) diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml index 05bd57d..00e5cfe 100644 --- a/doc/src/sgml/ref/alter_publication.sgml +++ b/doc/src/sgml/ref/alter_publication.sgml @@ -21,14 +21,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> WITH ( <replaceable class="PARAMETER">option</replaceable> [, ... ] ) - -<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase> - - PUBLISH INSERT | NOPUBLISH INSERT - | PUBLISH UPDATE | NOPUBLISH UPDATE - | PUBLISH DELETE | NOPUBLISH DELETE - +ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> WITH ( <replaceable class="parameter">publication_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> ADD TABLE [ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] [, ...] ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> SET TABLE [ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] [, ...] ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> DROP TABLE [ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] [, ...] @@ -44,8 +37,7 @@ ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> RENAME TO <r The first variant of this command listed in the synopsis can change all of the publication properties specified in <xref linkend="sql-createpublication">. Properties not mentioned in the - command retain their previous settings. Database superusers can change any - of these settings for any role. + command retain their previous settings. </para> <para> @@ -80,15 +72,10 @@ ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> RENAME TO <r </varlistentry> <varlistentry> - <term><literal>PUBLISH INSERT</literal></term> - <term><literal>NOPUBLISH INSERT</literal></term> - <term><literal>PUBLISH UPDATE</literal></term> - <term><literal>NOPUBLISH UPDATE</literal></term> - <term><literal>PUBLISH DELETE</literal></term> - <term><literal>NOPUBLISH DELETE</literal></term> + <term><literal>publish</literal></term> <listitem> <para> - These clauses alter properties originally set by + This clause alters property originally set by <xref linkend="SQL-CREATEPUBLICATION">. See there for more information. </para> </listitem> @@ -131,9 +118,9 @@ ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> RENAME TO <r <title>Examples</title> <para> - Change the publication to not publish inserts: + Change the publication to publish only deletes and updates: <programlisting> -ALTER PUBLICATION noinsert WITH (NOPUBLISH INSERT); +ALTER PUBLICATION noinsert OPTIONS (publish 'update, delete'); </programlisting> </para> diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml index 5dae4ae..57652d1 100644 --- a/doc/src/sgml/ref/alter_subscription.sgml +++ b/doc/src/sgml/ref/alter_subscription.sgml @@ -21,20 +21,9 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> WITH ( <replaceable class="PARAMETER">suboption</replaceable> [, ... ] ) - -<phrase>where <replaceable class="PARAMETER">suboption</replaceable> can be:</phrase> - - SLOT NAME = <replaceable class="PARAMETER">slot_name</replaceable> - | SYNCHRONOUS_COMMIT = <replaceable class="PARAMETER">synchronous_commit</replaceable> - -ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> SET PUBLICATION <replaceable class="PARAMETER">publication_name</replaceable> [, ...] { REFRESH WITH ( <replaceable class="PARAMETER">puboption</replaceable> [, ... ] ) | NOREFRESH } -ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> REFRESH PUBLICATION [ WITH ( <replaceable class="PARAMETER">puboption</replaceable> [, ... ] ) ] - -<phrase>where <replaceable class="PARAMETER">puboption</replaceable> can be:</phrase> - - COPY DATA | NOCOPY DATA - +ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> WITH ( <replaceable class="parameter">subscription_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) +ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> SET PUBLICATION <replaceable class="PARAMETER">publication_name</replaceable> [, ...] { REFRESH WITH ( <replaceable class="PARAMETER">refresh_option</replaceable> <replaceable class="PARAMETER">value</replaceable> [, ... ] ) | SKIP REFRESH } +ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> REFRESH PUBLICATION [ WITH ( <replaceable class="PARAMETER">refresh_option</replaceable> <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ] ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> CONNECTION '<replaceable>conninfo</replaceable>' ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> ENABLE ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> DISABLE @@ -73,11 +62,9 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO < <varlistentry> <term><literal>CONNECTION '<replaceable class="parameter">conninfo</replaceable>'</literal></term> - <term><literal>SLOT NAME = <replaceable class="parameter">slot_name</replaceable></literal></term> - <term><literal>SYNCHRONOUS_COMMIT = <replaceable class="PARAMETER">synchronous_commit</replaceable></literal></term> <listitem> <para> - These clauses alter properties originally set by + This clause alter property originally set by <xref linkend="SQL-CREATESUBSCRIPTION">. See there for more information. </para> @@ -85,6 +72,18 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO < </varlistentry> <varlistentry> + <term><literal>WITH ( <replaceable class="parameter">subscription_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term> + <listitem> + <para> + This clause alter property originally set by + <xref linkend="SQL-CREATESUBSCRIPTION">. See there for more + information. The allowed options are <literal>slot_name</literal> and + <literal>synchronous_commit</literal> + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><literal>SET PUBLICATION <replaceable class="parameter">publication_name</replaceable></literal></term> <listitem> <para> @@ -97,7 +96,12 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO < <literal>NOREFRESH</literal> is specified, the comamnd will not try to refresh table information. </para> - </listitem> + <para> + The <literal>refresh_option</literal> is an additional option for the + refresh operation. See + <xref linkend="sql-altersubscription-refresh-options"> for details. + </para> + </listitem> </varlistentry> <varlistentry> @@ -110,10 +114,9 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO < since <command>CREATE SUBSCRIPTION</command>. </para> <para> - The <literal>COPY DATA</literal> and <literal>NOCOPY DATA</literal> - options specify if the existing data in the publications that are being - subscribed to should be copied. <literal>COPY DATA</literal> is the - default. + The <literal>refresh_option</literal> is an additional option for the + refresh operation. See + <xref linkend="sql-altersubscription-refresh-options"> for details. </para> </listitem> </varlistentry> @@ -156,6 +159,31 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO < </listitem> </varlistentry> </variablelist> + + <refsect2 id="sql-altersubscription-refresh-options"> + <title id="sql-altersubscription-refresh-options-title">Refresh options</title> + + <para> + The optional <literal>WITH</> clause for + <literal>SET PUBLICATION</literal> and + <literal>REFRESH PUBLICATION</literal> clauses specifies behavior of the + refresh operation. The supported options are: + </para> + + <variablelist> + <varlistentry> + <term><literal>copy_data</literal> (<type>boolean</type>)</term> + <listitem> + <para> + Specifies if the existing data in the publications that are being + subscribed to should be copied once the replication starts. + The default is <literal>true</literal>. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect2> + </refsect1> <refsect1> diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 521376e..76f4250 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -24,13 +24,8 @@ PostgreSQL documentation CREATE PUBLICATION <replaceable class="parameter">name</replaceable> [ FOR TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ] [, ...] | FOR ALL TABLES ] - [ WITH ( <replaceable class="parameter">option</replaceable> [, ... ] ) ] + [ WITH ( <replaceable class="parameter">publication_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ] -<phrase>where <replaceable class="parameter">option</replaceable> can be:</phrase> - - PUBLISH INSERT | NOPUBLISH INSERT - | PUBLISH UPDATE | NOPUBLISH UPDATE - | PUBLISH DELETE | NOPUBLISH DELETE </synopsis> </refsynopsisdiv> @@ -97,37 +92,29 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> </varlistentry> <varlistentry> - <term><literal>PUBLISH INSERT</literal></term> - <term><literal>NOPUBLISH INSERT</literal></term> - <listitem> - <para> - These clauses determine whether the new publication will send - the <command>INSERT</command> operations to the subscribers. - <literal>PUBLISH INSERT</literal> is the default. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>PUBLISH UPDATE</literal></term> - <term><literal>NOPUBLISH UPDATE</literal></term> + <term><literal>WITH ( <replaceable class="parameter">publication_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term> <listitem> <para> - These clauses determine whether the new publication will send - the <command>UPDATE</command> operations to the subscribers. - <literal>PUBLISH UPDATE</literal> is the default. - </para> - </listitem> - </varlistentry> + This clause specifies optional parameters for a pubication; the + following parameters are supported: + + <variablelist> + <varlistentry> + <term><literal>publish</literal> (<type>string</type>)</term> + <listitem> + <para> + This clause determine which DML operations will be published by + the new publication to the subscribers. The value is comma + separated list of actions. The allowed operations are + <literal>insert</literal>, <literal>update</literal>, and + <literal>delete</literal>. The default is to publish all actions so + the default value for this option is + <literal>'insert,update,delete'</literal>. + </para> + </listitem> + </varlistentry> + </variablelist> - <varlistentry> - <term><literal>PUBLISH DELETE</literal></term> - <term><literal>NOPUBLISH DELETE</literal></term> - <listitem> - <para> - These clauses determine whether the new publication will send - the <command>DELETE</command> operations to the subscribers. - <literal>PUBLISH DELETE</literal> is the default. </para> </listitem> </varlistentry> @@ -203,7 +190,7 @@ CREATE PUBLICATION alltables FOR ALL TABLES; operations in one table: <programlisting> CREATE PUBLICATION insert_only FOR TABLE mydata - WITH (NOPUBLISH UPDATE, NOPUBLISH DELETE); + WITH (publish = 'insert'); </programlisting> </para> </refsect1> diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml index 6382468..9fbc804 100644 --- a/doc/src/sgml/ref/create_subscription.sgml +++ b/doc/src/sgml/ref/create_subscription.sgml @@ -24,16 +24,7 @@ PostgreSQL documentation CREATE SUBSCRIPTION <replaceable class="PARAMETER">subscription_name</replaceable> CONNECTION '<replaceable class="PARAMETER">conninfo</replaceable>' PUBLICATION { <replaceable class="PARAMETER">publication_name</replaceable> [, ...] } - [ WITH ( <replaceable class="PARAMETER">option</replaceable> [, ... ] ) ] - -<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase> - - | ENABLED | DISABLED - | CREATE SLOT | NOCREATE SLOT - | SLOT NAME = <replaceable class="PARAMETER">slot_name</replaceable> - | COPY DATA | NOCOPY DATA - | SYNCHRONOUS_COMMIT = <replaceable class="PARAMETER">synchronous_commit</replaceable> - | NOCONNECT + [ WITH ( <replaceable class="parameter">subscription_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ] </synopsis> </refsynopsisdiv> @@ -103,110 +94,122 @@ CREATE SUBSCRIPTION <replaceable class="PARAMETER">subscription_name</replaceabl </varlistentry> <varlistentry> - <term><literal>ENABLED</literal></term> - <term><literal>DISABLED</literal></term> - <listitem> - <para> - 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. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>CREATE SLOT</literal></term> - <term><literal>NOCREATE SLOT</literal></term> - <listitem> - <para> - Specifies whether the command should create the replication slot on the - publisher. <literal>CREATE SLOT</literal> is the default. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <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 - <literal>subscription_name</> for slot name. - </para> - - <para> - When <literal>SLOT NAME</literal> is set to - <literal>NONE</literal>, there will be no replication slot associated - with the subscription. This can be used if the replication slot will be - created later manually. Such subscriptions must also have both - <literal>ENABLED</literal> and <literal>CREATE SLOT</literal> set - to <literal>false</literal>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>COPY DATA</literal></term> - <term><literal>NOCOPY DATA</literal></term> + <term><literal>WITH ( <replaceable class="parameter">subscription_option</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term> <listitem> <para> - Specifies if the existing data in the publications that are being - subscribed to should be copied once the replication starts. - <literal>COPY DATA</literal> is the default. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>SYNCHRONOUS_COMMIT = <replaceable class="PARAMETER">synchronous_commit</replaceable></literal></term> - <listitem> - <para> - The value of this parameter overrides the - <xref linkend="guc-synchronous-commit"> setting. The default value is - <literal>off</literal>. - </para> - - <para> - It is safe to use <literal>off</literal> for logical replication: If the - subscriber loses transactions because of missing synchronization, the - data will be resent from the publisher. - </para> - - <para> - A different setting might be appropriate when doing synchronous logical - replication. The logical replication workers report the positions of - writes and flushes to the publisher, and when using synchronous - replication, the publisher will wait for the actual flush. This means - that setting <literal>SYNCHRONOUS_COMMIT</literal> for the subscriber - to <literal>off</literal> when the subscription is used for synchronous - replication might increase the latency for <command>COMMIT</command> on - the publisher. In this scenario, it can be advantageous to set - <literal>SYNCHRONOUS_COMMIT</literal> to <literal>local</literal> or - higher. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>NOCONNECT</literal></term> - <listitem> - <para> - Instructs <command>CREATE SUBSCRIPTION</command> to skip the initial - connection to the provider. This will change default values of other - options to <literal>DISABLED</literal>, - <literal>NOCREATE SLOT</literal>, and <literal>NOCOPY DATA</literal>. - </para> - <para> - It's not allowed to combine <literal>NOCONNECT</literal> and - <literal>ENABLED</literal>, <literal>CREATE SLOT</literal>, or - <literal>COPY DATA</literal>. - </para> - <para> - Since no connection is made when this option is specified, the tables - are not subscribed, so after you enable the subscription nothing will - be replicated. It is required to run - <literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</> in order for - tables to be subscribed. + This clause specifies optional parameters for a subscription; the + following parameters are supported: + + <variablelist> + <varlistentry> + <term><literal>enabled</literal> (<type>boolean</type>)</term> + <listitem> + <para> + Specifies whether the subscription should be actively replicating + or if it should be just setup but not started yet. The default is + <literal>true</literal>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>create_slot</literal> (<type>boolean</type>)</term> + <listitem> + <para> + Specifies whether the command should create the replication slot + on the publisher. The default is <literal>true</literal>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>slot_name</literal> (<type>string</type>)</term> + <listitem> + <para> + Name of the replication slot to use. The default behavior is to + use <literal>subscription_name</> for slot name. + </para> + + <para> + When <literal>slot_name</literal> is set to + <literal>NONE</literal>, there will be no replication slot + associated with the subscription. This can be used if the + replication slot will be created later manually. Such + subscriptions must also have both <literal>enabled</literal> and + <literal>create_slot</literal> set to <literal>false</literal>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>copy_data</literal> (<type>boolean</type>)</term> + <listitem> + <para> + Specifies if the existing data in the publications that are being + subscribed to should be copied once the replication starts. + The default is <literal>true</literal>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>synchronous_commit</literal> (<type>enum</type>)</term> + <listitem> + <para> + The value of this parameter overrides the + <xref linkend="guc-synchronous-commit"> setting. The default + value is <literal>off</literal>. + </para> + + <para> + It is safe to use <literal>off</literal> for logical replication: + If the subscriber loses transactions because of missing + synchronization, the data will be resent from the publisher. + </para> + + <para> + A different setting might be appropriate when doing synchronous + logical replication. The logical replication workers report the + positions of writes and flushes to the publisher, and when using + synchronous replication, the publisher will wait for the actual + flush. This means that setting + <literal>synchronous_commit</literal> for the subscriber to + <literal>off</literal> when the subscription is used for + synchronous replication might increase the latency for + <command>COMMIT</command> on the publisher. In this scenario, it + can be advantageous to set <literal>synchronous_commit</literal> + to <literal>local</literal> or higher. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>connect</literal> (<type>boolean</type>)</term> + <listitem> + <para> + Boolean specifying if the <command>CREATE SUBSCRIPTION</command> + should connect to the provider. Setting this to + <literal>false</literal> will change default values of + <literal>enabled</literal>, <literal>create_slot</literal> and + <literal>copy_data</literal> to <literal>false</literal>. + </para> + <para> + It's not allowed to combine <literal>connect</literal> set to + <literal>false</literal> and <literal>enabled</literal>, + <literal>create_slot</literal>, or <literal>copy_data</literal> + to <literal>true</literal>. + </para> + <para> + Since no connection is made when this option is specified, the + tables are not subscribed, so after you enable the subscription + nothing will be replicated. It is required to run + <literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</> in order + for tables to be subscribed. + </para> + </listitem> + </varlistentry> + + </variablelist> </para> </listitem> </varlistentry> @@ -246,7 +249,7 @@ CREATE SUBSCRIPTION mysub CREATE SUBSCRIPTION mysub CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb' PUBLICATION insert_only - WITH (DISABLED); + WITH (enabled = false); </programlisting> </para> </refsect1> diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 541da7e..0ead996 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -46,6 +46,7 @@ #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" +#include "utils/varlena.h" /* Same as MAXNUMMESSAGES in sinvaladt.c */ #define MAX_RELCACHE_INVAL_MSGS 4096 @@ -58,18 +59,14 @@ static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok); static void parse_publication_options(List *options, - bool *publish_insert_given, + bool *publish_given, bool *publish_insert, - bool *publish_update_given, bool *publish_update, - bool *publish_delete_given, bool *publish_delete) { ListCell *lc; - *publish_insert_given = false; - *publish_update_given = false; - *publish_delete_given = false; + *publish_given = false; /* Defaults are true */ *publish_insert = true; @@ -81,65 +78,47 @@ parse_publication_options(List *options, { DefElem *defel = (DefElem *) lfirst(lc); - if (strcmp(defel->defname, "publish insert") == 0) + if (strcmp(defel->defname, "publish") == 0) { - if (*publish_insert_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + char *publish; + List *publish_list; + ListCell *lc; - *publish_insert_given = true; - *publish_insert = defGetBoolean(defel); - } - else if (strcmp(defel->defname, "nopublish insert") == 0) - { - if (*publish_insert_given) + if (*publish_given) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); - *publish_insert_given = true; - *publish_insert = !defGetBoolean(defel); - } - else if (strcmp(defel->defname, "publish update") == 0) - { - if (*publish_update_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + /* + * If publish option was given only the explicitly listed actions + * should be published. + */ + *publish_insert = false; + *publish_update = false; + *publish_delete = false; - *publish_update_given = true; - *publish_update = defGetBoolean(defel); - } - else if (strcmp(defel->defname, "nopublish update") == 0) - { - if (*publish_update_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + *publish_given = true; + publish = defGetString(defel); - *publish_update_given = true; - *publish_update = !defGetBoolean(defel); - } - else if (strcmp(defel->defname, "publish delete") == 0) - { - if (*publish_delete_given) + if (!SplitIdentifierString(publish, ',', &publish_list)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); + errmsg("invalid publish list"))); - *publish_delete_given = true; - *publish_delete = defGetBoolean(defel); - } - else if (strcmp(defel->defname, "nopublish delete") == 0) - { - if (*publish_delete_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - - *publish_delete_given = true; - *publish_delete = !defGetBoolean(defel); + /* Process the option list. */ + foreach (lc, publish_list) + { + char *publish_opt = (char *)lfirst(lc); + + if (strcmp(publish_opt, "insert") == 0) + *publish_insert = true; + else if (strcmp(publish_opt, "update") == 0) + *publish_update = true; + else if (strcmp(publish_opt, "delete") == 0) + *publish_delete = true; + else + elog(ERROR, "unrecognized publish option: %s", publish_opt); + } } else elog(ERROR, "unrecognized option: %s", defel->defname); @@ -158,9 +137,7 @@ CreatePublication(CreatePublicationStmt *stmt) bool nulls[Natts_pg_publication]; Datum values[Natts_pg_publication]; HeapTuple tup; - bool publish_insert_given; - bool publish_update_given; - bool publish_delete_given; + bool publish_given; bool publish_insert; bool publish_update; bool publish_delete; @@ -199,9 +176,8 @@ CreatePublication(CreatePublicationStmt *stmt) values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId()); parse_publication_options(stmt->options, - &publish_insert_given, &publish_insert, - &publish_update_given, &publish_update, - &publish_delete_given, &publish_delete); + &publish_given, &publish_insert, + &publish_update, &publish_delete); values[Anum_pg_publication_puballtables - 1] = BoolGetDatum(stmt->for_all_tables); @@ -253,42 +229,31 @@ AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, bool nulls[Natts_pg_publication]; bool replaces[Natts_pg_publication]; Datum values[Natts_pg_publication]; - bool publish_insert_given; - bool publish_update_given; - bool publish_delete_given; + bool publish_given; bool publish_insert; bool publish_update; bool publish_delete; ObjectAddress obj; parse_publication_options(stmt->options, - &publish_insert_given, &publish_insert, - &publish_update_given, &publish_update, - &publish_delete_given, &publish_delete); + &publish_given, &publish_insert, + &publish_update, &publish_delete); + + Assert(publish_given); /* Everything ok, form a new tuple. */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); memset(replaces, false, sizeof(replaces)); - if (publish_insert_given) - { - values[Anum_pg_publication_pubinsert - 1] = - BoolGetDatum(publish_insert); - replaces[Anum_pg_publication_pubinsert - 1] = true; - } - if (publish_update_given) - { - values[Anum_pg_publication_pubupdate - 1] = - BoolGetDatum(publish_update); - replaces[Anum_pg_publication_pubupdate - 1] = true; - } - if (publish_delete_given) - { - values[Anum_pg_publication_pubdelete - 1] = - BoolGetDatum(publish_delete); - replaces[Anum_pg_publication_pubdelete - 1] = true; - } + values[Anum_pg_publication_pubinsert - 1] = BoolGetDatum(publish_insert); + replaces[Anum_pg_publication_pubinsert - 1] = true; + + values[Anum_pg_publication_pubupdate - 1] = BoolGetDatum(publish_update); + replaces[Anum_pg_publication_pubupdate - 1] = true; + + values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(publish_delete); + replaces[Anum_pg_publication_pubdelete - 1] = true; tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces); diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index b76cdc5..b3a41a2 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -93,7 +93,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, { DefElem *defel = (DefElem *) lfirst(lc); - if (strcmp(defel->defname, "noconnect") == 0 && connect) + if (strcmp(defel->defname, "connect") == 0 && connect) { if (connect_given) ereport(ERROR, @@ -101,7 +101,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, errmsg("conflicting or redundant options"))); connect_given = true; - *connect = !defGetBoolean(defel); + *connect = defGetBoolean(defel); } else if (strcmp(defel->defname, "enabled") == 0 && enabled) { @@ -113,17 +113,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, *enabled_given = true; *enabled = defGetBoolean(defel); } - else if (strcmp(defel->defname, "disabled") == 0 && enabled) - { - if (*enabled_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - - *enabled_given = true; - *enabled = !defGetBoolean(defel); - } - else if (strcmp(defel->defname, "create slot") == 0 && create_slot) + else if (strcmp(defel->defname, "create_slot") == 0 && create_slot) { if (create_slot_given) ereport(ERROR, @@ -133,17 +123,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, create_slot_given = true; *create_slot = defGetBoolean(defel); } - else if (strcmp(defel->defname, "nocreate slot") == 0 && create_slot) - { - if (create_slot_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - - create_slot_given = true; - *create_slot = !defGetBoolean(defel); - } - else if (strcmp(defel->defname, "slot name") == 0 && slot_name) + else if (strcmp(defel->defname, "slot_name") == 0 && slot_name) { if (*slot_name_given) ereport(ERROR, @@ -157,7 +137,7 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, if (strcmp(*slot_name, "none") == 0) *slot_name = NULL; } - else if (strcmp(defel->defname, "copy data") == 0 && copy_data) + else if (strcmp(defel->defname, "copy_data") == 0 && copy_data) { if (copy_data_given) ereport(ERROR, @@ -167,16 +147,6 @@ parse_subscription_options(List *options, bool *connect, bool *enabled_given, copy_data_given = true; *copy_data = defGetBoolean(defel); } - else if (strcmp(defel->defname, "nocopy data") == 0 && copy_data) - { - if (copy_data_given) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - - copy_data_given = true; - *copy_data = !defGetBoolean(defel); - } else if (strcmp(defel->defname, "synchronous_commit") == 0 && synchronous_commit) { @@ -336,7 +306,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) * replication slot. */ if (create_slot) - PreventTransactionChain(isTopLevel, "CREATE SUBSCRIPTION ... CREATE SLOT"); + PreventTransactionChain(isTopLevel, "CREATE SUBSCRIPTION ... (create_slot true)"); if (!superuser()) ereport(ERROR, diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 65c004c..68f5efd 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -652,8 +652,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NONE - NOREFRESH NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF - NULLS_P NUMERIC + NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER @@ -5685,7 +5684,6 @@ def_elem: def_key '=' def_arg def_key: ColLabel { $$ = $1; } - | ColLabel ColLabel { $$ = psprintf("%s %s", $1, $2); } ; /* Note: any simple identifier will be returned as a type name! */ @@ -9173,6 +9171,7 @@ publication_for_tables: } ; + /***************************************************************************** * * ALTER PUBLICATION name [ WITH ] options @@ -9296,7 +9295,7 @@ AlterSubscriptionStmt: n->options = $8; $$ = (Node *)n; } - | ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list NOREFRESH + | ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list SKIP REFRESH { AlterSubscriptionStmt *n = makeNode(AlterSubscriptionStmt); @@ -14758,7 +14757,6 @@ unreserved_keyword: | NEW | NEXT | NO - | NOREFRESH | NOTHING | NOTIFY | NOWAIT diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index d724b11..8aa420f 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -3460,6 +3460,7 @@ dumpPublication(Archive *fout, PublicationInfo *pubinfo) PQExpBuffer delq; PQExpBuffer query; PQExpBuffer labelq; + bool first = true; if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)) return; @@ -3479,23 +3480,32 @@ dumpPublication(Archive *fout, PublicationInfo *pubinfo) if (pubinfo->puballtables) appendPQExpBufferStr(query, " FOR ALL TABLES"); - appendPQExpBufferStr(query, " WITH ("); + appendPQExpBufferStr(query, " WITH (publish = '"); if (pubinfo->pubinsert) - appendPQExpBufferStr(query, "PUBLISH INSERT"); - else - appendPQExpBufferStr(query, "NOPUBLISH INSERT"); + { + appendPQExpBufferStr(query, "insert"); + first = false; + } + + if (!first) + appendPQExpBufferChar(query, ','); if (pubinfo->pubupdate) - appendPQExpBufferStr(query, ", PUBLISH UPDATE"); - else - appendPQExpBufferStr(query, ", NOPUBLISH UPDATE"); + { + appendPQExpBufferStr(query, "update"); + first = false; + } + + if (!first) + appendPQExpBufferChar(query, ','); if (pubinfo->pubdelete) - appendPQExpBufferStr(query, ", PUBLISH DELETE"); - else - appendPQExpBufferStr(query, ", NOPUBLISH DELETE"); + { + appendPQExpBufferStr(query, "delete"); + first = false; + } - appendPQExpBufferStr(query, ");\n"); + appendPQExpBufferStr(query, "');\n"); ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId, pubinfo->dobj.name, @@ -3817,11 +3827,11 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo) appendPQExpBufferStr(publications, fmtId(pubnames[i])); } - appendPQExpBuffer(query, " PUBLICATION %s WITH (NOCONNECT, SLOT NAME = ", publications->data); + appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data); appendStringLiteralAH(query, subinfo->subslotname, fout); if (strcmp(subinfo->subsynccommit, "off") != 0) - appendPQExpBuffer(query, ", SYNCHRONOUS_COMMIT = %s", fmtId(subinfo->subsynccommit)); + appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit)); appendPQExpBufferStr(query, ");\n"); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index ce0c9ef..938c332 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -4351,7 +4351,7 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog create_order => 50, create_sql => 'CREATE PUBLICATION pub1;', regexp => qr/^ - \QCREATE PUBLICATION pub1 WITH (PUBLISH INSERT, PUBLISH UPDATE, PUBLISH DELETE);\E + \QCREATE PUBLICATION pub1 WITH (publish = 'insert,update,delete');\E /xm, like => { binary_upgrade => 1, @@ -4384,11 +4384,9 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog create_order => 50, create_sql => 'CREATE PUBLICATION pub2 FOR ALL TABLES - WITH (NOPUBLISH INSERT, - NOPUBLISH UPDATE, - NOPUBLISH DELETE);', + WITH (publish = \'\');', regexp => qr/^ - \QCREATE PUBLICATION pub2 FOR ALL TABLES WITH (NOPUBLISH INSERT, NOPUBLISH UPDATE, NOPUBLISH DELETE);\E + \QCREATE PUBLICATION pub2 FOR ALL TABLES WITH (publish = '');\E /xm, like => { binary_upgrade => 1, @@ -4421,9 +4419,9 @@ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog create_order => 50, create_sql => 'CREATE SUBSCRIPTION sub1 CONNECTION \'dbname=doesnotexist\' PUBLICATION pub1 - WITH (NOCONNECT);', + WITH (connect = false);', regexp => qr/^ - \QCREATE SUBSCRIPTION sub1 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (NOCONNECT, SLOT NAME = 'sub1');\E + \QCREATE SUBSCRIPTION sub1 CONNECTION 'dbname=doesnotexist' PUBLICATION pub1 WITH (connect = false, slot_name = 'sub1');\E /xm, like => { binary_upgrade => 1, diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 3bd5277..16c93fa 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1507,8 +1507,7 @@ psql_completion(const char *text, int start, int end) /* ALTER PUBLICATION <name> .. WITH ( ... */ else if (HeadMatches3("ALTER", "PUBLICATION",MatchAny) && TailMatches2("WITH", "(")) { - COMPLETE_WITH_LIST6("PUBLISH INSERT", "NOPUBLISH INSERT", "PUBLISH UPDATE", - "NOPUBLISH UPDATE", "PUBLISH DELETE", "NOPUBLISH DELETE"); + COMPLETE_WITH_CONST("publish"); } /* ALTER SUBSCRIPTION <name> ... */ else if (Matches3("ALTER","SUBSCRIPTION",MatchAny)) @@ -1520,12 +1519,12 @@ psql_completion(const char *text, int start, int end) else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches4("REFRESH", "PUBLICATION", "WITH", "(")) { - COMPLETE_WITH_LIST2("COPY DATA", "NOCOPY DATA"); + COMPLETE_WITH_CONST("copy_data"); } /* ALTER SUBSCRIPTION <name> .. WITH ( ... */ else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches2("WITH", "(")) { - COMPLETE_WITH_CONST("SLOT NAME"); + COMPLETE_WITH_CONST("slot_name"); } /* ALTER SCHEMA <name> */ else if (Matches3("ALTER", "SCHEMA", MatchAny)) @@ -2349,9 +2348,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete "CREATE PUBLICATION <name> [...] WITH" */ else if (HeadMatches2("CREATE", "PUBLICATION") && TailMatches2("WITH", "(")) - COMPLETE_WITH_LIST2("PUBLISH", "NOPUBLISH"); - else if (HeadMatches2("CREATE", "PUBLICATION") && TailMatches3("WITH", "(", MatchAny)) - COMPLETE_WITH_LIST3("INSERT", "UPDATE", "DELETE"); + COMPLETE_WITH_CONST("publish"); /* CREATE RULE */ /* Complete "CREATE RULE <sth>" with "AS ON" */ @@ -2427,9 +2424,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_CONST("WITH ("); /* Complete "CREATE SUBSCRIPTION <name> ... WITH ( <opt>" */ else if (HeadMatches2("CREATE", "SUBSCRIPTION") && TailMatches2("WITH", "(")) - COMPLETE_WITH_LIST8("ENABLED", "DISABLED", "CREATE SLOT", - "NOCREATE SLOT", "SLOT NAME", "COPY DATA", "NOCOPY DATA", - "NOCONNECT"); + COMPLETE_WITH_LIST5("enabled", "create_slot", "slot_name", + "copy_data", "connect"); /* CREATE TRIGGER --- is allowed inside CREATE SCHEMA, so use TailMatches */ /* complete CREATE TRIGGER <name> with BEFORE,AFTER,INSTEAD OF */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 1ef03cf..f50e45e 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -259,7 +259,6 @@ PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD) PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD) PG_KEYWORD("no", NO, UNRESERVED_KEYWORD) PG_KEYWORD("none", NONE, COL_NAME_KEYWORD) -PG_KEYWORD("norefresh", NOREFRESH, UNRESERVED_KEYWORD) PG_KEYWORD("not", NOT, RESERVED_KEYWORD) PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD) PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD) diff --git a/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out index 5f37681..77bdc93 100644 --- a/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out +++ b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out @@ -69,7 +69,7 @@ CREATE SCHEMA dummy_seclabel_test; SECURITY LABEL ON SCHEMA dummy_seclabel_test IS 'unclassified'; -- OK SET client_min_messages = error; CREATE PUBLICATION dummy_pub; -CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (NOCONNECT, SLOT NAME = NONE); +CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (connect = false, slot_name = NONE); RESET client_min_messages; SECURITY LABEL ON PUBLICATION dummy_pub IS 'classified'; SECURITY LABEL ON SUBSCRIPTION dummy_sub IS 'classified'; diff --git a/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql b/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql index 97311c7..8c347b6 100644 --- a/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql +++ b/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql @@ -73,7 +73,7 @@ SECURITY LABEL ON SCHEMA dummy_seclabel_test IS 'unclassified'; -- OK SET client_min_messages = error; CREATE PUBLICATION dummy_pub; -CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (NOCONNECT, SLOT NAME = NONE); +CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (connect = false, slot_name = NONE); RESET client_min_messages; SECURITY LABEL ON PUBLICATION dummy_pub IS 'classified'; SECURITY LABEL ON SUBSCRIPTION dummy_sub IS 'classified'; diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 40eeeed..700f261 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -37,7 +37,7 @@ CREATE TRANSFORM FOR int LANGUAGE SQL ( FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal)); CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable; -CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (NOCONNECT, SLOT NAME = NONE); +CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE); WARNING: tables were not subscribed, you will have to run ALTER SUBSCRIPTION ... REFRESH PUBLICATION to subscribe the tables CREATE STATISTICS addr_nsp.gentable_stat ON (a,b) FROM addr_nsp.gentable; -- test some error cases diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index f3a348d..d9089af 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -13,8 +13,8 @@ SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; test publication (1 row) -CREATE PUBLICATION testpib_ins_trunct WITH (nopublish delete, nopublish update); -ALTER PUBLICATION testpub_default WITH (nopublish insert, nopublish delete); +CREATE PUBLICATION testpib_ins_trunct WITH (publish = insert); +ALTER PUBLICATION testpub_default WITH (publish = update); \dRp List of publications Name | Owner | Inserts | Updates | Deletes @@ -23,7 +23,7 @@ ALTER PUBLICATION testpub_default WITH (nopublish insert, nopublish delete); testpub_default | regress_publication_user | f | t | f (2 rows) -ALTER PUBLICATION testpub_default WITH (publish insert, publish delete); +ALTER PUBLICATION testpub_default WITH (publish = 'insert, update, delete'); \dRp List of publications Name | Owner | Inserts | Updates | Deletes @@ -38,8 +38,8 @@ CREATE TABLE testpub_tbl1 (id serial primary key, data text); CREATE TABLE pub_test.testpub_nopk (foo int, bar int); CREATE VIEW testpub_view AS SELECT 1; CREATE TABLE testpub_parted (a int) PARTITION BY LIST (a); -CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (nopublish delete, nopublish update); -ALTER PUBLICATION testpub_foralltables WITH (publish update); +CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (publish = 'insert'); +ALTER PUBLICATION testpub_foralltables WITH (publish = 'insert,update'); CREATE TABLE testpub_tbl2 (id serial primary key, data text); -- fail - can't add to for all tables publication ALTER PUBLICATION testpub_foralltables ADD TABLE testpub_tbl2; diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out index 56f826b..2caff71 100644 --- a/src/test/regress/expected/subscription.out +++ b/src/test/regress/expected/subscription.out @@ -17,18 +17,18 @@ LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo; ^ -- fail - cannot do CREATE SUBSCRIPTION CREATE SLOT inside transaction block BEGIN; -CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (CREATE SLOT); -ERROR: CREATE SUBSCRIPTION ... CREATE SLOT cannot run inside a transaction block +CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (create_slot); +ERROR: CREATE SUBSCRIPTION ... (create_slot true) cannot run inside a transaction block COMMIT; -- fail - invalid connection string CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub; ERROR: invalid connection string syntax: missing "=" after "testconn" in connection info string -- fail - duplicate publications -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION foo, testpub, foo WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION foo, testpub, foo WITH (connect = false); ERROR: publication name "foo" used more than once -- ok -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (connect = false); WARNING: tables were not subscribed, you will have to run ALTER SUBSCRIPTION ... REFRESH PUBLICATION to subscribe the tables COMMENT ON SUBSCRIPTION testsub IS 'test subscription'; SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s; @@ -38,11 +38,11 @@ SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s; (1 row) -- fail - name already exists -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (connect = false); ERROR: subscription "testsub" already exists -- fail - must be superuser SET SESSION AUTHORIZATION 'regress_subscription_user2'; -CREATE SUBSCRIPTION testsub2 CONNECTION 'dbname=doesnotexist' PUBLICATION foo WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub2 CONNECTION 'dbname=doesnotexist' PUBLICATION foo WITH (connect = false); ERROR: must be superuser to create subscriptions SET SESSION AUTHORIZATION 'regress_subscription_user'; -- fail - invalid connection string @@ -56,9 +56,9 @@ ERROR: invalid connection string syntax: missing "=" after "foobar" in connecti testsub | regress_subscription_user | f | {testpub} | off | dbname=doesnotexist (1 row) -ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3 NOREFRESH; +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3 SKIP REFRESH; ALTER SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist2'; -ALTER SUBSCRIPTION testsub WITH (SLOT NAME = 'newname'); +ALTER SUBSCRIPTION testsub WITH (slot_name = 'newname'); -- fail ALTER SUBSCRIPTION doesnotexist CONNECTION 'dbname=doesnotexist2'; ERROR: subscription "doesnotexist" does not exist @@ -93,8 +93,8 @@ ALTER SUBSCRIPTION testsub RENAME TO testsub_dummy; ERROR: must be owner of subscription testsub RESET ROLE; ALTER SUBSCRIPTION testsub RENAME TO testsub_foo; -ALTER SUBSCRIPTION testsub_foo WITH (SYNCHRONOUS_COMMIT = local); -ALTER SUBSCRIPTION testsub_foo WITH (SYNCHRONOUS_COMMIT = foobar); +ALTER SUBSCRIPTION testsub_foo WITH (synchronous_commit = local); +ALTER SUBSCRIPTION testsub_foo WITH (synchronous_commit = foobar); ERROR: invalid value for parameter "synchronous_commit": "foobar" HINT: Available values: local, remote_write, remote_apply, on, off. \dRs+ @@ -118,7 +118,7 @@ BEGIN; DROP SUBSCRIPTION testsub; ERROR: DROP SUBSCRIPTION cannot run inside a transaction block COMMIT; -ALTER SUBSCRIPTION testsub WITH (SLOT NAME = NONE); +ALTER SUBSCRIPTION testsub WITH (slot_name = NONE); -- now it works BEGIN; DROP SUBSCRIPTION testsub; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 6940392..8a738e2 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -40,7 +40,7 @@ CREATE TRANSFORM FOR int LANGUAGE SQL ( FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal)); CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable; -CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (NOCONNECT, SLOT NAME = NONE); +CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE); CREATE STATISTICS addr_nsp.gentable_stat ON (a,b) FROM addr_nsp.gentable; -- test some error cases diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 7d1cba5..ed6bd57 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -11,13 +11,13 @@ CREATE PUBLICATION testpub_default; COMMENT ON PUBLICATION testpub_default IS 'test publication'; SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; -CREATE PUBLICATION testpib_ins_trunct WITH (nopublish delete, nopublish update); +CREATE PUBLICATION testpib_ins_trunct WITH (publish = insert); -ALTER PUBLICATION testpub_default WITH (nopublish insert, nopublish delete); +ALTER PUBLICATION testpub_default WITH (publish = update); \dRp -ALTER PUBLICATION testpub_default WITH (publish insert, publish delete); +ALTER PUBLICATION testpub_default WITH (publish = 'insert, update, delete'); \dRp @@ -28,8 +28,8 @@ CREATE TABLE pub_test.testpub_nopk (foo int, bar int); CREATE VIEW testpub_view AS SELECT 1; CREATE TABLE testpub_parted (a int) PARTITION BY LIST (a); -CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (nopublish delete, nopublish update); -ALTER PUBLICATION testpub_foralltables WITH (publish update); +CREATE PUBLICATION testpub_foralltables FOR ALL TABLES WITH (publish = 'insert'); +ALTER PUBLICATION testpub_foralltables WITH (publish = 'insert,update'); CREATE TABLE testpub_tbl2 (id serial primary key, data text); -- fail - can't add to for all tables publication diff --git a/src/test/regress/sql/subscription.sql b/src/test/regress/sql/subscription.sql index b920446..0e0f042 100644 --- a/src/test/regress/sql/subscription.sql +++ b/src/test/regress/sql/subscription.sql @@ -15,27 +15,27 @@ CREATE SUBSCRIPTION testsub PUBLICATION foo; -- fail - cannot do CREATE SUBSCRIPTION CREATE SLOT inside transaction block BEGIN; -CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (CREATE SLOT); +CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub WITH (create_slot); COMMIT; -- fail - invalid connection string CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub; -- fail - duplicate publications -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION foo, testpub, foo WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION foo, testpub, foo WITH (connect = false); -- ok -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (connect = false); COMMENT ON SUBSCRIPTION testsub IS 'test subscription'; SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s; -- fail - name already exists -CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (connect = false); -- fail - must be superuser SET SESSION AUTHORIZATION 'regress_subscription_user2'; -CREATE SUBSCRIPTION testsub2 CONNECTION 'dbname=doesnotexist' PUBLICATION foo WITH (NOCONNECT); +CREATE SUBSCRIPTION testsub2 CONNECTION 'dbname=doesnotexist' PUBLICATION foo WITH (connect = false); SET SESSION AUTHORIZATION 'regress_subscription_user'; -- fail - invalid connection string @@ -43,9 +43,9 @@ ALTER SUBSCRIPTION testsub CONNECTION 'foobar'; \dRs+ -ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3 NOREFRESH; +ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3 SKIP REFRESH; ALTER SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist2'; -ALTER SUBSCRIPTION testsub WITH (SLOT NAME = 'newname'); +ALTER SUBSCRIPTION testsub WITH (slot_name = 'newname'); -- fail ALTER SUBSCRIPTION doesnotexist CONNECTION 'dbname=doesnotexist2'; @@ -69,8 +69,8 @@ ALTER SUBSCRIPTION testsub RENAME TO testsub_dummy; RESET ROLE; ALTER SUBSCRIPTION testsub RENAME TO testsub_foo; -ALTER SUBSCRIPTION testsub_foo WITH (SYNCHRONOUS_COMMIT = local); -ALTER SUBSCRIPTION testsub_foo WITH (SYNCHRONOUS_COMMIT = foobar); +ALTER SUBSCRIPTION testsub_foo WITH (synchronous_commit = local); +ALTER SUBSCRIPTION testsub_foo WITH (synchronous_commit = foobar); \dRs+ @@ -88,7 +88,7 @@ BEGIN; DROP SUBSCRIPTION testsub; COMMIT; -ALTER SUBSCRIPTION testsub WITH (SLOT NAME = NONE); +ALTER SUBSCRIPTION testsub WITH (slot_name = NONE); -- now it works BEGIN; diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl index 8e79fa3..50c4f4d 100644 --- a/src/test/subscription/t/001_rep_changes.pl +++ b/src/test/subscription/t/001_rep_changes.pl @@ -40,7 +40,7 @@ my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; $node_publisher->safe_psql('postgres', "CREATE PUBLICATION tap_pub"); $node_publisher->safe_psql('postgres', - "CREATE PUBLICATION tap_pub_ins_only WITH (nopublish delete, nopublish update)"); + "CREATE PUBLICATION tap_pub_ins_only WITH (publish = insert)"); $node_publisher->safe_psql('postgres', "ALTER PUBLICATION tap_pub ADD TABLE tab_rep, tab_full"); $node_publisher->safe_psql('postgres', @@ -136,7 +136,7 @@ $node_publisher->poll_query_until('postgres', $oldpid = $node_publisher->safe_psql('postgres', "SELECT pid FROM pg_stat_replication WHERE application_name = '$appname';"); $node_subscriber->safe_psql('postgres', - "ALTER SUBSCRIPTION tap_sub SET PUBLICATION tap_pub_ins_only REFRESH WITH (NOCOPY DATA)"); + "ALTER SUBSCRIPTION tap_sub SET PUBLICATION tap_pub_ins_only REFRESH WITH (copy_data = false)"); $node_publisher->poll_query_until('postgres', "SELECT pid != $oldpid FROM pg_stat_replication WHERE application_name = '$appname';") or die "Timed out while waiting for apply to restart"; @@ -159,13 +159,13 @@ is($result, qq(20|-20|-1), 'check changes skipped after subscription publication # check alter publication (relcache invalidation etc) $node_publisher->safe_psql('postgres', - "ALTER PUBLICATION tap_pub_ins_only WITH (publish delete)"); + "ALTER PUBLICATION tap_pub_ins_only WITH (publish = 'insert,delete')"); $node_publisher->safe_psql('postgres', "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_full"); $node_publisher->safe_psql('postgres', "DELETE FROM tab_ins WHERE a > 0"); $node_subscriber->safe_psql('postgres', - "ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION WITH (NOCOPY DATA)"); + "ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION WITH (copy_data = false)"); $node_publisher->safe_psql('postgres', "INSERT INTO tab_full VALUES(0)"); diff --git a/src/test/subscription/t/002_types.pl b/src/test/subscription/t/002_types.pl index ad15e85..e9368ab 100644 --- a/src/test/subscription/t/002_types.pl +++ b/src/test/subscription/t/002_types.pl @@ -103,7 +103,7 @@ $node_publisher->safe_psql('postgres', my $appname = 'tap_sub'; $node_subscriber->safe_psql('postgres', - "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (SLOT NAME = tap_sub_slot)"); + "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (slot_name = tap_sub_slot)"); # Wait for subscriber to finish initialization my $caughtup_query = diff --git a/src/test/subscription/t/003_constraints.pl b/src/test/subscription/t/003_constraints.pl index 11b8254..e906ea1 100644 --- a/src/test/subscription/t/003_constraints.pl +++ b/src/test/subscription/t/003_constraints.pl @@ -34,7 +34,7 @@ $node_publisher->safe_psql('postgres', my $appname = 'tap_sub'; $node_subscriber->safe_psql('postgres', - "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (NOCOPY DATA)"); + "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (copy_data = false)"); # Wait for subscriber to finish initialization my $caughtup_query = diff --git a/src/test/subscription/t/004_sync.pl b/src/test/subscription/t/004_sync.pl index fa0bf7f..8ece7dd 100644 --- a/src/test/subscription/t/004_sync.pl +++ b/src/test/subscription/t/004_sync.pl @@ -82,7 +82,7 @@ is($result, qq(20), 'initial data synced for second sub'); # now check another subscription for the same node pair $node_subscriber->safe_psql('postgres', - "CREATE SUBSCRIPTION tap_sub2 CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (NOCOPY DATA)"); + "CREATE SUBSCRIPTION tap_sub2 CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (copy_data = false)"); # wait for it to start $node_subscriber->poll_query_until('postgres', "SELECT pid IS NOT NULL FROM pg_stat_subscription WHERE subname = 'tap_sub2' AND relid IS NULL") -- 2.7.4

view thread (47+ messages)  latest in thread

Message-ID: <20856826-de0f-f630-4c67-36dca21037ad@2ndquadrant.com>
Permalink:  ../20856826-de0f-f630-4c67-36dca21037ad@2ndquadrant.com/
Also on:    postgresql.org/message-id/20856826-de0f-f630-4c67-36dca21037ad@2ndquadrant.com

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: petr.jelinek@2ndquadrant.com, peter.eisentraut@2ndquadrant.com, tgl@sss.pgh.pa.us, robertmhaas@gmail.com, michael.paquier@gmail.com
  Subject: Re: logical replication syntax (was DROP SUBSCRIPTION, query cancellations and slot handling)
  In-Reply-To: <20856826-de0f-f630-4c67-36dca21037ad@2ndquadrant.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox