<refsynopsisdiv>
<synopsis>
ALTER PUBLICATION <replaceable class="parameter">name</replaceable> ADD <replaceable class="parameter">publication_object</replaceable> [, ...]
-ALTER PUBLICATION <replaceable class="parameter">name</replaceable> SET <replaceable class="parameter">publication_object</replaceable> [, ...]
ALTER PUBLICATION <replaceable class="parameter">name</replaceable> DROP <replaceable class="parameter">publication_drop_object</replaceable> [, ...]
+ALTER PUBLICATION <replaceable class="parameter">name</replaceable> SET { <replaceable class="parameter">publication_object</replaceable> [, ...] | <replaceable class="parameter">publication_all_object</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_ROLE | CURRENT_USER | SESSION_USER }
ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
TABLE <replaceable class="parameter">table_and_columns</replaceable> [, ... ]
TABLES IN SCHEMA { <replaceable class="parameter">schema_name</replaceable> | CURRENT_SCHEMA } [, ... ]
+<phrase>and <replaceable class="parameter">publication_all_object</replaceable> is one of:</phrase>
+
+ ALL TABLES [ EXCEPT TABLE ( <replaceable class="parameter">except_table_object</replaceable> [, ... ] ) ]
+ ALL SEQUENCES
+
<phrase>and <replaceable class="parameter">publication_drop_object</replaceable> is one of:</phrase>
TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ] [, ... ]
<phrase>and <replaceable class="parameter">table_and_columns</replaceable> is:</phrase>
[ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ] [ ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) ] [ WHERE ( <replaceable class="parameter">expression</replaceable> ) ]
+
+<phrase>and <replaceable class="parameter">except_table_object</replaceable> is:</phrase>
+
+ [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ]
</synopsis>
</refsynopsisdiv>
</para>
<para>
- The first three variants change which tables/schemas are part of the
- publication. The <literal>SET</literal> clause will replace the list of
- tables/schemas in the publication with the specified list; the existing
- tables/schemas that were present in the publication will be removed. The
- <literal>ADD</literal> and <literal>DROP</literal> clauses will add and
- remove one or more tables/schemas from the publication. Note that adding
- tables/schemas to a publication that is already subscribed to will require an
+ The first two variants modify which tables/schemas are part of the
+ publication. The <literal>ADD</literal> and <literal>DROP</literal> clauses
+ will add and remove one or more tables/schemas from the publication.
+ </para>
+
+ <para>
+ The third variant either modifies the included tables/schemas
+ or marks the publication as <literal>FOR ALL SEQUENCES</literal> or
+ <literal>FOR ALL TABLES</literal>, optionally using
+ <literal>EXCEPT TABLE</literal> to exclude specific tables. The
+ <literal>SET ALL TABLES</literal> clause can transform an empty publication,
+ or one defined for <literal>ALL SEQUENCES</literal> (or both
+ <literal>ALL TABLES</literal> and <literal>ALL SEQUENCES</literal>), into
+ a publication defined for ALL TABLES. Likewise,
+ <literal>SET ALL SEQUENCES</literal> can convert an empty publication, or
+ one defined for <literal>ALL TABLES</literal> (or both
+ <literal>ALL TABLES</literal> and <literal>ALL SEQUENCES</literal>), into a
+ publication defined for <literal>ALL SEQUENCES</literal>. In addition,
+ <literal>SET ALL TABLES</literal> can be used to update the
+ <literal>EXCEPT TABLE</literal> list of a <literal>FOR ALL TABLES</literal>
+ publication. If <literal>EXCEPT TABLE</literal> is specified with a list of
+ tables, the existing exclusion list is replaced with the specified tables.
+ If <literal>EXCEPT TABLE</literal> is omitted, the existing exclusion list
+ is cleared. The <literal>SET</literal> clause, when used with a publication
+ defined with <literal>FOR TABLE</literal> or
+ <literal>FOR TABLES IN SCHEMA</literal>, replaces the list of tables/schemas
+ in the publication with the specified list; the existing tables or schemas
+ that were present in the publication will be removed.
+ </para>
+
+ <para>
+ Note that adding tables/except tables/schemas to a publication that is
+ already subscribed to will require an
<link linkend="sql-altersubscription-params-refresh-publication">
- <literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal></link> action on the
- subscribing side in order to become effective. Note also that
- <literal>DROP TABLES IN SCHEMA</literal> will not drop any schema tables
- that were specified using
+ <literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal></link> action
+ on the subscribing side in order to become effective. Likewise altering a
+ publication to set <literal>ALL TABLES</literal> or to set or unset
+ <literal>ALL SEQUENCES</literal> also requires the subscriber to refresh the
+ publication. Note also that <literal>DROP TABLES IN SCHEMA</literal> will
+ not drop any schema tables that were specified using
<link linkend="sql-createpublication-params-for-table"><literal>FOR TABLE</literal></link>/
<literal>ADD TABLE</literal>.
</para>
<para>
You must own the publication to use <command>ALTER PUBLICATION</command>.
Adding a table to a publication additionally requires owning that table.
- The <literal>ADD TABLES IN SCHEMA</literal> and
- <literal>SET TABLES IN SCHEMA</literal> to a publication requires the
+ The <literal>ADD TABLES IN SCHEMA</literal>,
+ <literal>SET TABLES IN SCHEMA</literal>, <literal>SET ALL TABLES</literal>,
+ and <literal>SET ALL SEQUENCES</literal> to a publication requires the
invoking user to be a superuser.
To alter the owner, you must be able to <literal>SET ROLE</literal> to the
new owning role, and that role must have <literal>CREATE</literal>
Change the set of columns published for a table:
<programlisting>
ALTER PUBLICATION mypublication SET TABLE users (user_id, firstname, lastname), TABLE departments;
+</programlisting></para>
+
+ <para>
+ Replace the publication's EXCEPT TABLE list:
+<programlisting>
+ALTER PUBLICATION mypublication SET ALL TABLES EXCEPT TABLE (users, departments);
+</programlisting></para>
+
+ <para>
+ Reset the publication to be a FOR ALL TABLES publication with no excluded
+ tables:
+<programlisting>
+ALTER PUBLICATION mypublication SET ALL TABLES;
</programlisting></para>
<para>
return result;
}
+/*
+ * Returns true if the publication has explicitly included relation (i.e.,
+ * not marked as EXCEPT).
+ */
+bool
+is_table_publication(Oid pubid)
+{
+ Relation pubrelsrel;
+ ScanKeyData scankey;
+ SysScanDesc scan;
+ HeapTuple tup;
+ bool result = false;
+
+ pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock);
+ ScanKeyInit(&scankey,
+ Anum_pg_publication_rel_prpubid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(pubid));
+
+ scan = systable_beginscan(pubrelsrel,
+ PublicationRelPrpubidIndexId,
+ true, NULL, 1, &scankey);
+ tup = systable_getnext(scan);
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_publication_rel pubrel;
+
+ pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
+
+ /*
+ * For any publication, pg_publication_rel contains either only EXCEPT
+ * entries or only explicitly included tables. Therefore, examining
+ * the first tuple is sufficient to determine table inclusion.
+ */
+ result = !pubrel->prexcept;
+ }
+
+ systable_endscan(scan);
+ table_close(pubrelsrel, AccessShareLock);
+
+ return result;
+}
+
/*
* Returns true if the relation has column list associated with the
* publication, false otherwise.
*/
ObjectAddress
publication_add_relation(Oid pubid, PublicationRelInfo *pri,
- bool if_not_exists)
+ bool if_not_exists, AlterPublicationStmt *alter_stmt)
{
Relation rel;
HeapTuple tup;
referenced;
List *relids = NIL;
int i;
+ bool inval_except_table;
rel = table_open(PublicationRelRelationId, RowExclusiveLock);
table_close(rel, RowExclusiveLock);
/*
- * Relations excluded via the EXCEPT clause do not need explicit
- * invalidation as CreatePublication() function invalidates all relations
- * as part of defining a FOR ALL TABLES publication.
+ * Determine whether EXCEPT tables require explicit relcache invalidation.
+ *
+ * For CREATE PUBLICATION with EXCEPT tables, invalidation is skipped
+ * here, as CreatePublication() function invalidates all relations as part
+ * of defining a FOR ALL TABLES publication.
+ *
+ * For ALTER PUBLICATION, invalidation is needed only when adding an
+ * EXCEPT table to a publication already marked as ALL TABLES. For
+ * publications that were originally empty or defined as ALL SEQUENCES and
+ * are being converted to ALL TABLES, invalidation is skipped here, as
+ * AlterPublicationAllFlags() function invalidates all relations while
+ * marking the publication as ALL TABLES publication.
*/
- if (!pri->except)
+ inval_except_table = (alter_stmt != NULL) && pub->alltables &&
+ (alter_stmt->for_all_tables && pri->except);
+
+ if (!pri->except || inval_except_table)
{
/*
* Invalidate relcache so that publication info is rebuilt.
PublicationDropTables(pubid, rels, false);
else /* AP_SetObjects */
{
- List *oldrelids = GetIncludedPublicationRelations(pubid,
- PUBLICATION_PART_ROOT);
+ List *oldrelids = NIL;
List *delrels = NIL;
ListCell *oldlc;
- TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
+ if (stmt->for_all_tables || stmt->for_all_sequences)
+ {
+ /*
+ * In FOR ALL TABLES mode, relations are tracked as exclusions
+ * (EXCEPT TABLES). Fetch the current excluded relations so they
+ * can be reconciled with the specified EXCEPT list.
+ *
+ * This applies only if the existing publication is already
+ * defined as FOR ALL TABLES; otherwise, there are no exclusion
+ * entries to process.
+ */
+ if (pubform->puballtables)
+ {
+ oldrelids = GetExcludedPublicationTables(pubid,
+ PUBLICATION_PART_ROOT);
+ }
+ }
+ else
+ {
+ oldrelids = GetIncludedPublicationRelations(pubid,
+ PUBLICATION_PART_ROOT);
- CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
- pubform->pubviaroot);
+ TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
+
+ CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
+ pubform->pubviaroot);
+ }
/*
* To recreate the relation list for the publication, look for
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to add or set schemas")));
+ if (stmt->for_all_tables && !superuser())
+ ereport(ERROR,
+ errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to set ALL TABLES"));
+
+ if (stmt->for_all_sequences && !superuser())
+ ereport(ERROR,
+ errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to set ALL SEQUENCES"));
+
/*
* Check that user is allowed to manipulate the publication tables in
* schema
NameStr(pubform->pubname)),
errdetail("Tables or sequences cannot be added to or dropped from FOR ALL SEQUENCES publications."));
}
+
+ if (stmt->for_all_tables || stmt->for_all_sequences)
+ {
+ /*
+ * If the publication already contains specific tables or schemas, we
+ * prevent switching to a ALL state.
+ */
+ if (is_table_publication(pubform->oid) ||
+ is_schema_publication(pubform->oid))
+ {
+ ereport(ERROR,
+ errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ stmt->for_all_tables ?
+ errmsg("publication \"%s\" does not support ALL TABLES operations", NameStr(pubform->pubname)) :
+ errmsg("publication \"%s\" does not support ALL SEQUENCES operations", NameStr(pubform->pubname)),
+ errdetail("This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty."));
+ }
+ }
+}
+
+/*
+ * Update FOR ALL TABLES / FOR ALL SEQUENCES flags of a publication.
+ */
+static void
+AlterPublicationAllFlags(AlterPublicationStmt *stmt, Relation rel,
+ HeapTuple tup)
+{
+ Form_pg_publication pubform;
+ bool nulls[Natts_pg_publication] = {0};
+ bool replaces[Natts_pg_publication] = {0};
+ Datum values[Natts_pg_publication] = {0};
+ bool dirty = false;
+
+ if (!stmt->for_all_tables && !stmt->for_all_sequences)
+ return;
+
+ pubform = (Form_pg_publication) GETSTRUCT(tup);
+
+ /* Update FOR ALL TABLES flag if changed */
+ if (stmt->for_all_tables != pubform->puballtables)
+ {
+ values[Anum_pg_publication_puballtables - 1] =
+ BoolGetDatum(stmt->for_all_tables);
+ replaces[Anum_pg_publication_puballtables - 1] = true;
+ dirty = true;
+ }
+
+ /* Update FOR ALL SEQUENCES flag if changed */
+ if (stmt->for_all_sequences != pubform->puballsequences)
+ {
+ values[Anum_pg_publication_puballsequences - 1] =
+ BoolGetDatum(stmt->for_all_sequences);
+ replaces[Anum_pg_publication_puballsequences - 1] = true;
+ dirty = true;
+ }
+
+ if (dirty)
+ {
+ tup = heap_modify_tuple(tup, RelationGetDescr(rel), values,
+ nulls, replaces);
+ CatalogTupleUpdate(rel, &tup->t_self, tup);
+ CommandCounterIncrement();
+
+ /* For ALL TABLES, we must invalidate all relcache entries */
+ if (replaces[Anum_pg_publication_puballtables - 1])
+ CacheInvalidateRelcacheAll();
+ }
}
/*
ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
&exceptrelations, &schemaidlist);
- /* EXCEPT clause is not supported with ALTER PUBLICATION */
- Assert(exceptrelations == NIL);
-
CheckAlterPublication(stmt, tup, relations, schemaidlist);
heap_freetuple(tup);
errmsg("publication \"%s\" does not exist",
stmt->pubname));
+ relations = list_concat(relations, exceptrelations);
AlterPublicationTables(stmt, tup, relations, pstate->p_sourcetext,
schemaidlist != NIL);
AlterPublicationSchemas(stmt, tup, schemaidlist);
+ AlterPublicationAllFlags(stmt, rel, tup);
}
/* Cleanup. */
aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind),
RelationGetRelationName(rel));
- obj = publication_add_relation(pubid, pub_rel, if_not_exists);
+ obj = publication_add_relation(pubid, pub_rel, if_not_exists, stmt);
if (stmt)
{
EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress,
list_length(exceptpuboids),
RelationGetRelationName(attachrel),
pubnames.data),
- errdetail("The publication EXCEPT clause cannot contain tables that are partitions."));
+ errdetail("The publication EXCEPT clause cannot contain tables that are partitions."),
+ errhint("Change the publication's EXCEPT clause using ALTER PUBLICATION ... SET ALL TABLES."));
}
list_free(exceptpuboids);
*
* ALTER PUBLICATION name SET pub_obj [, ...]
*
+ * ALTER PUBLICATION name SET pub_all_obj_type [, ...]
+ *
* pub_obj is one of:
*
* TABLE table_name [, ...]
* TABLES IN SCHEMA schema_name [, ...]
*
+ * pub_all_obj_type is one of:
+ *
+ * ALL TABLES [ EXCEPT TABLE ( table_name [, ...] ) ]
+ * ALL SEQUENCES
+ *
*****************************************************************************/
AlterPublicationStmt:
n->pubname = $3;
n->options = $5;
+ n->for_all_tables = false;
$$ = (Node *) n;
}
| ALTER PUBLICATION name ADD_P pub_obj_list
n->pubobjects = $5;
preprocess_pubobj_list(n->pubobjects, yyscanner);
n->action = AP_AddObjects;
+ n->for_all_tables = false;
$$ = (Node *) n;
}
| ALTER PUBLICATION name SET pub_obj_list
n->pubobjects = $5;
preprocess_pubobj_list(n->pubobjects, yyscanner);
n->action = AP_SetObjects;
+ n->for_all_tables = false;
+ $$ = (Node *) n;
+ }
+ | ALTER PUBLICATION name SET pub_all_obj_type_list
+ {
+ AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
+
+ n->pubname = $3;
+ n->action = AP_SetObjects;
+ preprocess_pub_all_objtype_list($5, &n->pubobjects,
+ &n->for_all_tables,
+ &n->for_all_sequences,
+ yyscanner);
$$ = (Node *) n;
}
| ALTER PUBLICATION name DROP pub_obj_list
n->pubobjects = $5;
preprocess_pubobj_list(n->pubobjects, yyscanner);
n->action = AP_DropObjects;
+ n->for_all_tables = false;
$$ = (Node *) n;
}
;
COMPLETE_WITH("TABLES IN SCHEMA", "TABLE");
/* ALTER PUBLICATION <name> SET */
else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET"))
- COMPLETE_WITH("(", "TABLES IN SCHEMA", "TABLE");
+ COMPLETE_WITH("(", "ALL SEQUENCES", "ALL TABLES", "TABLES IN SCHEMA", "TABLE");
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "ALL"))
+ COMPLETE_WITH("SEQUENCES", "TABLES");
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "ALL", "TABLES"))
+ COMPLETE_WITH("EXCEPT TABLE (");
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "ALL", "TABLES", "EXCEPT"))
+ COMPLETE_WITH("TABLE (");
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "ALL", "TABLES", "EXCEPT", "TABLE"))
+ COMPLETE_WITH("(");
+ /* Complete "ALTER PUBLICATION <name> FOR TABLE" with "<table>, ..." */
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "ALL", "TABLES", "EXCEPT", "TABLE", "("))
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD|DROP|SET", "TABLES", "IN", "SCHEMA"))
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_schemas
" AND nspname NOT LIKE E'pg\\\\_%%'",
extern bool is_publishable_relation(Relation rel);
extern bool is_schema_publication(Oid pubid);
+extern bool is_table_publication(Oid pubid);
extern bool check_and_fetch_column_list(Publication *pub, Oid relid,
MemoryContext mcxt, Bitmapset **cols);
extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri,
- bool if_not_exists);
+ bool if_not_exists,
+ AlterPublicationStmt *alter_stmt);
extern Bitmapset *pub_collist_validate(Relation targetrel, List *columns);
extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid,
bool if_not_exists);
List *pubobjects; /* Optional list of publication objects */
AlterPublicationAction action; /* What action to perform with the given
* objects */
+ bool for_all_tables; /* True if ALL TABLES is specified */
+ bool for_all_sequences; /* True if ALL SEQUENCES is specified */
} AlterPublicationStmt;
typedef struct CreateSubscriptionStmt
"testpub_foralltables_excepttable"
"testpub_foralltables_excepttable1"
+---------------------------------------------
+-- SET ALL TABLES/SEQUENCES
+---------------------------------------------
+-- Replace the existing EXCEPT TABLE list (testpub_tbl1) with a new
+-- EXCEPT TABLE list containing only (testpub_tbl2).
+ALTER PUBLICATION testpub_foralltables_excepttable SET ALL TABLES EXCEPT TABLE (testpub_tbl2);
+\dRp+ testpub_foralltables_excepttable
+ Publication testpub_foralltables_excepttable
+ Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | t | f | t | t | t | t | none | f |
+Except tables:
+ "public.testpub_tbl2"
+
+-- Clear the EXCEPT TABLE list, making the publication include all tables.
+ALTER PUBLICATION testpub_foralltables_excepttable SET ALL TABLES;
+\dRp+ testpub_foralltables_excepttable
+ Publication testpub_foralltables_excepttable
+ Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | t | f | t | t | t | t | none | f |
+(1 row)
+
+-- Create an empty publication for subsequent tests.
+CREATE PUBLICATION testpub_forall_tbls_seqs;
+-- Enable both puballtables and puballsequences
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL TABLES, ALL SEQUENCES;
+\dRp+ testpub_forall_tbls_seqs
+ Publication testpub_forall_tbls_seqs
+ Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | t | t | t | t | t | t | none | f |
+(1 row)
+
+-- Explicitly test that SET ALL TABLES resets puballsequences to false
+-- Result should be: puballtables = true, puballsequences = false
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL TABLES;
+\dRp+ testpub_forall_tbls_seqs
+ Publication testpub_forall_tbls_seqs
+ Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | t | f | t | t | t | t | none | f |
+(1 row)
+
+-- Explicitly test that SET ALL SEQUENCES resets puballtables to false
+-- Result should be: puballtables = false, puballsequences = true
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL SEQUENCES;
+\dRp+ testpub_forall_tbls_seqs
+ Publication testpub_forall_tbls_seqs
+ Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root | Description
+--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+----------+-------------
+ regress_publication_user | f | t | t | t | t | t | none | f |
+(1 row)
+
+-- fail - SET ALL TABLES/SEQUENCES is not allowed for a 'FOR TABLE' publication
+ALTER PUBLICATION testpub_fortable SET ALL TABLES EXCEPT TABLE (testpub_tbl1);
+ERROR: publication "testpub_fortable" does not support ALL TABLES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
+ALTER PUBLICATION testpub_fortable SET ALL TABLES;
+ERROR: publication "testpub_fortable" does not support ALL TABLES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
+ALTER PUBLICATION testpub_fortable SET ALL SEQUENCES;
+ERROR: publication "testpub_fortable" does not support ALL SEQUENCES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
+-- fail - SET ALL TABLES/SEQUENCES is not allowed for a schema publication
+ALTER PUBLICATION testpub_forschema SET ALL TABLES EXCEPT TABLE (pub_test.testpub_nopk);
+ERROR: publication "testpub_forschema" does not support ALL TABLES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
+ALTER PUBLICATION testpub_forschema SET ALL TABLES;
+ERROR: publication "testpub_forschema" does not support ALL TABLES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
+ALTER PUBLICATION testpub_forschema SET ALL SEQUENCES;
+ERROR: publication "testpub_forschema" does not support ALL SEQUENCES operations
+DETAIL: This operation requires the publication to be defined as FOR ALL TABLES/SEQUENCES or to be empty.
RESET client_min_messages;
DROP TABLE testpub_tbl2;
-DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema, testpub_foralltables_excepttable, testpub_foralltables_excepttable1;
+DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema;
+DROP PUBLICATION testpub_forall_tbls_seqs, testpub_foralltables_excepttable, testpub_foralltables_excepttable1;
---------------------------------------------
-- Tests for inherited tables, and
-- EXCEPT TABLE tests for inherited tables
ALTER TABLE tab_main ATTACH PARTITION testpub_root FOR VALUES FROM (0) TO (200);
ERROR: cannot attach table "testpub_root" as partition because it is referenced in publication "testpub8" EXCEPT clause
DETAIL: The publication EXCEPT clause cannot contain tables that are partitions.
+HINT: Change the publication's EXCEPT clause using ALTER PUBLICATION ... SET ALL TABLES.
RESET client_min_messages;
DROP TABLE testpub_root, testpub_part1, tab_main;
DROP PUBLICATION testpub8;
HINT: The owner of a FOR ALL TABLES or ALL SEQUENCES or TABLES IN SCHEMA publication must be a superuser.
ALTER PUBLICATION testpub4 owner to regress_publication_user; -- ok
SET ROLE regress_publication_user;
-DROP PUBLICATION testpub4;
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION testpub5 FOR ALL TABLES;
+RESET client_min_messages;
+ALTER PUBLICATION testpub5 OWNER TO regress_publication_user3;
+SET ROLE regress_publication_user3;
+-- fail - SET ALL TABLES/SEQUENCES on a publication requires superuser privileges
+ALTER PUBLICATION testpub5 SET ALL TABLES EXCEPT TABLE (testpub_tbl1); -- fail
+ERROR: must be superuser to set ALL TABLES
+ALTER PUBLICATION testpub5 SET ALL TABLES; -- fail
+ERROR: must be superuser to set ALL TABLES
+ALTER PUBLICATION testpub5 SET ALL SEQUENCES; -- fail
+ERROR: must be superuser to set ALL SEQUENCES
+SET ROLE regress_publication_user;
+DROP PUBLICATION testpub4, testpub5;
DROP ROLE regress_publication_user3;
REVOKE CREATE ON DATABASE regression FROM regress_publication_user2;
DROP TABLE testpub_parted;
-- in the EXCEPT TABLE clause
\d testpub_tbl1
+---------------------------------------------
+-- SET ALL TABLES/SEQUENCES
+---------------------------------------------
+-- Replace the existing EXCEPT TABLE list (testpub_tbl1) with a new
+-- EXCEPT TABLE list containing only (testpub_tbl2).
+ALTER PUBLICATION testpub_foralltables_excepttable SET ALL TABLES EXCEPT TABLE (testpub_tbl2);
+\dRp+ testpub_foralltables_excepttable
+
+-- Clear the EXCEPT TABLE list, making the publication include all tables.
+ALTER PUBLICATION testpub_foralltables_excepttable SET ALL TABLES;
+\dRp+ testpub_foralltables_excepttable
+
+-- Create an empty publication for subsequent tests.
+CREATE PUBLICATION testpub_forall_tbls_seqs;
+
+-- Enable both puballtables and puballsequences
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL TABLES, ALL SEQUENCES;
+\dRp+ testpub_forall_tbls_seqs
+
+-- Explicitly test that SET ALL TABLES resets puballsequences to false
+-- Result should be: puballtables = true, puballsequences = false
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL TABLES;
+\dRp+ testpub_forall_tbls_seqs
+
+-- Explicitly test that SET ALL SEQUENCES resets puballtables to false
+-- Result should be: puballtables = false, puballsequences = true
+ALTER PUBLICATION testpub_forall_tbls_seqs SET ALL SEQUENCES;
+\dRp+ testpub_forall_tbls_seqs
+
+-- fail - SET ALL TABLES/SEQUENCES is not allowed for a 'FOR TABLE' publication
+ALTER PUBLICATION testpub_fortable SET ALL TABLES EXCEPT TABLE (testpub_tbl1);
+ALTER PUBLICATION testpub_fortable SET ALL TABLES;
+ALTER PUBLICATION testpub_fortable SET ALL SEQUENCES;
+
+-- fail - SET ALL TABLES/SEQUENCES is not allowed for a schema publication
+ALTER PUBLICATION testpub_forschema SET ALL TABLES EXCEPT TABLE (pub_test.testpub_nopk);
+ALTER PUBLICATION testpub_forschema SET ALL TABLES;
+ALTER PUBLICATION testpub_forschema SET ALL SEQUENCES;
+
RESET client_min_messages;
DROP TABLE testpub_tbl2;
-DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema, testpub_foralltables_excepttable, testpub_foralltables_excepttable1;
+DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema;
+DROP PUBLICATION testpub_forall_tbls_seqs, testpub_foralltables_excepttable, testpub_foralltables_excepttable1;
---------------------------------------------
-- Tests for inherited tables, and
ALTER PUBLICATION testpub4 owner to regress_publication_user; -- ok
SET ROLE regress_publication_user;
-DROP PUBLICATION testpub4;
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION testpub5 FOR ALL TABLES;
+RESET client_min_messages;
+ALTER PUBLICATION testpub5 OWNER TO regress_publication_user3;
+SET ROLE regress_publication_user3;
+-- fail - SET ALL TABLES/SEQUENCES on a publication requires superuser privileges
+ALTER PUBLICATION testpub5 SET ALL TABLES EXCEPT TABLE (testpub_tbl1); -- fail
+ALTER PUBLICATION testpub5 SET ALL TABLES; -- fail
+ALTER PUBLICATION testpub5 SET ALL SEQUENCES; -- fail
+
+SET ROLE regress_publication_user;
+DROP PUBLICATION testpub4, testpub5;
DROP ROLE regress_publication_user3;
REVOKE CREATE ON DATABASE regression FROM regress_publication_user2;
$node_subscriber->safe_psql('postgres', "SELECT count(*) FROM child1");
is($result, qq(10), 'check replicated inserts on subscriber');
+$node_publisher->safe_psql('postgres',
+ "CREATE TABLE tab2 AS SELECT generate_series(1,10) AS a");
+$node_subscriber->safe_psql('postgres', "CREATE TABLE tab2 (a int)");
+
+# Replace the EXCEPT TABLE list so that only tab2 is excluded.
+$node_publisher->safe_psql('postgres',
+ "ALTER PUBLICATION tab_pub SET ALL TABLES EXCEPT TABLE (tab2)");
+
+# Refresh the subscription so the subscriber picks up the updated
+# publication definition and initiates table synchronization.
+$node_subscriber->safe_psql('postgres',
+ "ALTER SUBSCRIPTION tab_sub REFRESH PUBLICATION");
+
+# Wait for initial table sync to finish
+$node_subscriber->wait_for_subscription_sync($node_publisher, 'tab_sub');
+
+# Verify that initial table synchronization does not occur for tables
+# listed in the EXCEPT TABLE clause.
+$result =
+ $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM tab2");
+is($result, qq(0),
+ 'check there is no initial data copied for the tables specified in the EXCEPT TABLE clause'
+);
+
+# Verify that table synchronization now happens for tab1. Table tab1 is
+# included now since the EXCEPT TABLE list is only (tab2).
+$result =
+ $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM tab1");
+is($result, qq(20),
+ 'check that the data is copied as the tab1 is removed from EXCEPT TABLE clause'
+);
+
# cleanup
$node_subscriber->safe_psql(
'postgres', qq(
DROP SUBSCRIPTION tab_sub;
TRUNCATE TABLE tab1;
- DROP TABLE parent, parent1, child, child1;
+ DROP TABLE parent, parent1, child, child1, tab2;
));
$node_publisher->safe_psql(
'postgres', qq(
DROP PUBLICATION tab_pub;
TRUNCATE TABLE tab1;
- DROP TABLE parent, parent1, child, child1;
+ DROP TABLE parent, parent1, child, child1, tab2;
));
# ============================================