From 6edc83bb25feba45801e24221a27ed62099c603d Mon Sep 17 00:00:00 2001 From: Vigneshwaran C Date: Mon, 12 Sep 2022 11:24:54 +0530 Subject: [PATCH v3] Allow creation of publication with schema and table of the same schema. After the scenario is allowed, it's possible to publish a table that specifies column list along with a schema which the table belongs to. This case is not consistent with the rule that different column lists cannot not be used for the same table. To avoid this case, disallow using column list and ALL TABLES IN SCHEMA together. Besides, ignoring the row filter on a table if the table's schema is also part of the publication since different row filters are combined using 'OR'. --- doc/src/sgml/logical-replication.sgml | 5 + doc/src/sgml/ref/alter_publication.sgml | 18 +-- doc/src/sgml/ref/create_publication.sgml | 20 +-- src/backend/catalog/pg_publication.c | 16 ++- src/backend/commands/publicationcmds.c | 133 +++++++------------- src/backend/commands/tablecmds.c | 27 ---- src/backend/replication/pgoutput/pgoutput.c | 31 +++-- src/bin/pg_dump/t/002_pg_dump.pl | 14 +++ src/test/regress/expected/alter_table.out | 14 ++- src/test/regress/expected/publication.out | 90 +++++++++++-- src/test/regress/sql/alter_table.sql | 3 +- src/test/regress/sql/publication.sql | 44 ++++++- src/test/subscription/t/028_row_filter.pl | 2 +- 13 files changed, 245 insertions(+), 172 deletions(-) diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index 0ab191e402..7cff1ba398 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -1142,6 +1142,11 @@ test_sub=# SELECT * FROM child ORDER BY a; the column list is arbitrary and may omit some replica identity columns. + + Column list cannot be specified when the publication publishes + FOR ALL TABLES IN SCHEMA. + + diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml index d8ed89ee91..516f589feb 100644 --- a/doc/src/sgml/ref/alter_publication.sgml +++ b/doc/src/sgml/ref/alter_publication.sgml @@ -52,9 +52,11 @@ ALTER PUBLICATION name RENAME TO ALTER SUBSCRIPTION ... REFRESH PUBLICATION action on the - subscribing side in order to become effective. Note also that the combination - of DROP with a WHERE clause is not - allowed. + subscribing side in order to become effective. Note also that + DROP ALL TABLES IN SCHEMA will not drop any schema tables + that were specified using FOR TABLE/ + ADD TABLE, and the combination of DROP + with a WHERE clause is not allowed. @@ -82,11 +84,11 @@ ALTER PUBLICATION name RENAME TO - Adding/Setting a table that is part of schema specified in - ALL TABLES IN SCHEMA, adding/setting a schema to a - 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. + Adding/Setting a table that specifies a column list when any schema is + specified in ALL TABLES IN SCHEMA, adding/setting a schema + to a publication that already has a table that specifies a column list or + adding/setting a table that specifies a column list to a publication that + already has a schema is not supported. diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index f61641896a..40e52e4a62 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -102,6 +102,11 @@ CREATE PUBLICATION name materialized views, and regular views cannot be part of a publication. + + Specifying a column list when the publication also publishes + FOR ALL TABLES IN SCHEMA is not supported. + + When a partitioned table is added to a publication, all of its existing and future partitions are implicitly considered to be part of the @@ -109,11 +114,6 @@ CREATE PUBLICATION name partition are also published via publications that its ancestors are part of. - - - Specifying a table that is part of a schema specified by - FOR ALL TABLES IN SCHEMA is not supported. - @@ -136,8 +136,8 @@ CREATE PUBLICATION name - Specifying a schema along with a table which belongs to the specified - schema using FOR TABLE is not supported. + Specifying a schema when the publication also publishes a table with a + column list is not supported. @@ -273,6 +273,12 @@ CREATE PUBLICATION name system columns. + + The row filter on a table becomes redundant if + FOR ALL TABLES IN SCHEMA is specified and the table + belongs to the referred schema. + + For published partitioned tables, the row filter for each partition is taken from the published partitioned table if the diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index 6af3570005..f37827f42e 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -1113,6 +1113,7 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) Oid relid = list_nth_oid(tables, funcctx->call_cntr); Datum values[NUM_PUBLICATION_TABLES_ELEM] = {0}; bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0}; + Oid schemaid = get_rel_namespace(relid); /* * Form tuple with appropriate data. @@ -1122,9 +1123,18 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) values[0] = ObjectIdGetDatum(relid); - pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP, - ObjectIdGetDatum(relid), - ObjectIdGetDatum(publication->oid)); + /* + * If the publication is FOR ALL TABLES or FOR ALL TABLES IN SCHEMA + * then it is treated the same as if there are no row filters or column + * lists. + */ + if (!publication->alltables && + !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP, + ObjectIdGetDatum(schemaid), + ObjectIdGetDatum(publication->oid))) + pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP, + ObjectIdGetDatum(relid), + ObjectIdGetDatum(publication->oid)); if (HeapTupleIsValid(pubtuple)) { diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 8b574b86c4..d0ea7f0e38 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -66,7 +66,6 @@ typedef struct rf_context Oid parentid; /* relid of the parent relation */ } rf_context; -static List *OpenRelIdList(List *relids); static List *OpenTableList(List *tables); static void CloseTableList(List *rels); 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 * not part of REPLICA IDENTITY, false otherwise. @@ -720,7 +681,8 @@ TransformPubWhereClauses(List *tables, const char *queryString, * Check the publication column lists expression for all relations in the list. */ static void -CheckPubRelationColumnList(List *tables, const char *queryString, +CheckPubRelationColumnList(List *tables, bool publish_schema, + const char *queryString, bool pubviaroot) { ListCell *lc; @@ -732,6 +694,17 @@ CheckPubRelationColumnList(List *tables, const char *queryString, if (pri->columns == NIL) continue; + /* + * Disallow using column list if any schema is in the publication. + */ + 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 * table, the partition's column list will be used. So disallow using @@ -858,13 +831,11 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) List *rels; rels = OpenTableList(relations); - CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist, - PUBLICATIONOBJ_TABLE); - TransformPubWhereClauses(rels, pstate->p_sourcetext, publish_via_partition_root); - CheckPubRelationColumnList(rels, pstate->p_sourcetext, + CheckPubRelationColumnList(rels, schemaidlist != NIL, + pstate->p_sourcetext, publish_via_partition_root); PublicationAddTables(puboid, rels, true, NULL); @@ -1131,17 +1102,12 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, { 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); - CheckPubRelationColumnList(rels, queryString, pubform->pubviaroot); + CheckPubRelationColumnList(rels, schemas != NIL, queryString, + pubform->pubviaroot); PublicationAddTables(pubid, rels, false, stmt); } @@ -1154,12 +1120,10 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, List *delrels = NIL; ListCell *oldlc; - CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist, - PUBLICATIONOBJ_TABLE); - TransformPubWhereClauses(rels, queryString, pubform->pubviaroot); - CheckPubRelationColumnList(rels, queryString, pubform->pubviaroot); + CheckPubRelationColumnList(rels, schemaidlist != NIL, queryString, + pubform->pubviaroot); /* * To recreate the relation list for the publication, look for @@ -1308,16 +1272,35 @@ AlterPublicationSchemas(AlterPublicationStmt *stmt, LockSchemaList(schemaidlist); if (stmt->action == AP_AddObjects) { - List *rels; - List *reloids; + ListCell *lc; + List *relids; - reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT); - rels = OpenRelIdList(reloids); + relids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT); - CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist, - PUBLICATIONOBJ_TABLES_IN_SCHEMA); + foreach(lc, relids) + { + HeapTuple coltuple; + + coltuple = SearchSysCache2(PUBLICATIONRELMAP, + ObjectIdGetDatum(lfirst_oid(lc)), + ObjectIdGetDatum(pubform->oid)); + + if (!HeapTupleIsValid(coltuple)) + continue; + + /* + * Disallow adding schema if column list is specified in the + * publication. + */ + 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); } else if (stmt->action == AP_DropObjects) @@ -1569,32 +1552,6 @@ RemovePublicationSchemaById(Oid psoid) 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. * The returned tables are locked in ShareUpdateExclusiveLock mode in order to diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e3233a8f38..5277b7b12d 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16409,33 +16409,6 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema) newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1); 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 */ CheckSetNamespace(oldNspOid, nspOid); diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 62e0ffecd8..caa2c905a1 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -854,6 +854,7 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications, MemoryContext oldctx; int idx; 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 @@ -867,26 +868,26 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications, * are multiple lists (one for each operation) to which row filters will * be appended. * - * FOR ALL TABLES implies "don't use row filter expression" so it takes - * precedence. + * FOR ALL TABLES and FOR ALL TABLES IN SCHEMA implies "don't use row + * filter expression" so it takes precedence. */ foreach(lc, publications) { Publication *pub = lfirst(lc); HeapTuple rftuple = NULL; Datum rfdatum = 0; - bool pub_no_filter = false; + bool pub_no_filter = true; - if (pub->alltables) - { - /* - * If the publication is FOR ALL TABLES then it is treated the - * same as if this table has no row filters (even if for other - * publications it does). - */ - pub_no_filter = true; - } - else + /* + * If the publication is FOR ALL TABLES, or the publication is FOR ALL + * TABLES IN SCHEMA and the table belongs to the referred schema then + * it is treated the same as if there are no row filters (even if + * other publications have a row filter). + */ + if (!pub->alltables && + !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP, + ObjectIdGetDatum(schemaid), + ObjectIdGetDatum(pub->oid))) { /* * 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, &pub_no_filter); } - else - { - pub_no_filter = true; - } } if (pub_no_filter) diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 2873b662fb..714b1321ae 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -2565,6 +2565,20 @@ my %tests = ( 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);' => { create_order => 51, create_sql => diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index d63f4f1cba..0906c080b5 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4595,10 +4595,16 @@ create table alter1.t1 (a int); set client_min_messages = 'ERROR'; create publication pub1 for table alter1.t1, all tables in schema alter2; reset client_min_messages; -alter table alter1.t1 set schema alter2; -- should fail -ERROR: cannot move table "t1" to schema "alter2" -DETAIL: The schema "alter2" and same schema's table "t1" cannot be part of the same publication "pub1". +alter table alter1.t1 set schema alter2; +\d+ alter2.t1 + Table "alter2.t1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + a | integer | | | | plain | | +Publications: + "pub1" + drop publication pub1; drop schema alter1 cascade; -NOTICE: drop cascades to table alter1.t1 drop schema alter2 cascade; +NOTICE: drop cascades to table alter2.t1 diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index e6e082de2f..156a82cffd 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -118,15 +118,42 @@ Tables from schemas: SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pub_test; -RESET client_min_messages; --- fail - can't create publication with schema and table of the same schema +-- should be able to create publication with schema and table of the same +-- schema CREATE PUBLICATION testpub_for_tbl_schema FOR ALL TABLES IN SCHEMA pub_test, TABLE pub_test.testpub_nopk; -ERROR: cannot add relation "pub_test.testpub_nopk" to publication -DETAIL: Table's schema "pub_test" is already part of the publication or part of the specified schema list. --- fail - can't add a table of the same schema to the schema publication +RESET client_min_messages; +\dRp+ testpub_for_tbl_schema + 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; -ERROR: cannot add relation "pub_test.testpub_nopk" to publication -DETAIL: Table's schema "pub_test" is already part of the publication or part of the specified schema list. +\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: + "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 -- publication ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk; @@ -166,7 +193,7 @@ Publications: (1 row) 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_tbl3a (b text) INHERITS (testpub_tbl3); 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 SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub6 FOR ALL TABLES IN SCHEMA testpub_rf_schema2; +-- should be able to set publication with schema and table of the same schema ALTER PUBLICATION testpub6 SET ALL 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; +\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_tbl2; DROP TABLE testpub_rf_tbl3; @@ -812,8 +848,40 @@ ALTER TABLE testpub_tbl8_0 REPLICA IDENTITY FULL; UPDATE testpub_tbl8 SET a = 1; ERROR: cannot update table "testpub_tbl8_0" 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 ALL 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 ALL 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 ALL 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 ALL 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 ALL 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 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 SET client_min_messages = 'ERROR'; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index e7013f5e15..3f01fdd8a8 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -3031,7 +3031,8 @@ create table alter1.t1 (a int); set client_min_messages = 'ERROR'; create publication pub1 for table alter1.t1, all tables in schema alter2; 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 schema alter1 cascade; drop schema alter2 cascade; diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index a56387edee..923b7ea5d5 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -73,11 +73,20 @@ ALTER PUBLICATION testpub_fortable SET ALL TABLES IN SCHEMA pub_test; SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pub_test; -RESET client_min_messages; --- fail - can't create publication with schema and table of the same schema +-- should be able to create publication with schema and table of the same +-- schema CREATE PUBLICATION testpub_for_tbl_schema FOR ALL 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; +\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 -- publication 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 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_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 SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub6 FOR ALL TABLES IN SCHEMA testpub_rf_schema2; +-- should be able to set publication with schema and table of the same schema ALTER PUBLICATION testpub6 SET ALL TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99); RESET client_min_messages; +\dRp+ testpub6 DROP TABLE testpub_rf_tbl1; DROP TABLE testpub_rf_tbl2; @@ -525,8 +536,31 @@ UPDATE testpub_tbl8 SET a = 1; ALTER TABLE testpub_tbl8_0 REPLICA IDENTITY FULL; 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 ALL TABLES IN SCHEMA public, TABLE public.testpub_tbl7(a); +-- ok - only publish schema +CREATE PUBLICATION testpub_tbl9 FOR ALL 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 ALL TABLES IN SCHEMA public; +-- failure - cannot SET column list and schema together +ALTER PUBLICATION testpub_tbl9 SET ALL 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 ALL 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 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 diff --git a/src/test/subscription/t/028_row_filter.pl b/src/test/subscription/t/028_row_filter.pl index f5f8a67092..020a9c3793 100644 --- a/src/test/subscription/t/028_row_filter.pl +++ b/src/test/subscription/t/028_row_filter.pl @@ -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)" ); $node_publisher->safe_psql('postgres', - "CREATE PUBLICATION tap_pub_allinschema FOR ALL TABLES IN SCHEMA schema_rf_x" + "CREATE PUBLICATION tap_pub_allinschema FOR ALL TABLES IN SCHEMA schema_rf_x, TABLE schema_rf_x.tab_rf_x WHERE (x > 10)" ); $node_publisher->safe_psql('postgres', "ALTER PUBLICATION tap_pub_allinschema ADD TABLE public.tab_rf_partition WHERE (x > 10)" -- 2.18.4