Commit b807f598 authored by Peter Eisentraut's avatar Peter Eisentraut

Rework the options syntax for logical replication commands

For CREATE/ALTER PUBLICATION/SUBSCRIPTION, use similar option style as
other statements that use a WITH clause for options.

Author: Petr Jelinek <petr.jelinek@2ndquadrant.com>
parent 734cb4c2
......@@ -222,8 +222,9 @@
<listitem>
<para>
When creating a subscription, the replication slot already exists. In
that case, the subscription can be created using the <literal>NOCREATE
SLOT</literal> option to associate with the existing slot.
that case, the subscription can be created using
the <literal>create_slot = false</literal> option to associate with the
existing slot.
</para>
</listitem>
......@@ -231,7 +232,7 @@
<para>
When creating a subscription, the remote host is not reachable or in an
unclear state. In that case, the subscription can be created using
the <literal>NOCONNECT</literal> option. The remote host will then not
the <literal>connect = false</literal> option. The remote host will then not
be contacted at all. This is what <application>pg_dump</application>
uses. The remote replication slot will then have to be created
manually before the subscription can be activated.
......
......@@ -21,17 +21,10 @@ 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> 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> [ * ] [, ...]
ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> SET ( <replaceable class="parameter">publication_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )
ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER PUBLICATION <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
</synopsis>
......@@ -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,29 +72,24 @@ 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><replaceable class="parameter">table_name</replaceable></term>
<listitem>
<para>
These clauses alter properties originally set by
<xref linkend="SQL-CREATEPUBLICATION">. See there for more information.
Name of an existing table. If <literal>ONLY</> is specified before the
table name, only that table is affected. If <literal>ONLY</> is not
specified, the table and all its descendant tables (if any) are
affected. Optionally, <literal>*</> can be specified after the table
name to explicitly indicate that descendant tables are included.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">table_name</replaceable></term>
<term><literal>SET ( <replaceable class="parameter">publication_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term>
<listitem>
<para>
Name of an existing table. If <literal>ONLY</> is specified before the
table name, only that table is affected. If <literal>ONLY</> is not
specified, the table and all its descendant tables (if any) are
affected. Optionally, <literal>*</> can be specified after the table
name to explicitly indicate that descendant tables are included.
This clause alters publication parameters originally set by
<xref linkend="SQL-CREATEPUBLICATION">. See there for more information.
</para>
</listitem>
</varlistentry>
......@@ -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 SET (publish = 'update, delete');
</programlisting>
</para>
......
......@@ -21,23 +21,12 @@ 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> CONNECTION '<replaceable>conninfo</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> ENABLE
ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> DISABLE
ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> SET ( <replaceable class="parameter">subscription_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )
ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
</synopsis>
......@@ -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 alters the connection property originally set by
<xref linkend="SQL-CREATESUBSCRIPTION">. See there for more
information.
</para>
......@@ -91,11 +78,17 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO <
Changes list of subscribed publications. See
<xref linkend="SQL-CREATESUBSCRIPTION"> for more information.
</para>
<para>
When <literal>REFRESH</literal> is specified, this command will also
act like <literal>REFRESH PUBLICATION</literal>. When
<literal>NOREFRESH</literal> is specified, the comamnd will not try to
refresh table information.
When <literal>REFRESH</literal> is specified, this command will also act
like <literal>REFRESH
PUBLICATION</literal>. <literal>refresh_option</literal> specifies
additional options for the refresh operation, as described
under <literal>REFRESH PUBLICATION</literal>. When
<literal>SKIP REFRESH</literal> is specified, the command will not try
to refresh table information. Note that
either <literal>REFRESH</literal> or <literal>SKIP REFRESH</literal>
must be specified.
</para>
</listitem>
</varlistentry>
......@@ -104,16 +97,28 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO <
<term><literal>REFRESH PUBLICATION</literal></term>
<listitem>
<para>
Fetch missing table information from publisher. This will start
Fetch missing table information from publisher. This will start
replication of tables that were added to the subscribed-to publications
since the last invocation of <command>REFRESH PUBLICATION</command> or
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.
<literal>refresh_option</literal> specifies additional options for the
refresh operation. The supported options are:
<variablelist>
<varlistentry>
<term><literal>copy_data</literal> (<type>boolean</type>)</term>
<listitem>
<para>
Specifies whether 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>
</para>
</listitem>
</varlistentry>
......@@ -138,6 +143,18 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO <
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SET ( <replaceable class="parameter">subscription_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term>
<listitem>
<para>
This clause alters parameters 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><replaceable class="parameter">new_owner</replaceable></term>
<listitem>
......@@ -165,7 +182,7 @@ ALTER SUBSCRIPTION <replaceable class="PARAMETER">name</replaceable> RENAME TO <
Change the publication subscribed by a subscription to
<literal>insert_only</literal>:
<programlisting>
ALTER SUBSCRIPTION mysub SET PUBLICATION insert_only;
ALTER SUBSCRIPTION mysub SET PUBLICATION insert_only REFRESH;
</programlisting>
</para>
......
......@@ -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_parameter</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_parameter</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 publication. The
following parameters are supported:
<variablelist>
<varlistentry>
<term><literal>publish</literal> (<type>string</type>)</term>
<listitem>
<para>
This parameter determines which DML operations will be published by
the new publication to the subscribers. The value is
comma-separated list of operations. The allowed operations are
<literal>insert</literal>, <literal>update</literal>, and
<literal>delete</literal>. The default is to publish all actions,
and 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>
......
......@@ -23,17 +23,8 @@ PostgreSQL documentation
<synopsis>
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
PUBLICATION <replaceable class="PARAMETER">publication_name</replaceable> [, ...]
[ WITH ( <replaceable class="parameter">subscription_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ]
</synopsis>
</refsynopsisdiv>
......@@ -59,7 +50,7 @@ CREATE SUBSCRIPTION <replaceable class="PARAMETER">subscription_name</replaceabl
<para>
<command>CREATE SUBSCRIPTION</command> cannot be executed inside a
transaction block when <literal>CREATE SLOT</literal> is specified.
transaction block when the parameter <literal>create_slot</literal> is specified.
</para>
<para>
......@@ -97,116 +88,129 @@ CREATE SUBSCRIPTION <replaceable class="PARAMETER">subscription_name</replaceabl
<term><literal>PUBLICATION <replaceable class="parameter">publication_name</replaceable></literal></term>
<listitem>
<para>
Name(s) of the publications on the publisher to subscribe to.
</para>
</listitem>
</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>
<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.
Names of the publications on the publisher to subscribe to.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SYNCHRONOUS_COMMIT = <replaceable class="PARAMETER">synchronous_commit</replaceable></literal></term>
<term><literal>WITH ( <replaceable class="parameter">subscription_parameter</replaceable> [= <replaceable class="parameter">value</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>copy_data</literal> (<type>boolean</type>)</term>
<listitem>
<para>
Specifies whether 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>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>enabled</literal> (<type>boolean</type>)</term>
<listitem>
<para>
Specifies whether the subscription should be actively replicating,
or whether it should be just setup but not started yet. 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 the name of the subscription for the 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>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>
Specifies whether the <command>CREATE SUBSCRIPTION</command>
should connect to the publisher at all. 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 is 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>
set to <literal>true</literal>.
</para>
<para>
Since no connection is made when this option is specified, the
tables are not subscribed, and 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 +250,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>
......
......@@ -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,68 +78,54 @@ 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")));
*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")));
errmsg("invalid publish list")));
*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
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized \"publish\" value: \"%s\"", publish_opt)));
}
}
else
elog(ERROR, "unrecognized option: %s", defel->defname);
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized publication parameter: %s", defel->defname)));
}
}
......@@ -158,9 +141,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 +180,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,40 +233,30 @@ 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);
/* 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)
if (publish_given)
{
values[Anum_pg_publication_pubinsert - 1] =
BoolGetDatum(publish_insert);
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);
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);
values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(publish_delete);
replaces[Anum_pg_publication_pubdelete - 1] = true;
}
......
......@@ -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 ... WITH (create_slot = true)");
if (!superuser())
ereport(ERROR,
......
......@@ -338,7 +338,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
database_name access_method_clause access_method attr_name
name cursor_name file_name
index_name opt_index_name cluster_index_specification
def_key
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
opt_class opt_inline_handler opt_validator validator_clause
......@@ -652,7 +651,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
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
NULLS_P NUMERIC
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
......@@ -5673,21 +5672,16 @@ def_list: def_elem { $$ = list_make1($1); }
| def_list ',' def_elem { $$ = lappend($1, $3); }
;
def_elem: def_key '=' def_arg
def_elem: ColLabel '=' def_arg
{
$$ = makeDefElem($1, (Node *) $3, @1);
}
| def_key
| ColLabel
{
$$ = makeDefElem($1, NULL, @1);
}
;
def_key:
ColLabel { $$ = $1; }
| ColLabel ColLabel { $$ = psprintf("%s %s", $1, $2); }
;
/* Note: any simple identifier will be returned as a type name! */
def_arg: func_type { $$ = (Node *)$1; }
| reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); }
......@@ -9173,9 +9167,10 @@ publication_for_tables:
}
;
/*****************************************************************************
*
* ALTER PUBLICATION name [ WITH ] options
* ALTER PUBLICATION name SET ( options )
*
* ALTER PUBLICATION name ADD TABLE table [, table2]
*
......@@ -9186,7 +9181,7 @@ publication_for_tables:
*****************************************************************************/
AlterPublicationStmt:
ALTER PUBLICATION name WITH definition
ALTER PUBLICATION name SET definition
{
AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
n->pubname = $3;
......@@ -9254,12 +9249,12 @@ publication_name_item:
/*****************************************************************************
*
* ALTER SUBSCRIPTION name [ WITH ] options
* ALTER SUBSCRIPTION name ...
*
*****************************************************************************/
AlterSubscriptionStmt:
ALTER SUBSCRIPTION name WITH definition
ALTER SUBSCRIPTION name SET definition
{
AlterSubscriptionStmt *n =
makeNode(AlterSubscriptionStmt);
......@@ -9296,7 +9291,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 +14753,6 @@ unreserved_keyword:
| NEW
| NEXT
| NO
| NOREFRESH
| NOTHING
| NOTIFY
| NOWAIT
......
......@@ -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)
appendPQExpBufferStr(query, ", ");
if (pubinfo->pubupdate)
appendPQExpBufferStr(query, ", PUBLISH UPDATE");
else
appendPQExpBufferStr(query, ", NOPUBLISH UPDATE");
{
appendPQExpBufferStr(query, "update");
first = false;
}
if (!first)
appendPQExpBufferStr(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");
......
......@@ -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,
......
......@@ -1504,28 +1504,27 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_LIST6("WITH (", "ADD TABLE", "SET TABLE", "DROP TABLE",
"OWNER TO", "RENAME TO");
}
/* ALTER PUBLICATION <name> .. WITH ( ... */
else if (HeadMatches3("ALTER", "PUBLICATION",MatchAny) && TailMatches2("WITH", "("))
/* ALTER PUBLICATION <name> .. SET ( ... */
else if (HeadMatches3("ALTER", "PUBLICATION",MatchAny) && TailMatches2("SET", "("))
{
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))
{
COMPLETE_WITH_LIST8("WITH (", "CONNECTION", "SET PUBLICATION", "ENABLE",
COMPLETE_WITH_LIST8("SET (", "CONNECTION", "SET PUBLICATION", "ENABLE",
"DISABLE", "OWNER TO", "RENAME TO", "REFRESH PUBLICATION WITH (");
}
/* ALTER SUBSCRIPTION <name> REFRESH PUBLICATION WITH ( ... */
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", "("))
/* ALTER SUBSCRIPTION <name> .. SET ( ... */
else if (HeadMatches3("ALTER", "SUBSCRIPTION", MatchAny) && TailMatches2("SET", "("))
{
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 */
......
......@@ -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)
......
......@@ -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';
......
......@@ -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';
......
......@@ -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
......
......@@ -13,8 +13,13 @@ 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 SET (publish = update);
-- error cases
CREATE PUBLICATION testpub_xxx WITH (foo);
ERROR: unrecognized publication parameter: foo
CREATE PUBLICATION testpub_xxx WITH (publish = 'cluster, vacuum');
ERROR: unrecognized "publish" value: "cluster"
\dRp
List of publications
Name | Owner | Inserts | Updates | Deletes
......@@ -23,7 +28,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 SET (publish = 'insert, update, delete');
\dRp
List of publications
Name | Owner | Inserts | Updates | Deletes
......@@ -38,8 +43,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 SET (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;
......
......@@ -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 ... WITH (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 SET (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 SET (synchronous_commit = local);
ALTER SUBSCRIPTION testsub_foo SET (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 SET (slot_name = NONE);
-- now it works
BEGIN;
DROP SUBSCRIPTION testsub;
......
......@@ -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
......
......@@ -11,13 +11,17 @@ 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 SET (publish = update);
-- error cases
CREATE PUBLICATION testpub_xxx WITH (foo);
CREATE PUBLICATION testpub_xxx WITH (publish = 'cluster, vacuum');
\dRp
ALTER PUBLICATION testpub_default WITH (publish insert, publish delete);
ALTER PUBLICATION testpub_default SET (publish = 'insert, update, delete');
\dRp
......@@ -28,8 +32,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 SET (publish = 'insert, update');
CREATE TABLE testpub_tbl2 (id serial primary key, data text);
-- fail - can't add to for all tables publication
......
......@@ -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 SET (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 SET (synchronous_commit = local);
ALTER SUBSCRIPTION testsub_foo SET (synchronous_commit = foobar);
\dRs+
......@@ -88,7 +88,7 @@ BEGIN;
DROP SUBSCRIPTION testsub;
COMMIT;
ALTER SUBSCRIPTION testsub WITH (SLOT NAME = NONE);
ALTER SUBSCRIPTION testsub SET (slot_name = NONE);
-- now it works
BEGIN;
......
......@@ -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 SET (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)");
......
......@@ -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 =
......
......@@ -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 =
......
......@@ -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")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment