Allow publications with schema and table of the same schema.

We previously thought that allowing such cases can confuse users when they
specify DROP TABLES IN SCHEMA but that doesn't seem to be the case based
on discussion. This helps to uplift the restriction during
ALTER TABLE ... SET SCHEMA which used to ensure that we couldn't end up
with a publication having both a schema and the same schema's table.

To allow this, we need to forbid having any schema on a publication if
column lists on a table are specified (and vice versa). This is because
otherwise we still need a restriction during ALTER TABLE ... SET SCHEMA to
forbid cases where it could lead to a publication having both a schema and
the same schema's table with column list.

Based on suggestions by Peter Eisentraut.

Author: Hou Zhijie and Vignesh C
Reviewed-By: Peter Smith, Amit Kapila
Backpatch-through: 15, where it was introduced
Discussion: https://postgr.es/m/2729c9e2-9aac-8cda-f2f4-34f2bcc18f4e@enterprisedb.com
This commit is contained in:
Amit Kapila 2022-09-23 08:21:26 +05:30
parent d89755dac6
commit 13a185f54b
13 changed files with 251 additions and 185 deletions

View File

@ -1119,6 +1119,11 @@ test_sub=# SELECT * FROM child ORDER BY a;
of columns in the list is not preserved. of columns in the list is not preserved.
</para> </para>
<para>
Specifying a column list when the publication also publishes
<literal>FOR TABLES IN SCHEMA</literal> is not supported.
</para>
<para> <para>
For partitioned tables, the publication parameter For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list <literal>publish_via_partition_root</literal> determines which column list

View File

@ -52,9 +52,11 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
remove one or more tables/schemas from the publication. Note that adding 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 tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the <literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
subscribing side in order to become effective. Note also that the combination subscribing side in order to become effective. Note also that
of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not <literal>DROP TABLES IN SCHEMA</literal> will not drop any schema tables
allowed. that were specified using <literal>FOR TABLE</literal>/
<literal>ADD TABLE</literal>, and the combination of <literal>DROP</literal>
with a <literal>WHERE</literal> clause is not allowed.
</para> </para>
<para> <para>
@ -82,11 +84,8 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para> </para>
<para> <para>
Adding/Setting a table that is part of schema specified in Adding/Setting any schema when the publication also publishes a table with a
<literal>TABLES IN SCHEMA</literal>, adding/setting a schema to a column list, and vice versa is not supported.
publication that already has a table that is part of the specified schema or
adding/setting a table to a publication that already has a table's schema as
part of the specified schema is not supported.
</para> </para>
</refsect1> </refsect1>

View File

@ -102,6 +102,11 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
materialized views, and regular views cannot be part of a publication. materialized views, and regular views cannot be part of a publication.
</para> </para>
<para>
Specifying a column list when the publication also publishes
<literal>FOR TABLES IN SCHEMA</literal> is not supported.
</para>
<para> <para>
When a partitioned table is added to a publication, all of its existing When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the and future partitions are implicitly considered to be part of the
@ -109,11 +114,6 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
partition are also published via publications that its ancestors are partition are also published via publications that its ancestors are
part of. part of.
</para> </para>
<para>
Specifying a table that is part of a schema specified by
<literal>FOR TABLES IN SCHEMA</literal> is not supported.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para> </para>
<para> <para>
Specifying a schema along with a table which belongs to the specified Specifying a schema when the publication also publishes a table with a
schema using <literal>FOR TABLE</literal> is not supported. column list is not supported.
</para> </para>
<para> <para>
@ -273,6 +273,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
system columns. system columns.
</para> </para>
<para>
The row filter on a table becomes redundant if
<literal>FOR TABLES IN SCHEMA</literal> is specified and the table
belongs to the referred schema.
</para>
<para> <para>
For published partitioned tables, the row filter for each For published partitioned tables, the row filter for each
partition is taken from the published partitioned table if the partition is taken from the published partitioned table if the

View File

@ -1111,6 +1111,7 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
HeapTuple pubtuple = NULL; HeapTuple pubtuple = NULL;
HeapTuple rettuple; HeapTuple rettuple;
Oid relid = list_nth_oid(tables, funcctx->call_cntr); Oid relid = list_nth_oid(tables, funcctx->call_cntr);
Oid schemaid = get_rel_namespace(relid);
Datum values[NUM_PUBLICATION_TABLES_ELEM] = {0}; Datum values[NUM_PUBLICATION_TABLES_ELEM] = {0};
bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0}; bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
@ -1122,9 +1123,17 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
values[0] = ObjectIdGetDatum(relid); values[0] = ObjectIdGetDatum(relid);
pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP, /*
ObjectIdGetDatum(relid), * We don't consider row filters or column lists for FOR ALL TABLES or
ObjectIdGetDatum(publication->oid)); * FOR TABLES IN SCHEMA publications.
*/
if (!publication->alltables &&
!SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
ObjectIdGetDatum(schemaid),
ObjectIdGetDatum(publication->oid)))
pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP,
ObjectIdGetDatum(relid),
ObjectIdGetDatum(publication->oid));
if (HeapTupleIsValid(pubtuple)) if (HeapTupleIsValid(pubtuple))
{ {

View File

@ -66,7 +66,6 @@ typedef struct rf_context
Oid parentid; /* relid of the parent relation */ Oid parentid; /* relid of the parent relation */
} rf_context; } rf_context;
static List *OpenRelIdList(List *relids);
static List *OpenTableList(List *tables); static List *OpenTableList(List *tables);
static void CloseTableList(List *rels); static void CloseTableList(List *rels);
static void LockSchemaList(List *schemalist); static void LockSchemaList(List *schemalist);
@ -214,44 +213,6 @@ ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate,
} }
} }
/*
* Check if any of the given relation's schema is a member of the given schema
* list.
*/
static void
CheckObjSchemaNotAlreadyInPublication(List *rels, List *schemaidlist,
PublicationObjSpecType checkobjtype)
{
ListCell *lc;
foreach(lc, rels)
{
PublicationRelInfo *pub_rel = (PublicationRelInfo *) lfirst(lc);
Relation rel = pub_rel->relation;
Oid relSchemaId = RelationGetNamespace(rel);
if (list_member_oid(schemaidlist, relSchemaId))
{
if (checkobjtype == PUBLICATIONOBJ_TABLES_IN_SCHEMA)
ereport(ERROR,
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add schema \"%s\" to publication",
get_namespace_name(relSchemaId)),
errdetail("Table \"%s\" in schema \"%s\" is already part of the publication, adding the same schema is not supported.",
RelationGetRelationName(rel),
get_namespace_name(relSchemaId)));
else if (checkobjtype == PUBLICATIONOBJ_TABLE)
ereport(ERROR,
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add relation \"%s.%s\" to publication",
get_namespace_name(relSchemaId),
RelationGetRelationName(rel)),
errdetail("Table's schema \"%s\" is already part of the publication or part of the specified schema list.",
get_namespace_name(relSchemaId)));
}
}
}
/* /*
* Returns true if any of the columns used in the row filter WHERE expression is * Returns true if any of the columns used in the row filter WHERE expression is
* not part of REPLICA IDENTITY, false otherwise. * not part of REPLICA IDENTITY, false otherwise.
@ -721,7 +682,7 @@ TransformPubWhereClauses(List *tables, const char *queryString,
*/ */
static void static void
CheckPubRelationColumnList(List *tables, const char *queryString, CheckPubRelationColumnList(List *tables, const char *queryString,
bool pubviaroot) bool publish_schema, bool pubviaroot)
{ {
ListCell *lc; ListCell *lc;
@ -732,6 +693,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
if (pri->columns == NIL) if (pri->columns == NIL)
continue; continue;
/*
* Disallow specifying column list if any schema is in the
* publication.
*
* XXX We could instead just forbid the case when the publication
* tries to publish the table with a column list and a schema for that
* table. However, if we do that then we need a restriction during
* ALTER TABLE ... SET SCHEMA to prevent such a case which doesn't
* seem to be a good idea.
*/
if (publish_schema)
ereport(ERROR,
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot use publication column list for relation \"%s.%s\"",
get_namespace_name(RelationGetNamespace(pri->relation)),
RelationGetRelationName(pri->relation)),
errdetail("Column list cannot be specified if any schema is part of the publication or specified in the list."));
/* /*
* If the publication doesn't publish changes via the root partitioned * If the publication doesn't publish changes via the root partitioned
* table, the partition's column list will be used. So disallow using * table, the partition's column list will be used. So disallow using
@ -858,13 +837,11 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
List *rels; List *rels;
rels = OpenTableList(relations); rels = OpenTableList(relations);
CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist,
PUBLICATIONOBJ_TABLE);
TransformPubWhereClauses(rels, pstate->p_sourcetext, TransformPubWhereClauses(rels, pstate->p_sourcetext,
publish_via_partition_root); publish_via_partition_root);
CheckPubRelationColumnList(rels, pstate->p_sourcetext, CheckPubRelationColumnList(rels, pstate->p_sourcetext,
schemaidlist != NIL,
publish_via_partition_root); publish_via_partition_root);
PublicationAddTables(puboid, rels, true, NULL); PublicationAddTables(puboid, rels, true, NULL);
@ -1110,8 +1087,8 @@ InvalidatePublicationRels(List *relids)
*/ */
static void static void
AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
List *tables, List *schemaidlist, List *tables, const char *queryString,
const char *queryString) bool publish_schema)
{ {
List *rels = NIL; List *rels = NIL;
Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup); Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup);
@ -1129,19 +1106,12 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
if (stmt->action == AP_AddObjects) if (stmt->action == AP_AddObjects)
{ {
List *schemas = NIL;
/*
* Check if the relation is member of the existing schema in the
* publication or member of the schema list specified.
*/
schemas = list_concat_copy(schemaidlist, GetPublicationSchemas(pubid));
CheckObjSchemaNotAlreadyInPublication(rels, schemas,
PUBLICATIONOBJ_TABLE);
TransformPubWhereClauses(rels, queryString, pubform->pubviaroot); TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
CheckPubRelationColumnList(rels, queryString, pubform->pubviaroot); publish_schema |= is_schema_publication(pubid);
CheckPubRelationColumnList(rels, queryString, publish_schema,
pubform->pubviaroot);
PublicationAddTables(pubid, rels, false, stmt); PublicationAddTables(pubid, rels, false, stmt);
} }
@ -1154,12 +1124,10 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
List *delrels = NIL; List *delrels = NIL;
ListCell *oldlc; ListCell *oldlc;
CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist,
PUBLICATIONOBJ_TABLE);
TransformPubWhereClauses(rels, queryString, pubform->pubviaroot); TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
CheckPubRelationColumnList(rels, queryString, pubform->pubviaroot); CheckPubRelationColumnList(rels, queryString, publish_schema,
pubform->pubviaroot);
/* /*
* To recreate the relation list for the publication, look for * To recreate the relation list for the publication, look for
@ -1308,16 +1276,35 @@ AlterPublicationSchemas(AlterPublicationStmt *stmt,
LockSchemaList(schemaidlist); LockSchemaList(schemaidlist);
if (stmt->action == AP_AddObjects) if (stmt->action == AP_AddObjects)
{ {
List *rels; ListCell *lc;
List *reloids; List *reloids;
reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT); reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT);
rels = OpenRelIdList(reloids);
CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist, foreach(lc, reloids)
PUBLICATIONOBJ_TABLES_IN_SCHEMA); {
HeapTuple coltuple;
coltuple = SearchSysCache2(PUBLICATIONRELMAP,
ObjectIdGetDatum(lfirst_oid(lc)),
ObjectIdGetDatum(pubform->oid));
if (!HeapTupleIsValid(coltuple))
continue;
/*
* Disallow adding schema if column list is already part of the
* publication. See CheckPubRelationColumnList.
*/
if (!heap_attisnull(coltuple, Anum_pg_publication_rel_prattrs, NULL))
ereport(ERROR,
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add schema to the publication"),
errdetail("Schema cannot be added if any table that specifies column list is already part of the publication."));
ReleaseSysCache(coltuple);
}
CloseTableList(rels);
PublicationAddSchemas(pubform->oid, schemaidlist, false, stmt); PublicationAddSchemas(pubform->oid, schemaidlist, false, stmt);
} }
else if (stmt->action == AP_DropObjects) else if (stmt->action == AP_DropObjects)
@ -1429,14 +1416,7 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
heap_freetuple(tup); heap_freetuple(tup);
/* /* Lock the publication so nobody else can do anything with it. */
* Lock the publication so nobody else can do anything with it. This
* prevents concurrent alter to add table(s) that were already going
* to become part of the publication by adding corresponding schema(s)
* via this command and similarly it will prevent the concurrent
* addition of schema(s) for which there is any corresponding table
* being added by this command.
*/
LockDatabaseObject(PublicationRelationId, pubid, 0, LockDatabaseObject(PublicationRelationId, pubid, 0,
AccessExclusiveLock); AccessExclusiveLock);
@ -1453,8 +1433,8 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
errmsg("publication \"%s\" does not exist", errmsg("publication \"%s\" does not exist",
stmt->pubname)); stmt->pubname));
AlterPublicationTables(stmt, tup, relations, schemaidlist, AlterPublicationTables(stmt, tup, relations, pstate->p_sourcetext,
pstate->p_sourcetext); schemaidlist != NIL);
AlterPublicationSchemas(stmt, tup, schemaidlist); AlterPublicationSchemas(stmt, tup, schemaidlist);
} }
@ -1569,32 +1549,6 @@ RemovePublicationSchemaById(Oid psoid)
table_close(rel, RowExclusiveLock); table_close(rel, RowExclusiveLock);
} }
/*
* Open relations specified by a relid list.
* The returned tables are locked in ShareUpdateExclusiveLock mode in order to
* add them to a publication.
*/
static List *
OpenRelIdList(List *relids)
{
ListCell *lc;
List *rels = NIL;
foreach(lc, relids)
{
PublicationRelInfo *pub_rel;
Oid relid = lfirst_oid(lc);
Relation rel = table_open(relid,
ShareUpdateExclusiveLock);
pub_rel = palloc(sizeof(PublicationRelInfo));
pub_rel->relation = rel;
rels = lappend(rels, pub_rel);
}
return rels;
}
/* /*
* Open relations specified by a PublicationTable list. * Open relations specified by a PublicationTable list.
* The returned tables are locked in ShareUpdateExclusiveLock mode in order to * The returned tables are locked in ShareUpdateExclusiveLock mode in order to

View File

@ -16409,33 +16409,6 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1); newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL); nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
/*
* Check that setting the relation to a different schema won't result in a
* publication having both a schema and the same schema's table, as this
* is not supported.
*/
if (stmt->objectType == OBJECT_TABLE)
{
ListCell *lc;
List *schemaPubids = GetSchemaPublications(nspOid);
List *relPubids = GetRelationPublications(RelationGetRelid(rel));
foreach(lc, relPubids)
{
Oid pubid = lfirst_oid(lc);
if (list_member_oid(schemaPubids, pubid))
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move table \"%s\" to schema \"%s\"",
RelationGetRelationName(rel), stmt->newschema),
errdetail("The schema \"%s\" and same schema's table \"%s\" cannot be part of the same publication \"%s\".",
stmt->newschema,
RelationGetRelationName(rel),
get_publication_name(pubid, false)));
}
}
/* common checks on switching namespaces */ /* common checks on switching namespaces */
CheckSetNamespace(oldNspOid, nspOid); CheckSetNamespace(oldNspOid, nspOid);

View File

@ -854,6 +854,7 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications,
MemoryContext oldctx; MemoryContext oldctx;
int idx; int idx;
bool has_filter = true; bool has_filter = true;
Oid schemaid = get_rel_namespace(entry->publish_as_relid);
/* /*
* Find if there are any row filters for this relation. If there are, then * Find if there are any row filters for this relation. If there are, then
@ -867,26 +868,26 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications,
* are multiple lists (one for each operation) to which row filters will * are multiple lists (one for each operation) to which row filters will
* be appended. * be appended.
* *
* FOR ALL TABLES implies "don't use row filter expression" so it takes * FOR ALL TABLES and FOR TABLES IN SCHEMA implies "don't use row
* precedence. * filter expression" so it takes precedence.
*/ */
foreach(lc, publications) foreach(lc, publications)
{ {
Publication *pub = lfirst(lc); Publication *pub = lfirst(lc);
HeapTuple rftuple = NULL; HeapTuple rftuple = NULL;
Datum rfdatum = 0; Datum rfdatum = 0;
bool pub_no_filter = false; bool pub_no_filter = true;
if (pub->alltables) /*
{ * If the publication is FOR ALL TABLES, or the publication includes a
/* * FOR TABLES IN SCHEMA where the table belongs to the referred
* If the publication is FOR ALL TABLES then it is treated the * schema, then it is treated the same as if there are no row filters
* same as if this table has no row filters (even if for other * (even if other publications have a row filter).
* publications it does). */
*/ if (!pub->alltables &&
pub_no_filter = true; !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
} ObjectIdGetDatum(schemaid),
else ObjectIdGetDatum(pub->oid)))
{ {
/* /*
* Check for the presence of a row filter in this publication. * Check for the presence of a row filter in this publication.
@ -902,10 +903,6 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications,
Anum_pg_publication_rel_prqual, Anum_pg_publication_rel_prqual,
&pub_no_filter); &pub_no_filter);
} }
else
{
pub_no_filter = true;
}
} }
if (pub_no_filter) if (pub_no_filter)

View File

@ -2564,6 +2564,20 @@ my %tests = (
like => { %full_runs, section_post_data => 1, }, like => { %full_runs, section_post_data => 1, },
}, },
'ALTER PUBLICATION pub3 ADD TABLE test_table' => {
create_order => 51,
create_sql =>
'ALTER PUBLICATION pub3 ADD TABLE dump_test.test_table;',
regexp => qr/^
\QALTER PUBLICATION pub3 ADD TABLE ONLY dump_test.test_table;\E
/xm,
like => { %full_runs, section_post_data => 1, },
unlike => {
exclude_dump_test_schema => 1,
exclude_test_table => 1,
},
},
'ALTER PUBLICATION pub4 ADD TABLE test_table WHERE (col1 > 0);' => { 'ALTER PUBLICATION pub4 ADD TABLE test_table WHERE (col1 > 0);' => {
create_order => 51, create_order => 51,
create_sql => create_sql =>

View File

@ -4595,10 +4595,16 @@ create table alter1.t1 (a int);
set client_min_messages = 'ERROR'; set client_min_messages = 'ERROR';
create publication pub1 for table alter1.t1, tables in schema alter2; create publication pub1 for table alter1.t1, tables in schema alter2;
reset client_min_messages; reset client_min_messages;
alter table alter1.t1 set schema alter2; -- should fail alter table alter1.t1 set schema alter2;
ERROR: cannot move table "t1" to schema "alter2" \d+ alter2.t1
DETAIL: The schema "alter2" and same schema's table "t1" cannot be part of the same publication "pub1". Table "alter2.t1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+---------+--------------+-------------
a | integer | | | | plain | |
Publications:
"pub1"
drop publication pub1; drop publication pub1;
drop schema alter1 cascade; drop schema alter1 cascade;
NOTICE: drop cascades to table alter1.t1
drop schema alter2 cascade; drop schema alter2 cascade;
NOTICE: drop cascades to table alter2.t1

View File

@ -118,15 +118,42 @@ Tables from schemas:
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pub_test; CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pub_test;
RESET client_min_messages; -- should be able to create publication with schema and table of the same
-- fail - can't create publication with schema and table of the same schema -- schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA pub_test, TABLE pub_test.testpub_nopk; CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA pub_test, TABLE pub_test.testpub_nopk;
ERROR: cannot add relation "pub_test.testpub_nopk" to publication RESET client_min_messages;
DETAIL: Table's schema "pub_test" is already part of the publication or part of the specified schema list. \dRp+ testpub_for_tbl_schema
-- fail - can't add a table of the same schema to the schema publication Publication testpub_for_tbl_schema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
--------------------------+------------+---------+---------+---------+-----------+----------
regress_publication_user | f | t | t | t | t | f
Tables:
"pub_test.testpub_nopk"
Tables from schemas:
"pub_test"
-- should be able to add a table of the same schema to the schema publication
ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk; ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk;
ERROR: cannot add relation "pub_test.testpub_nopk" to publication \dRp+ testpub_forschema
DETAIL: Table's schema "pub_test" is already part of the publication or part of the specified schema list. Publication testpub_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
--------------------------+------------+---------+---------+---------+-----------+----------
regress_publication_user | f | t | t | t | t | f
Tables:
"pub_test.testpub_nopk"
Tables from schemas:
"pub_test"
-- should be able to drop the table
ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk;
\dRp+ testpub_forschema
Publication testpub_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
--------------------------+------------+---------+---------+---------+-----------+----------
regress_publication_user | f | t | t | t | t | f
Tables from schemas:
"pub_test"
-- fail - can't drop a table from the schema publication which isn't in the -- fail - can't drop a table from the schema publication which isn't in the
-- publication -- publication
ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk; ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk;
@ -166,7 +193,7 @@ Publications:
(1 row) (1 row)
DROP TABLE testpub_tbl2; DROP TABLE testpub_tbl2;
DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema; DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema;
CREATE TABLE testpub_tbl3 (a int); CREATE TABLE testpub_tbl3 (a int);
CREATE TABLE testpub_tbl3a (b text) INHERITS (testpub_tbl3); CREATE TABLE testpub_tbl3a (b text) INHERITS (testpub_tbl3);
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';
@ -466,10 +493,19 @@ ERROR: cannot use a WHERE clause when removing a table from a publication
-- fail - cannot ALTER SET table which is a member of a pre-existing schema -- fail - cannot ALTER SET table which is a member of a pre-existing schema
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2; CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2;
-- should be able to set publication with schema and table of the same schema
ALTER PUBLICATION testpub6 SET TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99); ALTER PUBLICATION testpub6 SET TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99);
ERROR: cannot add relation "testpub_rf_schema2.testpub_rf_tbl6" to publication
DETAIL: Table's schema "testpub_rf_schema2" is already part of the publication or part of the specified schema list.
RESET client_min_messages; RESET client_min_messages;
\dRp+ testpub6
Publication testpub6
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
--------------------------+------------+---------+---------+---------+-----------+----------
regress_publication_user | f | t | t | t | t | f
Tables:
"testpub_rf_schema2.testpub_rf_tbl6" WHERE (i < 99)
Tables from schemas:
"testpub_rf_schema2"
DROP TABLE testpub_rf_tbl1; DROP TABLE testpub_rf_tbl1;
DROP TABLE testpub_rf_tbl2; DROP TABLE testpub_rf_tbl2;
DROP TABLE testpub_rf_tbl3; DROP TABLE testpub_rf_tbl3;
@ -812,8 +848,40 @@ ALTER TABLE testpub_tbl8_0 REPLICA IDENTITY FULL;
UPDATE testpub_tbl8 SET a = 1; UPDATE testpub_tbl8 SET a = 1;
ERROR: cannot update table "testpub_tbl8_0" ERROR: cannot update table "testpub_tbl8_0"
DETAIL: Column list used by the publication does not cover the replica identity. DETAIL: Column list used by the publication does not cover the replica identity.
-- test that using column list for table is disallowed if any schemas are
-- part of the publication
SET client_min_messages = 'ERROR';
-- failure - cannot use column list and schema together
CREATE PUBLICATION testpub_tbl9 FOR TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
ERROR: cannot use publication column list for relation "public.testpub_tbl7"
DETAIL: Column list cannot be specified if any schema is part of the publication or specified in the list.
-- ok - only publish schema
CREATE PUBLICATION testpub_tbl9 FOR TABLES IN SCHEMA public;
-- failure - add a table with column list when there is already a schema in the
-- publication
ALTER PUBLICATION testpub_tbl9 ADD TABLE public.testpub_tbl7(a);
ERROR: cannot use publication column list for relation "public.testpub_tbl7"
DETAIL: Column list cannot be specified if any schema is part of the publication or specified in the list.
-- ok - only publish table with column list
ALTER PUBLICATION testpub_tbl9 SET TABLE public.testpub_tbl7(a);
-- failure - specify a schema when there is already a column list in the
-- publication
ALTER PUBLICATION testpub_tbl9 ADD TABLES IN SCHEMA public;
ERROR: cannot add schema to the publication
DETAIL: Schema cannot be added if any table that specifies column list is already part of the publication.
-- failure - cannot SET column list and schema together
ALTER PUBLICATION testpub_tbl9 SET TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
ERROR: cannot use publication column list for relation "public.testpub_tbl7"
DETAIL: Column list cannot be specified if any schema is part of the publication or specified in the list.
-- ok - drop table
ALTER PUBLICATION testpub_tbl9 DROP TABLE public.testpub_tbl7;
-- failure - cannot ADD column list and schema together
ALTER PUBLICATION testpub_tbl9 ADD TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
ERROR: cannot use publication column list for relation "public.testpub_tbl7"
DETAIL: Column list cannot be specified if any schema is part of the publication or specified in the list.
RESET client_min_messages;
DROP TABLE testpub_tbl5, testpub_tbl6, testpub_tbl7, testpub_tbl8, testpub_tbl8_1; DROP TABLE testpub_tbl5, testpub_tbl6, testpub_tbl7, testpub_tbl8, testpub_tbl8_1;
DROP PUBLICATION testpub_table_ins, testpub_fortable, testpub_fortable_insert, testpub_col_list; DROP PUBLICATION testpub_table_ins, testpub_fortable, testpub_fortable_insert, testpub_col_list, testpub_tbl9;
-- ====================================================== -- ======================================================
-- Test combination of column list and row filter -- Test combination of column list and row filter
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';

View File

@ -3031,7 +3031,8 @@ create table alter1.t1 (a int);
set client_min_messages = 'ERROR'; set client_min_messages = 'ERROR';
create publication pub1 for table alter1.t1, tables in schema alter2; create publication pub1 for table alter1.t1, tables in schema alter2;
reset client_min_messages; reset client_min_messages;
alter table alter1.t1 set schema alter2; -- should fail alter table alter1.t1 set schema alter2;
\d+ alter2.t1
drop publication pub1; drop publication pub1;
drop schema alter1 cascade; drop schema alter1 cascade;
drop schema alter2 cascade; drop schema alter2 cascade;

View File

@ -73,11 +73,20 @@ ALTER PUBLICATION testpub_fortable SET TABLES IN SCHEMA pub_test;
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pub_test; CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pub_test;
RESET client_min_messages; -- should be able to create publication with schema and table of the same
-- fail - can't create publication with schema and table of the same schema -- schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA pub_test, TABLE pub_test.testpub_nopk; CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA pub_test, TABLE pub_test.testpub_nopk;
-- fail - can't add a table of the same schema to the schema publication RESET client_min_messages;
\dRp+ testpub_for_tbl_schema
-- should be able to add a table of the same schema to the schema publication
ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk; ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk;
\dRp+ testpub_forschema
-- should be able to drop the table
ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk;
\dRp+ testpub_forschema
-- fail - can't drop a table from the schema publication which isn't in the -- fail - can't drop a table from the schema publication which isn't in the
-- publication -- publication
ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk; ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk;
@ -90,7 +99,7 @@ SELECT pubname, puballtables FROM pg_publication WHERE pubname = 'testpub_forall
\dRp+ testpub_foralltables \dRp+ testpub_foralltables
DROP TABLE testpub_tbl2; DROP TABLE testpub_tbl2;
DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema; DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema;
CREATE TABLE testpub_tbl3 (a int); CREATE TABLE testpub_tbl3 (a int);
CREATE TABLE testpub_tbl3a (b text) INHERITS (testpub_tbl3); CREATE TABLE testpub_tbl3a (b text) INHERITS (testpub_tbl3);
@ -242,8 +251,10 @@ ALTER PUBLICATION testpub5 DROP TABLE testpub_rf_tbl1 WHERE (e < 27);
-- fail - cannot ALTER SET table which is a member of a pre-existing schema -- fail - cannot ALTER SET table which is a member of a pre-existing schema
SET client_min_messages = 'ERROR'; SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2; CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2;
-- should be able to set publication with schema and table of the same schema
ALTER PUBLICATION testpub6 SET TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99); ALTER PUBLICATION testpub6 SET TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99);
RESET client_min_messages; RESET client_min_messages;
\dRp+ testpub6
DROP TABLE testpub_rf_tbl1; DROP TABLE testpub_rf_tbl1;
DROP TABLE testpub_rf_tbl2; DROP TABLE testpub_rf_tbl2;
@ -525,8 +536,31 @@ UPDATE testpub_tbl8 SET a = 1;
ALTER TABLE testpub_tbl8_0 REPLICA IDENTITY FULL; ALTER TABLE testpub_tbl8_0 REPLICA IDENTITY FULL;
UPDATE testpub_tbl8 SET a = 1; UPDATE testpub_tbl8 SET a = 1;
-- test that using column list for table is disallowed if any schemas are
-- part of the publication
SET client_min_messages = 'ERROR';
-- failure - cannot use column list and schema together
CREATE PUBLICATION testpub_tbl9 FOR TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
-- ok - only publish schema
CREATE PUBLICATION testpub_tbl9 FOR TABLES IN SCHEMA public;
-- failure - add a table with column list when there is already a schema in the
-- publication
ALTER PUBLICATION testpub_tbl9 ADD TABLE public.testpub_tbl7(a);
-- ok - only publish table with column list
ALTER PUBLICATION testpub_tbl9 SET TABLE public.testpub_tbl7(a);
-- failure - specify a schema when there is already a column list in the
-- publication
ALTER PUBLICATION testpub_tbl9 ADD TABLES IN SCHEMA public;
-- failure - cannot SET column list and schema together
ALTER PUBLICATION testpub_tbl9 SET TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
-- ok - drop table
ALTER PUBLICATION testpub_tbl9 DROP TABLE public.testpub_tbl7;
-- failure - cannot ADD column list and schema together
ALTER PUBLICATION testpub_tbl9 ADD TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a);
RESET client_min_messages;
DROP TABLE testpub_tbl5, testpub_tbl6, testpub_tbl7, testpub_tbl8, testpub_tbl8_1; DROP TABLE testpub_tbl5, testpub_tbl6, testpub_tbl7, testpub_tbl8, testpub_tbl8_1;
DROP PUBLICATION testpub_table_ins, testpub_fortable, testpub_fortable_insert, testpub_col_list; DROP PUBLICATION testpub_table_ins, testpub_fortable, testpub_fortable_insert, testpub_col_list, testpub_tbl9;
-- ====================================================== -- ======================================================
-- Test combination of column list and row filter -- Test combination of column list and row filter

View File

@ -119,7 +119,7 @@ $node_publisher->safe_psql('postgres',
"CREATE PUBLICATION tap_pub_x FOR TABLE schema_rf_x.tab_rf_x WHERE (x > 10)" "CREATE PUBLICATION tap_pub_x FOR TABLE schema_rf_x.tab_rf_x WHERE (x > 10)"
); );
$node_publisher->safe_psql('postgres', $node_publisher->safe_psql('postgres',
"CREATE PUBLICATION tap_pub_allinschema FOR TABLES IN SCHEMA schema_rf_x" "CREATE PUBLICATION tap_pub_allinschema FOR TABLES IN SCHEMA schema_rf_x, TABLE schema_rf_x.tab_rf_x WHERE (x > 10)"
); );
$node_publisher->safe_psql('postgres', $node_publisher->safe_psql('postgres',
"ALTER PUBLICATION tap_pub_allinschema ADD TABLE public.tab_rf_partition WHERE (x > 10)" "ALTER PUBLICATION tap_pub_allinschema ADD TABLE public.tab_rf_partition WHERE (x > 10)"