diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index 7fe3a1043e..77be4c37e7 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -1119,6 +1119,11 @@ test_sub=# SELECT * FROM child ORDER BY a; of columns in the list is not preserved. + + Specifying a column list when the publication also publishes + FOR TABLES IN SCHEMA is not supported. + + For partitioned tables, the publication parameter publish_via_partition_root determines which column list diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml index fc2d6d4885..c84b11f47a 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 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,8 @@ ALTER PUBLICATION name RENAME TO - Adding/Setting a table that is part of schema specified in - 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 any schema when the publication also publishes a table with a + column list, and vice versa is not supported. diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 2e097a81e5..c5190f0ce6 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 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 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 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 e27db27f04..cd48cb6c46 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -1111,6 +1111,7 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) HeapTuple pubtuple = NULL; HeapTuple rettuple; Oid relid = list_nth_oid(tables, funcctx->call_cntr); + Oid schemaid = get_rel_namespace(relid); Datum values[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); - pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP, - ObjectIdGetDatum(relid), - ObjectIdGetDatum(publication->oid)); + /* + * We don't consider row filters or column lists for FOR ALL TABLES or + * 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)) { diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 15ab5aa99e..7ffad096aa 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. @@ -721,7 +682,7 @@ TransformPubWhereClauses(List *tables, const char *queryString, */ static void CheckPubRelationColumnList(List *tables, const char *queryString, - bool pubviaroot) + bool publish_schema, bool pubviaroot) { ListCell *lc; @@ -732,6 +693,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString, if (pri->columns == NIL) 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 * table, the partition's column list will be used. So disallow using @@ -858,13 +837,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, + schemaidlist != NIL, publish_via_partition_root); PublicationAddTables(puboid, rels, true, NULL); @@ -1110,8 +1087,8 @@ InvalidatePublicationRels(List *relids) */ static void AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, - List *tables, List *schemaidlist, - const char *queryString) + List *tables, const char *queryString, + bool publish_schema) { List *rels = NIL; Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup); @@ -1129,19 +1106,12 @@ AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, 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); - CheckPubRelationColumnList(rels, queryString, pubform->pubviaroot); + publish_schema |= is_schema_publication(pubid); + + CheckPubRelationColumnList(rels, queryString, publish_schema, + pubform->pubviaroot); PublicationAddTables(pubid, rels, false, stmt); } @@ -1154,12 +1124,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, queryString, publish_schema, + pubform->pubviaroot); /* * To recreate the relation list for the publication, look for @@ -1308,16 +1276,35 @@ AlterPublicationSchemas(AlterPublicationStmt *stmt, LockSchemaList(schemaidlist); if (stmt->action == AP_AddObjects) { - List *rels; + ListCell *lc; List *reloids; reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT); - rels = OpenRelIdList(reloids); - CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist, - PUBLICATIONOBJ_TABLES_IN_SCHEMA); + foreach(lc, reloids) + { + 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); } else if (stmt->action == AP_DropObjects) @@ -1429,14 +1416,7 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) heap_freetuple(tup); - /* - * 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. - */ + /* Lock the publication so nobody else can do anything with it. */ LockDatabaseObject(PublicationRelationId, pubid, 0, AccessExclusiveLock); @@ -1453,8 +1433,8 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) errmsg("publication \"%s\" does not exist", stmt->pubname)); - AlterPublicationTables(stmt, tup, relations, schemaidlist, - pstate->p_sourcetext); + AlterPublicationTables(stmt, tup, relations, pstate->p_sourcetext, + schemaidlist != NIL); AlterPublicationSchemas(stmt, tup, schemaidlist); } @@ -1569,32 +1549,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 6c52edd9be..7d8a75d23c 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 92bbffbe7c..2ecaa5b907 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 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 includes a + * FOR TABLES IN SCHEMA where 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 68fe9e2b73..a869321cdf 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -2564,6 +2564,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 656dac6801..346f594ad0 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, 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 ce63511b94..c0c0e7d92e 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 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 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 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); -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 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 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 8846c14dbb..9f773aeeb9 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, 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 231c9d5c53..a47c5939d5 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -73,11 +73,20 @@ ALTER PUBLICATION testpub_fortable SET TABLES IN SCHEMA pub_test; SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_forschema FOR 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 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 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); 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 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 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 ba07ed37b7..da52289dde 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 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', "ALTER PUBLICATION tap_pub_allinschema ADD TABLE public.tab_rf_partition WHERE (x > 10)"