why can't a table be part of the same publication as its schema
Apparently, you can't add a table to a publication if its schema is
already part of the publication (and vice versa), e.g.,
=# alter publication p1 add table s1.t1;
ERROR: 22023: cannot add relation "s1.t1" to publication
DETAIL: Table's schema "s1" is already part of the publication or part
of the specified schema list.
Is there a reason for this? It looks a bit like a misfeature to me. It
constrains how you can move your tables around between schemas, based on
how somewhere else a publication has been constructed.
It seems to me that it shouldn't be difficult to handle the case that a
table is part of the publication via two different routes. (We must
already handle that since a subscription can use more than one publication.)
On Thu, Sep 8, 2022 at 5:06 PM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:
Apparently, you can't add a table to a publication if its schema is
already part of the publication (and vice versa), e.g.,=# alter publication p1 add table s1.t1;
ERROR: 22023: cannot add relation "s1.t1" to publication
DETAIL: Table's schema "s1" is already part of the publication or part
of the specified schema list.Is there a reason for this?
Yes, because otherwise, there was confusion while dropping the objects
from publication. Consider in the above case, if we would have allowed
it and then the user performs ALTER PUBLICATION p1 DROP ALL TABLES IN
SCHEMA s1, then (a) shall we remove both schema s1 and a table that is
separately added (s1.t1) from that schema, or (b) just remove schema
s1? There is a point that the user can expect that as she has added
them separately, so we should allow her to drop them separately as
well. OTOH, if we go that way, then it is again questionable that when
the user has asked to Drop all the tables in the schema (via DROP ALL
TABLES IN SCHEMA command) then why keep some tables?
The other confusion from allowing publications to have schemas and
tables from the same schema is that say the user has created a
publication with the command CREATE PUBLICATION pub1 FOR ALL TABLES IN
SCHEMA s1, and then she can ask to allow dropping one of the tables in
the schema by ALTER PUBLICATION pub1 DROP TABLE s1.t1. Now, it will be
tricky to support and I think it doesn't make sense as well.
Similarly, what if the user has first created a publication with
"CREATE PUBLICATION pub1 ADD TABLE s1.t1, s1.t2, ... s1.t99;" and then
tries to drop all tables in one shot by ALTER PUBLICATION DROP ALL
TABLES IN SCHEMA sch1;?
To avoid these confusions, we have disallowed adding a table if its
schema is already part of the publication and vice-versa. Also, there
won't be any additional benefit to doing so.
--
With Regards,
Amit Kapila.
Amit Kapila <amit.kapila16@gmail.com> writes:
To avoid these confusions, we have disallowed adding a table if its
schema is already part of the publication and vice-versa.
Really?
Is there logic in ALTER TABLE SET SCHEMA that rejects the command
dependent on the contents of the publication tables? If so, are
there locks taken in both ALTER TABLE SET SCHEMA and the
publication-modifying commands that are sufficient to prevent
race conditions in such changes?
This position sounds quite untenable from here, even if I found
your arguments-in-support convincing, which I don't really.
ISTM the rule should be along the lines of "table S.T should
be published either if schema S is published or S.T itself is".
There's no obvious need to interconnect the two conditions.
regards, tom lane
On Fri, Sep 9, 2022 at 11:44 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Amit Kapila <amit.kapila16@gmail.com> writes:
To avoid these confusions, we have disallowed adding a table if its
schema is already part of the publication and vice-versa.Really?
Is there logic in ALTER TABLE SET SCHEMA that rejects the command
dependent on the contents of the publication tables?
Yes, it has. For example,
postgres=# create schema s1;
CREATE SCHEMA
postgres=# create table s1.t1(c1 int);
CREATE TABLE
postgres=# create schema s2;
CREATE SCHEMA
postgres=# create publication pub1 for all tables in schema s2, table s1.t1;
CREATE PUBLICATION
postgres=# Alter table s1.t1 set schema s2;
ERROR: cannot move table "t1" to schema "s2"
DETAIL: The schema "s2" and same schema's table "t1" cannot be part
of the same publication "pub1".
If so, are
there locks taken in both ALTER TABLE SET SCHEMA and the
publication-modifying commands that are sufficient to prevent
race conditions in such changes?
Good point. I have checked it and found that ALTER TABLE SET SCHEMA
takes AccessExclusiveLock on relation and AccessShareLock on the
schema which it is going to set. The alter publication command takes
ShareUpdateExclusiveLock on relation for dropping/adding a table to
publication which will prevent any race condition with ALTER TABLE SET
SCHEMA. However, the alter publication command takes AccessShareLock
for dropping/adding schema which won't block with ALTER TABLE SET
SCHEMA command. So, I think we need to change the lock mode for it in
alter publication command.
This position sounds quite untenable from here, even if I found
your arguments-in-support convincing, which I don't really.
ISTM the rule should be along the lines of "table S.T should
be published either if schema S is published or S.T itself is".
There's no obvious need to interconnect the two conditions.
This rule is currently followed when a subscription has more than one
publication. It is just that we didn't allow it in the same
publication because of a fear that it may cause confusion for some of
the users. The other thing to look at here is that the existing case
of a "FOR ALL TABLES" publication also follows a similar rule such
that it doesn't allow adding individual tables if the publication is
for all tables. For example,
postgres=# create publication pub1 for all tables;
CREATE PUBLICATION
postgres=# alter publication pub1 add table t1;
ERROR: publication "pub1" is defined as FOR ALL TABLES
DETAIL: Tables cannot be added to or dropped from FOR ALL TABLES publications.
So, why shouldn't a "FOR ALL TABLES IN SCHEMA" publication follow a
similar behavior?
--
With Regards,
Amit Kapila.
On Fri, Sep 9, 2022 at 5:21 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
So, why shouldn't a "FOR ALL TABLES IN SCHEMA" publication follow a
similar behavior?
Surely that is not the same case at all. If you're publishing
everything, there's no point in also having a specific list of things
that you want published, but when you're publishing only some things,
there is. If my wife tells me to wash everything in the laundry basket
and also my nice pants, and I discover that my nice pants already
happen to be in the laundry basket, I do not tell her:
ERROR: my nice pants are already in the laundry basket
It feels like a mistake to me that there's any catalog representation
at all for a table that is published because it is part of a schema.
The way a feature like this should work is that the schema should be
labelled as published, and we should discover which tables are part of
it at any given time as we go. We shouldn't need separate catalog
entries for each table in the schema just because the schema is
published. But if we do have such catalog entries, surely there should
be a difference between the catalog entry that gets created when the
table is individually published and the one that gets created when the
containing schema is published. We have such tracking in other cases
(coninhcount, conislocal; attinhcount, attislocal).
In my opinion, this shouldn't have been committed working the way it does.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Friday, September 9, 2022 9:57 PM Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Sep 9, 2022 at 5:21 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
So, why shouldn't a "FOR ALL TABLES IN SCHEMA" publication follow a
similar behavior?
Hi
It feels like a mistake to me that there's any catalog representation at all for a
table that is published because it is part of a schema.
The way a feature like this should work is that the schema should be labelled as
published, and we should discover which tables are part of it at any given time as
we go. We shouldn't need separate catalog entries for each table in the schema
just because the schema is published.
IIRC, the feature currently works almost the same as you described. It doesn't
create entry for tables that are published via its schema level, it only record
the published schema and check which tables are part of it.
Sorry, If I misunderstand your points or missed something.
Best regards,
Hou zj
On Fri, Sep 9, 2022 at 10:29 AM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:
IIRC, the feature currently works almost the same as you described. It doesn't
create entry for tables that are published via its schema level, it only record
the published schema and check which tables are part of it.
Oh, well if that's the case, that is great news. But then I don't
understand Amit's comment from before:
Yes, because otherwise, there was confusion while dropping the objects
from publication. Consider in the above case, if we would have allowed
it and then the user performs ALTER PUBLICATION p1 DROP ALL TABLES IN
SCHEMA s1, then (a) shall we remove both schema s1 and a table that is
separately added (s1.t1) from that schema, or (b) just remove schema
s1?
I believe that (b) is the correct behavior, so I assumed that this
issue must be some difficulty in implementing it, like a funny catalog
representation.
Things might be clearer if we'd made the syntax "ALTER PUBLICATION p1
{ ADD | DROP } { TABLE | SCHEMA } name". I don't understand why we
used this ALL TABLES IN SCHEMA language.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Sep 9, 2022, at 8:18 AM, Robert Haas <robertmhaas@gmail.com> wrote:
Things might be clearer if we'd made the syntax "ALTER PUBLICATION p1
{ ADD | DROP } { TABLE | SCHEMA } name". I don't understand why we
used this ALL TABLES IN SCHEMA language.
The conversation, as I recall, was that "ADD SCHEMA foo" would only mean all tables in foo, until publication of other object types became supported, at which point "ADD SCHEMA foo" would suddenly mean more than it did before. People might find that surprising, so the "ALL TABLES IN" was intended to future-proof against surprising behavioral changes.
—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Sep 9, 2022 at 8:48 PM Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Sep 9, 2022 at 10:29 AM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:IIRC, the feature currently works almost the same as you described. It doesn't
create entry for tables that are published via its schema level, it only record
the published schema and check which tables are part of it.Oh, well if that's the case, that is great news.
Yes, the feature works as you and Hou-San have mentioned.
But then I don't
understand Amit's comment from before:Yes, because otherwise, there was confusion while dropping the objects
from publication. Consider in the above case, if we would have allowed
it and then the user performs ALTER PUBLICATION p1 DROP ALL TABLES IN
SCHEMA s1, then (a) shall we remove both schema s1 and a table that is
separately added (s1.t1) from that schema, or (b) just remove schema
s1?I believe that (b) is the correct behavior, so I assumed that this
issue must be some difficulty in implementing it, like a funny catalog
representation.
No, it was because of syntax. IIRC, during development, Greg Nancarrow
raised a point [1]/messages/by-id/CAJcOf-fTRZ3HiA5xU0-O-PT390A7wuUUkjP8uX3aQJLBsJNVmw@mail.gmail.com that a user can expect the individually added
tables for a schema which is also part of the publication to also get
dropped when she specifies DROP ALL TABLES IN SCHEMA. IIRC,
originally, the patch had a behavior (b) but then changed due to
discussion around this point. But now that it seems you and others
don't feel that was right, we can change back to (b) as I think that
shouldn't be difficult to achieve.
Things might be clearer if we'd made the syntax "ALTER PUBLICATION p1
{ ADD | DROP } { TABLE | SCHEMA } name". I don't understand why we
used this ALL TABLES IN SCHEMA language.
It was exactly due to the reason Mark had mentioned in the email [2]/messages/by-id/596EA671-66DF-4285-8560-0270DC062353@enterprisedb.com.
[1]: /messages/by-id/CAJcOf-fTRZ3HiA5xU0-O-PT390A7wuUUkjP8uX3aQJLBsJNVmw@mail.gmail.com
[2]: /messages/by-id/596EA671-66DF-4285-8560-0270DC062353@enterprisedb.com
--
With Regards,
Amit Kapila.
On Fri, Sep 9, 2022 at 2:17 PM Mark Dilger <mark.dilger@enterprisedb.com> wrote:
On Sep 9, 2022, at 8:18 AM, Robert Haas <robertmhaas@gmail.com> wrote:
Things might be clearer if we'd made the syntax "ALTER PUBLICATION p1
{ ADD | DROP } { TABLE | SCHEMA } name". I don't understand why we
used this ALL TABLES IN SCHEMA language.The conversation, as I recall, was that "ADD SCHEMA foo" would only mean all tables in foo, until publication of other object types became supported, at which point "ADD SCHEMA foo" would suddenly mean more than it did before. People might find that surprising, so the "ALL TABLES IN" was intended to future-proof against surprising behavioral changes.
If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all the
tables in the schema to the publication one by one as individual
objects, i.e. add the tables that are currently as of this moment in
that schema to the publication; and I would think that ADD SCHEMA
meant remember that this schema is part of the publication and so
whenever tables are created and dropped in that schema (or moved in
and out) what is being published is automatically updated.
The analogy here seems to be to GRANT, which actually does support
both syntaxes. And if I understand correctly, GRANT ON SCHEMA gives
privileges on the schema; whereas GRANT ON ALL TABLES IN SCHEMA
modifies each table that is currently in that schema (never mind what
happens later).
--
Robert Haas
EDB: http://www.enterprisedb.com
On Sat, 10 Sept 2022 at 19:18, Robert Haas <robertmhaas@gmail.com> wrote:
If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all the
tables in the schema to the publication one by one as individual
objects, i.e. add the tables that are currently as of this moment in
that schema to the publication; and I would think that ADD SCHEMA
meant remember that this schema is part of the publication and so
whenever tables are created and dropped in that schema (or moved in
and out) what is being published is automatically updated.The analogy here seems to be to GRANT, which actually does support
both syntaxes. And if I understand correctly, GRANT ON SCHEMA gives
privileges on the schema; whereas GRANT ON ALL TABLES IN SCHEMA
modifies each table that is currently in that schema (never mind what
happens later).
Yes, except GRANT ON SCHEMA only grants access to the schema - CREATE or
USAGE. You cannot write GRANT SELECT ON SCHEMA to grant access to all
tables in the schema.
On Sep 10, 2022, at 4:17 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I don't understand why we
used this ALL TABLES IN SCHEMA language.The conversation, as I recall, was that "ADD SCHEMA foo" would only mean all tables in foo, until publication of other object types became supported, at which point "ADD SCHEMA foo" would suddenly mean more than it did before. People might find that surprising, so the "ALL TABLES IN" was intended to future-proof against surprising behavioral changes.
If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all the
tables in the schema to the publication one by one as individual
objects
Yes, it appears the syntax was chosen to avoid one kind of confusion, but created another kind. Per the docs on this feature:
FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in the specified list of schemas, including tables created in the future.
Like you, I wouldn't expect that definition, given the behavior of GRANT with respect to the same grammatical construction.
—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Monday, September 12, 2022 1:08 AM Mark Dilger <mark.dilger@enterprisedb.com> wrote:
On Sep 10, 2022, at 4:17 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I don't understand why we
used this ALL TABLES IN SCHEMA language.The conversation, as I recall, was that "ADD SCHEMA foo" would only mean
all tables in foo, until publication of other object types became supported, at
which point "ADD SCHEMA foo" would suddenly mean more than it did before.
People might find that surprising, so the "ALL TABLES IN" was intended to
future-proof against surprising behavioral changes.If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all the
tables in the schema to the publication one by one as individual
objectsYes, it appears the syntax was chosen to avoid one kind of confusion, but created
another kind. Per the docs on this feature:FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in the
specified list of schemas, including tables created in the future.Like you, I wouldn't expect that definition, given the behavior of GRANT with
respect to the same grammatical construction.
I'm a bit unsure if it should be compared to GRANT. Because even if we chose
"ALTER PUBLICATION p1 { ADD | DROP } SCHEMA name", it's also not
consistent with the meaning of GRANT ON SCHEMA, as GRANT ON SCHEMA doesn't
grant rights on the tables within schema if I understand correctly.
I feel we'd better compare the syntax with the existing publication command:
FOR ALL TABLES. If you create a publication FOR ALL TABLES, it means publishing
all the tables in the database *including* tables created in the future. I
think both the syntax and meaning of ALL TABLES IN SCHEMA are consistent with
the existing FOR ALL TABLES.
And the behavior is clearly documented, so personally I think it's fine.
https://www.postgresql.org/docs/devel/sql-createpublication.html
--
FOR ALL TABLES
Marks the publication as one that replicates changes for all tables in the database, including tables created in the future.
FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in the specified list of schemas, including tables created in the future.
--
Besides, as mentioned(and suggested by Tom[1]/messages/by-id/155565.1628954580@sss.pgh.pa.us), we might support publishing
SEQUENCE(or others) in the future. It would give more flexibility to user if we
have another FOR ALL SEQUENCES(or other objects) IN SCHEMA.
[1]: /messages/by-id/155565.1628954580@sss.pgh.pa.us
Best regards,
Hou zj
On Sat, 10 Sept 2022 at 07:32, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 9, 2022 at 8:48 PM Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Sep 9, 2022 at 10:29 AM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:IIRC, the feature currently works almost the same as you described. It doesn't
create entry for tables that are published via its schema level, it only record
the published schema and check which tables are part of it.Oh, well if that's the case, that is great news.
Yes, the feature works as you and Hou-San have mentioned.
But then I don't
understand Amit's comment from before:Yes, because otherwise, there was confusion while dropping the objects
from publication. Consider in the above case, if we would have allowed
it and then the user performs ALTER PUBLICATION p1 DROP ALL TABLES IN
SCHEMA s1, then (a) shall we remove both schema s1 and a table that is
separately added (s1.t1) from that schema, or (b) just remove schema
s1?I believe that (b) is the correct behavior, so I assumed that this
issue must be some difficulty in implementing it, like a funny catalog
representation.No, it was because of syntax. IIRC, during development, Greg Nancarrow
raised a point [1] that a user can expect the individually added
tables for a schema which is also part of the publication to also get
dropped when she specifies DROP ALL TABLES IN SCHEMA. IIRC,
originally, the patch had a behavior (b) but then changed due to
discussion around this point. But now that it seems you and others
don't feel that was right, we can change back to (b) as I think that
shouldn't be difficult to achieve.
I have made the changes to allow creation of publication with a schema
and table of the same schema. The attached patch has the changes for
the same.
I'm planning to review and test the patch further.
Regards,
Vignesh
Attachments:
v1-0001-Allow-creation-of-publication-with-schema-and-tab.patchapplication/octet-stream; name=v1-0001-Allow-creation-of-publication-with-schema-and-tab.patchDownload
From 63ac94b530bae358d9a781280febe5c8cfa5334f Mon Sep 17 00:00:00 2001
From: Vigneshwaran C <vignesh21@gmail.com>
Date: Mon, 12 Sep 2022 11:24:54 +0530
Subject: [PATCH v1] Allow creation of publication with schema and table of the
same schema.
Allow creation of publication with schema and table of the same schema.
---
doc/src/sgml/ref/alter_publication.sgml | 16 ++--
doc/src/sgml/ref/create_publication.sgml | 10 ---
src/backend/commands/publicationcmds.c | 99 +----------------------
src/backend/commands/tablecmds.c | 27 -------
src/bin/pg_dump/t/002_pg_dump.pl | 14 ++++
src/test/regress/expected/alter_table.out | 14 +++-
src/test/regress/expected/publication.out | 56 ++++++++++---
src/test/regress/sql/alter_table.sql | 3 +-
src/test/regress/sql/publication.sql | 19 ++++-
9 files changed, 94 insertions(+), 164 deletions(-)
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89ee91..cebedc4058 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -80,14 +82,6 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
SCHEMA</literal> publication must be a superuser. However, a superuser can
change the ownership of a publication regardless of these restrictions.
</para>
-
- <para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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.
- </para>
</refsect1>
<refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index f61641896a..96758af4f7 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -109,11 +109,6 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -135,11 +130,6 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
the specified list of schemas, including tables created in the future.
</para>
- <para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
- </para>
-
<para>
Only persistent base tables and partitioned tables present in the schema
will be included as part of the publication. Temporary tables, unlogged
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 8b574b86c4..e36068893d 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.
@@ -858,9 +819,6 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
List *rels;
rels = OpenTableList(relations);
- CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist,
- PUBLICATIONOBJ_TABLE);
-
TransformPubWhereClauses(rels, pstate->p_sourcetext,
publish_via_partition_root);
@@ -1110,8 +1068,7 @@ InvalidatePublicationRels(List *relids)
*/
static void
AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
- List *tables, List *schemaidlist,
- const char *queryString)
+ List *tables, const char *queryString)
{
List *rels = NIL;
Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup);
@@ -1129,16 +1086,6 @@ 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);
@@ -1154,9 +1101,6 @@ 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);
@@ -1307,19 +1251,7 @@ AlterPublicationSchemas(AlterPublicationStmt *stmt,
*/
LockSchemaList(schemaidlist);
if (stmt->action == AP_AddObjects)
- {
- List *rels;
- List *reloids;
-
- reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT);
- rels = OpenRelIdList(reloids);
-
- CheckObjSchemaNotAlreadyInPublication(rels, schemaidlist,
- PUBLICATIONOBJ_TABLES_IN_SCHEMA);
-
- CloseTableList(rels);
PublicationAddSchemas(pubform->oid, schemaidlist, false, stmt);
- }
else if (stmt->action == AP_DropObjects)
PublicationDropSchemas(pubform->oid, schemaidlist, false);
else /* AP_SetObjects */
@@ -1453,8 +1385,7 @@ 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);
AlterPublicationSchemas(stmt, tup, schemaidlist);
}
@@ -1569,32 +1500,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 53b0f3a9c1..ac95e18e71 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -16397,33 +16397,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/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..eb0c1373c9 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;
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..ff1d49ec10 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;
--
2.32.0
At Mon, 12 Sep 2022 04:26:48 +0000, "houzj.fnst@fujitsu.com" <houzj.fnst@fujitsu.com> wrote in
On Monday, September 12, 2022 1:08 AM Mark Dilger <mark.dilger@enterprisedb.com> wrote:
On Sep 10, 2022, at 4:17 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I don't understand why we
used this ALL TABLES IN SCHEMA language.The conversation, as I recall, was that "ADD SCHEMA foo" would only mean
all tables in foo, until publication of other object types became supported, at
which point "ADD SCHEMA foo" would suddenly mean more than it did before.
People might find that surprising, so the "ALL TABLES IN" was intended to
future-proof against surprising behavioral changes.If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all the
tables in the schema to the publication one by one as individual
objectsYes, it appears the syntax was chosen to avoid one kind of confusion, but created
another kind. Per the docs on this feature:FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in the
specified list of schemas, including tables created in the future.Like you, I wouldn't expect that definition, given the behavior of GRANT with
respect to the same grammatical construction.I'm a bit unsure if it should be compared to GRANT. Because even if we chose
"ALTER PUBLICATION p1 { ADD | DROP } SCHEMA name", it's also not
consistent with the meaning of GRANT ON SCHEMA, as GRANT ON SCHEMA doesn't
grant rights on the tables within schema if I understand correctly.I feel we'd better compare the syntax with the existing publication command:
FOR ALL TABLES. If you create a publication FOR ALL TABLES, it means publishing
all the tables in the database *including* tables created in the future. I
think both the syntax and meaning of ALL TABLES IN SCHEMA are consistent with
the existing FOR ALL TABLES.
IMHO, I feel closer to Robert. "ALL TABLES IN SCHEMA" sounds like the
concrete tables at the time of invocation. While I agree that it is
not directly comparable to GRANT, but if I see "ALTER PUBLICATION p1
ADD SCHEMA s1", I automatically translate that into "all tables in the
schema s1 at the time of using this publication". At least, it would
cause less confusion when it were "ALT PUB p1 DROP SCEMA s1" aginst
"DROP ALL TABLES IN SCHEMA s1".
However..
And the behavior is clearly documented, so personally I think it's fine.
https://www.postgresql.org/docs/devel/sql-createpublication.html
--
FOR ALL TABLES
Marks the publication as one that replicates changes for all tables in the database, including tables created in the future.
FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in the specified list of schemas, including tables created in the future.
--Besides, as mentioned(and suggested by Tom[1]), we might support publishing
SEQUENCE(or others) in the future. It would give more flexibility to user if we
have another FOR ALL SEQUENCES(or other objects) IN SCHEMA.
Fair point. Should be stupid, but how about the following?
CREATE PUBLICATION p1 FOR TABLES * IN SCHEMA s1;
DROP PUBLICATION p1 FOR TABLES * IN SCHEMA s1;
ATLER PUBLICATION p1 ADD TABLES * IN SCHEMA s1;
ALTER PUBLICATION p1 DROP TABLES * IN SCHEMA s1;
This is an analog of synchronous_standby_names. But I'm not sure a
bare asterisc can appear there.. We could use ANY instead?
CREATE PUBLICATION p1 FOR TABLES ANY IN SCHEMA s1;
...
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
On Tuesday, September 13, 2022 12:40 PM Kyotaro Horiguchi <horikyota.ntt@gmail.com> wrote:
At Mon, 12 Sep 2022 04:26:48 +0000, "houzj.fnst@fujitsu.com"
<houzj.fnst@fujitsu.com> wrote inOn Monday, September 12, 2022 1:08 AM Mark Dilger <mark.dilger@enterprisedb.com> wrote:
On Sep 10, 2022, at 4:17 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I don't understand why we
used this ALL TABLES IN SCHEMA language.The conversation, as I recall, was that "ADD SCHEMA foo" would
only meanall tables in foo, until publication of other object types became
supported, at which point "ADD SCHEMA foo" would suddenly mean more than it did before.
People might find that surprising, so the "ALL TABLES IN" was
intended to future-proof against surprising behavioral changes.If I encountered this syntax in a vacuum, that's not what I would
think. I would think that ADD ALL TABLES IN SCHEMA meant add all
the tables in the schema to the publication one by one as
individual objectsYes, it appears the syntax was chosen to avoid one kind of
confusion, but created another kind. Per the docs on this feature:FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all
tables in the specified list of schemas, including tables created in the future.Like you, I wouldn't expect that definition, given the behavior of
GRANT with respect to the same grammatical construction.I'm a bit unsure if it should be compared to GRANT. Because even if we
chose "ALTER PUBLICATION p1 { ADD | DROP } SCHEMA name", it's also not
consistent with the meaning of GRANT ON SCHEMA, as GRANT ON SCHEMA
doesn't grant rights on the tables within schema if I understand correctly.I feel we'd better compare the syntax with the existing publication command:
FOR ALL TABLES. If you create a publication FOR ALL TABLES, it means
publishing all the tables in the database *including* tables created
in the future. I think both the syntax and meaning of ALL TABLES IN
SCHEMA are consistent with the existing FOR ALL TABLES.IMHO, I feel closer to Robert. "ALL TABLES IN SCHEMA" sounds like the
concrete tables at the time of invocation. While I agree that it is not directly
comparable to GRANT, but if I see "ALTER PUBLICATION p1 ADD SCHEMA s1", I
automatically translate that into "all tables in the schema s1 at the time of using
this publication". At least, it would cause less confusion when it were "ALT PUB
p1 DROP SCEMA s1" aginst "DROP ALL TABLES IN SCHEMA s1".However..
And the behavior is clearly documented, so personally I think it's fine.
https://www.postgresql.org/docs/devel/sql-createpublication.html
--
FOR ALL TABLES
Marks the publication as one that replicates changes for all tables in thedatabase, including tables created in the future.
FOR ALL TABLES IN SCHEMA
Marks the publication as one that replicates changes for all tables in thespecified list of schemas, including tables created in the future.
--
Besides, as mentioned(and suggested by Tom[1]), we might support
publishing SEQUENCE(or others) in the future. It would give more
flexibility to user if we have another FOR ALL SEQUENCES(or other objects) INSCHEMA.
[1]
/messages/by-id/155565.1628954580@sss.pgh.pa.u
s
Fair point. Should be stupid, but how about the following?
CREATE PUBLICATION p1 FOR TABLES * IN SCHEMA s1;
DROP PUBLICATION p1 FOR TABLES * IN SCHEMA s1;
ATLER PUBLICATION p1 ADD TABLES * IN SCHEMA s1; ALTER PUBLICATION
p1 DROP TABLES * IN SCHEMA s1;This is an analog of synchronous_standby_names. But I'm not sure a bare
asterisc can appear there.. We could use ANY instead?CREATE PUBLICATION p1 FOR TABLES ANY IN SCHEMA s1; ...
Thanks for the suggestions. But personally, I am not sure if this is better the
current syntax as it seems syntactically inconsistent with the existing "FOR
ALL TABLES". Also, the behavior to include future tables is consistent with FOR
ALL TABLES.
Best regards,
Hou zj
On Monday, September 12, 2022 10:14 PM vignesh C <vignesh21@gmail.com> wrote:
On Sat, 10 Sept 2022 at 07:32, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 9, 2022 at 8:48 PM Robert Haas <robertmhaas@gmail.com>
wrote:
On Fri, Sep 9, 2022 at 10:29 AM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:IIRC, the feature currently works almost the same as you
described. It doesn't create entry for tables that are published
via its schema level, it only record the published schema and check whichtables are part of it.
Oh, well if that's the case, that is great news.
Yes, the feature works as you and Hou-San have mentioned.
But then I don't
understand Amit's comment from before:Yes, because otherwise, there was confusion while dropping the
objects from publication. Consider in the above case, if we would
have allowed it and then the user performs ALTER PUBLICATION p1
DROP ALL TABLES IN SCHEMA s1, then (a) shall we remove both schema
s1 and a table that is separately added (s1.t1) from that schema,
or (b) just remove schema s1?I believe that (b) is the correct behavior, so I assumed that this
issue must be some difficulty in implementing it, like a funny
catalog representation.No, it was because of syntax. IIRC, during development, Greg Nancarrow
raised a point [1] that a user can expect the individually added
tables for a schema which is also part of the publication to also get
dropped when she specifies DROP ALL TABLES IN SCHEMA. IIRC,
originally, the patch had a behavior (b) but then changed due to
discussion around this point. But now that it seems you and others
don't feel that was right, we can change back to (b) as I think that
shouldn't be difficult to achieve.I have made the changes to allow creation of publication with a schema and
table of the same schema. The attached patch has the changes for the same.
I'm planning to review and test the patch further.
Thanks for the patch. While reviewing it, I found that the column list behavior
might need to be changed or confirmed after allowing the above case.
After applying the patch, we support adding a table with column list along with
the table's schema[1]- CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN SCHEMA public; -----, and it will directly apply the column list in the
logical replication after applying the patch.
[1]: - CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN SCHEMA public; -----
CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN SCHEMA public;
-----
If from the point of view of consistency, for column list, we could report an
ERROR because we currently don't allow using different column lists for a
table. Maybe an ERROR like:
"ERROR: cannot use column for table x when the table's schema is also in the publication"
But if we want to report an ERROR for column list in above case. We might need
to restrict the ALTER TABLE SET SCHEMA as well because user could move a table
which is published with column list to a schema that is also published in the
publication, so we might need to add some similar check(which is removed in
Vignesh's patch) to tablecmd.c to disallow this case.
Another option could be just ingore the column list if table's schema is also
part of publication. But it seems slightly inconsistent with the rule that we
disallow using different column list for a table.
Best regards,
Hou zj
On 14.09.22 07:10, houzj.fnst@fujitsu.com wrote:
After applying the patch, we support adding a table with column list along with
the table's schema[1], and it will directly apply the column list in the
logical replication after applying the patch.[1]--
CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN SCHEMA public;
-----If from the point of view of consistency, for column list, we could report an
ERROR because we currently don't allow using different column lists for a
table. Maybe an ERROR like:"ERROR: cannot use column for table x when the table's schema is also in the publication"
But if we want to report an ERROR for column list in above case. We might need
to restrict the ALTER TABLE SET SCHEMA as well because user could move a table
which is published with column list to a schema that is also published in the
publication, so we might need to add some similar check(which is removed in
Vignesh's patch) to tablecmd.c to disallow this case.Another option could be just ingore the column list if table's schema is also
part of publication. But it seems slightly inconsistent with the rule that we
disallow using different column list for a table.
Ignoring things doesn't seem like a good idea.
A solution might be to disallow adding any schemas to a publication if
column lists on a table are specified.
On Thursday, September 15, 2022 3:37 AM Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:
Hi,
On 14.09.22 07:10, houzj.fnst@fujitsu.com wrote:
After applying the patch, we support adding a table with column list
along with the table's schema[1], and it will directly apply the
column list in the logical replication after applying the patch.[1]--
CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN
SCHEMA public;
-----If from the point of view of consistency, for column list, we could
report an ERROR because we currently don't allow using different
column lists for a table. Maybe an ERROR like:"ERROR: cannot use column for table x when the table's schema is also in the
publication"
But if we want to report an ERROR for column list in above case. We
might need to restrict the ALTER TABLE SET SCHEMA as well because user
could move a table which is published with column list to a schema
that is also published in the publication, so we might need to add
some similar check(which is removed in Vignesh's patch) to tablecmd.c todisallow this case.
Another option could be just ingore the column list if table's schema
is also part of publication. But it seems slightly inconsistent with
the rule that we disallow using different column list for a table.Ignoring things doesn't seem like a good idea.
A solution might be to disallow adding any schemas to a publication if column
lists on a table are specified.
Thanks for the suggestion. If I understand correctly, you mean we can disallow
publishing a table with column list and any schema(a schema that the table
might not be part of) in the same publication[1]CREATE PUBLICATION pub FOR TABLE public.test(a), ALL TABLES IN SCHEMA s2; ERROR: "cannot add schema to publication when column list is used in the published table" --.
something like--
[1]: CREATE PUBLICATION pub FOR TABLE public.test(a), ALL TABLES IN SCHEMA s2; ERROR: "cannot add schema to publication when column list is used in the published table" --
ERROR: "cannot add schema to publication when column list is used in the published table"
--
Personally, it looks acceptable to me as user can anyway achieve the same
purpose by creating serval publications and combine it and we can save the
restriction at ALTER TABLE SET SCHEMA. Although it restricts some cases.
I will post a top-up patch about this soon.
About the row filter handling, maybe we don't need to restrict row filter like
above ? Because the rule is to simply merge the row filter with 'OR' among
publications, so it seems we could ignore the row filter in the publication when
the table's schema is also published in the same publication(which means no filter).
Best regards,
Hou zj
On Thursday, September 15, 2022 10:48 AM houzj.fnst@fujitsu.com wrote:
On Thursday, September 15, 2022 3:37 AM Peter Eisentraut
<peter.eisentraut@enterprisedb.com> wrote:Hi,
On 14.09.22 07:10, houzj.fnst@fujitsu.com wrote:
After applying the patch, we support adding a table with column list
along with the table's schema[1], and it will directly apply the
column list in the logical replication after applying the patch.[1]--
CREATE PUBLICATION pub FOR TABLE public.test(a), FOR ALL TABLES IN
SCHEMA public;
-----If from the point of view of consistency, for column list, we could
report an ERROR because we currently don't allow using different
column lists for a table. Maybe an ERROR like:"ERROR: cannot use column for table x when the table's schema is
also in thepublication"
But if we want to report an ERROR for column list in above case. We
might need to restrict the ALTER TABLE SET SCHEMA as well because
user could move a table which is published with column list to a
schema that is also published in the publication, so we might need
to add some similar check(which is removed in Vignesh's patch) to
tablecmd.c todisallow this case.
Another option could be just ingore the column list if table's
schema is also part of publication. But it seems slightly
inconsistent with the rule that we disallow using different column list for atable.
Ignoring things doesn't seem like a good idea.
A solution might be to disallow adding any schemas to a publication if
column lists on a table are specified.Thanks for the suggestion. If I understand correctly, you mean we can disallow
publishing a table with column list and any schema(a schema that the table
might not be part of) in the same publication[1].something like--
[1]CREATE PUBLICATION pub FOR TABLE public.test(a), ALL TABLES IN SCHEMA
s2;
ERROR: "cannot add schema to publication when column list is used in the
published table"
--Personally, it looks acceptable to me as user can anyway achieve the same
purpose by creating serval publications and combine it and we can save the
restriction at ALTER TABLE SET SCHEMA. Although it restricts some cases.
I will post a top-up patch about this soon.About the row filter handling, maybe we don't need to restrict row filter like
above ? Because the rule is to simply merge the row filter with 'OR' among
publications, so it seems we could ignore the row filter in the publication when
the table's schema is also published in the same publication(which means no
filter).
Attach the new version patch which added suggested restriction for column list
and merged Vignesh's patch.
Some other document might need to be updated. I will update them soon.
Best regards,
Hou zj
Attachments:
v3-0001-Allow-creation-of-publication-with-schema-and-tab.patchapplication/octet-stream; name=v3-0001-Allow-creation-of-publication-with-schema-and-tab.patchDownload
From 6edc83bb25feba45801e24221a27ed62099c603d Mon Sep 17 00:00:00 2001
From: Vigneshwaran C <vignesh21@gmail.com>
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.
</para>
+ <para>
+ Column list cannot be specified when the publication publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal>.
+ </para>
+
</sect2>
<sect2 id="logical-replication-col-list-partitioned">
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 <replaceable class="parameter">name</replaceable> RENAME TO <r
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
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,11 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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 <literal>ALL TABLES IN SCHEMA</literal>, 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.
</para>
</refsect1>
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 <replaceable class="parameter">name</replaceable>
materialized views, and regular views cannot be part of a publication.
</para>
+ <para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
<para>
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 <replaceable class="parameter">name</replaceable>
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -273,6 +273,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
system columns.
</para>
+ <para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
<para>
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
On Thu, Sep 15, 2022 at 10:57 PM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:
...
Attach the new version patch which added suggested restriction for column list
and merged Vignesh's patch.Some other document might need to be updated. I will update them soon.
Best regards,
Hou zj
Hi Hou-san.
FYI, I found your v3 patch apply was broken due to a very recent changes pushed:
e.g.
error: patch failed: doc/src/sgml/logical-replication.sgml:1142
~~
PSA a rebase of your same patch (I left the version number the same)
------
Kind Regards,
Peter Smith.
Fujitsu Australia
Attachments:
v3-0001-Allow-creation-of-publication-with-schema-and-tab.patchapplication/octet-stream; name=v3-0001-Allow-creation-of-publication-with-schema-and-tab.patchDownload
From 5defea9cdb701d424b5768dea3ea3fbf0d18fd48 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Fri, 16 Sep 2022 11:22:14 +1000
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 1ae3287..7deb3ad 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a;
</para>
<para>
+ Column list cannot be specified when the publication publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal>.
+ </para>
+
+ <para>
For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list
is used. If <literal>publish_via_partition_root</literal> is
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89e..516f589 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,11 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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 <literal>ALL TABLES IN SCHEMA</literal>, 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.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4b..0ced7da 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the
publication. So, even operations that are performed directly on a
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -274,6 +274,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
+ <para>
For published partitioned tables, the row filter for each
partition is taken from the published partitioned table if the
publication parameter <literal>publish_via_partition_root</literal> is true,
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 6af3570..f37827f 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 8b574b8..d0ea7f0 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);
@@ -215,44 +214,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;
@@ -733,6 +695,17 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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
* the column list on partitioned table in this case.
@@ -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)
@@ -1570,32 +1553,6 @@ RemovePublicationSchemaById(Oid psoid)
}
/*
- * 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
* add them to a publication.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e3233a8..5277b7b 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 62e0ffe..caa2c90 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 2873b66..714b132 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 d63f4f1..0906c08 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 e6e082d..156a82c 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 e7013f5..3f01fdd 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 a56387e..923b7ea 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 f5f8a67..020a9c3 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)"
--
1.8.3.1
On Thu, Sep 15, 2022 at 8:18 AM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:
On Thursday, September 15, 2022 3:37 AM Peter Eisentraut <peter.eisentraut@enterprisedb.com> wrote:
Another option could be just ingore the column list if table's schema
is also part of publication. But it seems slightly inconsistent with
the rule that we disallow using different column list for a table.Ignoring things doesn't seem like a good idea.
A solution might be to disallow adding any schemas to a publication if column
lists on a table are specified.Thanks for the suggestion. If I understand correctly, you mean we can disallow
publishing a table with column list and any schema(a schema that the table
might not be part of) in the same publication[1].something like--
[1]CREATE PUBLICATION pub FOR TABLE public.test(a), ALL TABLES IN SCHEMA s2;
ERROR: "cannot add schema to publication when column list is used in the published table"
--Personally, it looks acceptable to me as user can anyway achieve the same
purpose by creating serval publications and combine it and we can save the
restriction at ALTER TABLE SET SCHEMA. Although it restricts some cases.
Yeah, I agree that it restricts more cases for how different
combinations can be specified for a publication but OTOH it helps to
uplift restriction in ALTER TABLE ... SET SCHEMA which seems like a
good trade-off.
I will post a top-up patch about this soon.
About the row filter handling, maybe we don't need to restrict row filter like
above ? Because the rule is to simply merge the row filter with 'OR' among
publications, so it seems we could ignore the row filter in the publication when
the table's schema is also published in the same publication(which means no filter).
Yeah, this is what we are doing internally when combining multiple
publications but let me explain with an example the case of a single
publication so that if anybody has any objections to it, we can
discuss the same.
Case-1: When row filter is specified *without* ALL TABLES IN SCHEMA clause
postgres=# create table t1(c1 int, c2 int, c3 int);
CREATE TABLE
postgres=# create publication pub1 for table t1 where (c1 > 10);
CREATE PUBLICATION
postgres=# select pubname, schemaname, tablename, rowfilter from
pg_publication_tables;
pubname | schemaname | tablename | rowfilter
---------+------------+-----------+-----------
pub1 | public | t1 | (c1 > 10)
(1 row)
Case-2: When row filter is specified *with* ALL TABLES IN SCHEMA clause
postgres=# create schema s1;
CREATE SCHEMA
postgres=# create table s1.t2(c1 int, c2 int, c3 int);
CREATE TABLE
postgres=# create publication pub2 for table s1.t2 where (c1 > 10),
all tables in schema s1;
CREATE PUBLICATION
postgres=# select pubname, schemaname, tablename, rowfilter from
pg_publication_tables;
pubname | schemaname | tablename | rowfilter
---------+------------+-----------+-----------
pub1 | public | t1 | (c1 > 10)
pub2 | s1 | t2 |
(2 rows)
So, for case-2, the rowfilter is not considered. Note, case-2 was not
possible before the patch which is discussed here and after the patch,
the behavior will be the same as we have it before when we combine
publications.
--
With Regards,
Amit Kapila.
On Thu, Sep 15, 2022 at 6:27 PM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:
Attach the new version patch which added suggested restriction for column list
and merged Vignesh's patch.
Few comments:
============
1.
static void
-CheckPubRelationColumnList(List *tables, const char *queryString,
+CheckPubRelationColumnList(List *tables, bool publish_schema,
+ const char *queryString,
bool pubviaroot)
It is better to keep bool parameters together at the end.
2.
/*
+ * 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."));
I think it would be better to explain why we disallow this case.
3.
+ 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"));
A full stop is missing at the end in the errdetail message.
4. I have modified a few comments in the attached. Please check and if
you like the changes then please include those in the next version.
--
With Regards,
Amit Kapila.
Attachments:
change_comments_amit_1.patchapplication/octet-stream; name=change_comments_amit_1.patchDownload
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index f37827f42e..5ba4c1d1bd 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -1124,9 +1124,8 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
values[0] = ObjectIdGetDatum(relid);
/*
- * 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.
+ * We don't consider row filters or column lists for FOR ALL TABLES or
+ * FOR ALL TABLES IN SCHEMA publications.
*/
if (!publication->alltables &&
!SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index d0ea7f0e38..6a4f784604 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -1412,14 +1412,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);
On Friday, September 16, 2022 1:42 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Thu, Sep 15, 2022 at 6:27 PM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:Attach the new version patch which added suggested restriction for
column list and merged Vignesh's patch.Few comments: ============ 1. static void -CheckPubRelationColumnList(List *tables, const char *queryString, +CheckPubRelationColumnList(List *tables, bool publish_schema, + const char *queryString, bool pubviaroot)It is better to keep bool parameters together at the end.
2. /* + * 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."));I think it would be better to explain why we disallow this case.
3. + 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"));A full stop is missing at the end in the errdetail message.
4. I have modified a few comments in the attached. Please check and if you like
the changes then please include those in the next version.
Thanks for the comments.
Attach the new version patch which addressed above comments and ran pgident.
I also improved some codes and documents based on some comments
given by Vignesh and Peter offlist.
Best regards,
Hou zj
Attachments:
v4-0001-Allow-publications-with-schema-and-table-of-the-s.patchapplication/octet-stream; name=v4-0001-Allow-publications-with-schema-and-table-of-the-s.patchDownload
From f3c79659857d93734d19188abf520556f24941bf Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Fri, 16 Sep 2022 11:22:14 +1000
Subject: [PATCH v4] Allow publications with schema and table of the same
schema.
We previously thought that allowing such cases can confuse users when they
specify DROP ALL 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
---
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 | 15 +-
src/backend/commands/publicationcmds.c | 159 ++++++++------------
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, 259 insertions(+), 183 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 1ae3287f22..0ab768d914 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.
</para>
+ <para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
<para>
For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89ee91..00359e206b 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,11 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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 at the same time a table that specifies a column list and any
+ schema 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.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4bf73..0ced7dae19 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -102,6 +102,11 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
materialized views, and regular views cannot be part of a publication.
</para>
+ <para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
<para>
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 <replaceable class="parameter">name</replaceable>
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -273,6 +273,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
system columns.
</para>
+ <para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
<para>
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..28399a508e 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 ALL 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 8b574b86c4..1f21c6a850 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.
@@ -718,10 +679,22 @@ TransformPubWhereClauses(List *tables, const char *queryString,
/*
* Check the publication column lists expression for all relations in the list.
+ *
+ * Throw an error if column list is specified when schema is also published or
+ * column list is used on a partitioned table when pubviaroot is false.
+ *
+ * XXX The restriction for column list and schema is used to prevent the
+ * problematic case that a publication has both a schema and the same schema's
+ * table with column list which violates the rule that different column lists
+ * cannot be used for the same table. We could restrict the actual problematic
+ * case but then we need a restriction during ALTER TABLE ... SET SCHEMA to
+ * prevent the problematic case which seems not good. So, we just forbid having
+ * any schema on a publication if column lists on a table are specified (and
+ * vice versa).
*/
static void
CheckPubRelationColumnList(List *tables, const char *queryString,
- bool pubviaroot)
+ bool publish_schema, bool pubviaroot)
{
ListCell *lc;
@@ -732,6 +705,18 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
if (pri->columns == NIL)
continue;
+ /*
+ * Disallow specifying 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 +843,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,7 +1093,7 @@ InvalidatePublicationRels(List *relids)
*/
static void
AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup,
- List *tables, List *schemaidlist,
+ List *tables, bool publish_schema,
const char *queryString)
{
List *rels = NIL;
@@ -1129,19 +1112,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 +1130,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 +1282,36 @@ 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 comments above CheckPubRelationColumnList for
+ * the reason)
+ */
+ 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 +1423,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,7 +1440,7 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt)
errmsg("publication \"%s\" does not exist",
stmt->pubname));
- AlterPublicationTables(stmt, tup, relations, schemaidlist,
+ AlterPublicationTables(stmt, tup, relations, schemaidlist != NIL,
pstate->p_sourcetext);
AlterPublicationSchemas(stmt, tup, schemaidlist);
}
@@ -1569,32 +1556,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..3db7f49c63 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 includes a
+ * FOR ALL 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 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..95ea32cf50 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
On Fri, Sep 16, 2022 at 1:09 PM houzj.fnst@fujitsu.com
<houzj.fnst@fujitsu.com> wrote:
Attach the new version patch which addressed above comments and ran pgident.
I also improved some codes and documents based on some comments
given by Vignesh and Peter offlist.
Thanks, the patch looks mostly good to me. I have made a few cosmetic
changes and edited a few comments. I would like to push this to HEAD
and backpatch it to 15 by Tuesday unless there are any comments. I
think we should back patch this because otherwise, users will see a
change in behavior in 16 but if others don't think the same way then
we can consider pushing this to HEAD only.
--
With Regards,
Amit Kapila.
Attachments:
v5-0001-Allow-publications-with-schema-and-table-of-the-s.patchapplication/octet-stream; name=v5-0001-Allow-publications-with-schema-and-table-of-the-s.patchDownload
From 05434d7a98d1e54f79453451806c73779363718c Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Fri, 16 Sep 2022 11:22:14 +1000
Subject: [PATCH v6] Allow publications with schema and table of the same
schema.
We previously thought that allowing such cases can confuse users when they
specify DROP ALL 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
---
doc/src/sgml/logical-replication.sgml | 5 +
doc/src/sgml/ref/alter_publication.sgml | 15 ++-
doc/src/sgml/ref/create_publication.sgml | 20 ++--
src/backend/catalog/pg_publication.c | 15 ++-
src/backend/commands/publicationcmds.c | 156 ++++++++++------------------
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, 251 insertions(+), 185 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 1ae3287..0ab768d 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a;
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list
is used. If <literal>publish_via_partition_root</literal> is
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89e..970df22 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,8 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4b..0ced7da 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the
publication. So, even operations that are performed directly on a
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -274,6 +274,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
+ <para>
For published partitioned tables, the row filter for each
partition is taken from the published partitioned table if the
publication parameter <literal>publish_via_partition_root</literal> is true,
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 6af3570..28399a5 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 ALL 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 8b574b8..6711a25 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);
@@ -215,44 +214,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;
@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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
* the column list on partitioned table in this case.
@@ -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);
}
@@ -1570,32 +1550,6 @@ RemovePublicationSchemaById(Oid psoid)
}
/*
- * 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
* add them to a publication.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e3233a8..5277b7b 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 62e0ffe..3db7f49 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 includes a
+ * FOR ALL 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 2873b66..714b132 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 d63f4f1..0906c08 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 e6e082d..95ea32c 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 e7013f5..3f01fdd 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 a56387e..923b7ea 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 f5f8a67..020a9c3 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)"
--
1.8.3.1
On Saturday, September 17, 2022 11:22 AM Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Sep 16, 2022 at 1:09 PM houzj.fnst@fujitsu.com <houzj.fnst@fujitsu.com>
wrote:Attach the new version patch which addressed above comments and ran
pgident.
I also improved some codes and documents based on some comments given
by Vignesh and Peter offlist.Thanks, the patch looks mostly good to me. I have made a few cosmetic changes
and edited a few comments. I would like to push this to HEAD and backpatch it
to 15 by Tuesday unless there are any comments. I think we should back patch
this because otherwise, users will see a change in behavior in 16 but if others
don't think the same way then we can consider pushing this to HEAD only.
Thanks for the patch.
I rebased it based on PG15 and here is the patch.
Best regards,
Hou zj
Attachments:
v5-0001-Allow-publications-with-schema-and-table-of-the-s.patchapplication/octet-stream; name=v5-0001-Allow-publications-with-schema-and-table-of-the-s.patchDownload
From 05434d7a98d1e54f79453451806c73779363718c Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Fri, 16 Sep 2022 11:22:14 +1000
Subject: [PATCH v6] Allow publications with schema and table of the same
schema.
We previously thought that allowing such cases can confuse users when they
specify DROP ALL 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
---
doc/src/sgml/logical-replication.sgml | 5 +
doc/src/sgml/ref/alter_publication.sgml | 15 ++-
doc/src/sgml/ref/create_publication.sgml | 20 ++--
src/backend/catalog/pg_publication.c | 15 ++-
src/backend/commands/publicationcmds.c | 156 ++++++++++------------------
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, 251 insertions(+), 185 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 1ae3287..0ab768d 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a;
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list
is used. If <literal>publish_via_partition_root</literal> is
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89e..970df22 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,8 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4b..0ced7da 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the
publication. So, even operations that are performed directly on a
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -274,6 +274,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
+ <para>
For published partitioned tables, the row filter for each
partition is taken from the published partitioned table if the
publication parameter <literal>publish_via_partition_root</literal> is true,
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 6af3570..28399a5 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 ALL 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 8b574b8..6711a25 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);
@@ -215,44 +214,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;
@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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
* the column list on partitioned table in this case.
@@ -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);
}
@@ -1570,32 +1550,6 @@ RemovePublicationSchemaById(Oid psoid)
}
/*
- * 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
* add them to a publication.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e3233a8..5277b7b 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 62e0ffe..3db7f49 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 includes a
+ * FOR ALL 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 2873b66..714b132 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 d63f4f1..0906c08 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 e6e082d..95ea32c 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 e7013f5..3f01fdd 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 a56387e..923b7ea 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 f5f8a67..020a9c3 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)"
--
1.8.3.1
v5-PG15-0001-Allow-publications-with-schema-and-table-of-the-s.patchapplication/octet-stream; name=v5-PG15-0001-Allow-publications-with-schema-and-table-of-the-s.patchDownload
From a95a8985f45aded0fc89280dc641c8cf59e2117f Mon Sep 17 00:00:00 2001
From: "houzj.fnst" <houzj.fnst@cn.fujitsu.com>
Date: Sat, 17 Sep 2022 09:53:45 +0800
Subject: [PATCH v5] Allow publications with schema and table of the same
schema.
We previously thought that allowing such cases can confuse users when they
specify DROP ALL 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
---
doc/src/sgml/logical-replication.sgml | 5 +
doc/src/sgml/ref/alter_publication.sgml | 15 ++-
doc/src/sgml/ref/create_publication.sgml | 20 ++--
src/backend/catalog/pg_publication.c | 15 ++-
src/backend/commands/publicationcmds.c | 156 ++++++++++------------------
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, 251 insertions(+), 185 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 48fd8e3..be03cb6 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a;
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
For partitioned tables, the publication parameter
<literal>publish_via_partition_root</literal> determines which column list
is used. If <literal>publish_via_partition_root</literal> is
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89e..970df22 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -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
tables/schemas to a publication that is already subscribed to will require an
<literal>ALTER SUBSCRIPTION ... REFRESH PUBLICATION</literal> action on the
- subscribing side in order to become effective. Note also that the combination
- of <literal>DROP</literal> with a <literal>WHERE</literal> clause is not
- allowed.
+ subscribing side in order to become effective. Note also that
+ <literal>DROP ALL TABLES IN SCHEMA</literal> will not drop any schema tables
+ 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>
@@ -82,11 +84,8 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
</para>
<para>
- Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, 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.
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4b..8cc5e37 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ Specifying a column list when the publication also publishes
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ </para>
+
+ <para>
When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the
publication. So, even operations that are performed directly on a
partition are also published via publications that its ancestors are
part of.
</para>
-
- <para>
- Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
- </para>
</listitem>
</varlistentry>
@@ -136,8 +136,8 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
- Specifying a schema along with a table which belongs to the specified
- schema using <literal>FOR TABLE</literal> is not supported.
+ Specifying a schema when the publication also publishes a table with a
+ column list is not supported.
</para>
<para>
@@ -274,6 +274,12 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</para>
<para>
+ The row filter on a table becomes redundant if
+ <literal>FOR ALL TABLES IN SCHEMA</literal> is specified and the table
+ belongs to the referred schema.
+ </para>
+
+ <para>
For published partitioned tables, the row filter for each
partition is taken from the published partitioned table if the
publication parameter <literal>publish_via_partition_root</literal> is true,
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index c365de3..67781ca 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -1162,6 +1162,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];
bool nulls[NUM_PUBLICATION_TABLES_ELEM];
@@ -1175,9 +1176,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 ALL 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 89a0055..3afdee3 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);
@@ -215,44 +214,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;
@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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
* the column list on partitioned table in this case.
@@ -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);
}
@@ -1570,32 +1550,6 @@ RemovePublicationSchemaById(Oid psoid)
}
/*
- * 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
* add them to a publication.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index bc748f8..e9f0a41 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -16449,33 +16449,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 8deae57..c6b5b6f 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -835,6 +835,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
@@ -848,26 +849,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 includes a
+ * FOR ALL 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.
@@ -883,10 +884,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 ab28f75..a43ad01 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -2543,6 +2543,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 5ede56d..7563c97 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4591,10 +4591,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 e6e082d..95ea32c 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 52001e3..9ac7c49 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -3028,7 +3028,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 a56387e..923b7ea 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 f5f8a67..020a9c3 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.7.2.windows.1
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index 1ae3287..0ab768d 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a; </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para> + + <para> For partitioned tables, the publication parameter <literal>publish_via_partition_root</literal> determines which column list is used. If <literal>publish_via_partition_root</literal> isdiff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 0a68c4b..0ced7da 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para>@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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.")); +
This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.
The whole FOR ALL TABLES IN SCHEMA thing seems pretty weird in several
aspects. Others have already commented about the syntax, which is
unlike what GRANT uses; I'm also surprised that we've gotten away with
it being superuser-only. Why are we building more superuser-only
features in this day and age? I think not even FOR ALL TABLES should
require superuser.
--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
Thou shalt study thy libraries and strive not to reinvent them without
cause, that thy code may be short and readable and thy days pleasant
and productive. (7th Commandment for C Programmers)
On 9/19/22 11:16 AM, Alvaro Herrera wrote:
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index 1ae3287..0ab768d 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a; </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para> + + <para> For partitioned tables, the publication parameter <literal>publish_via_partition_root</literal> determines which column list is used. If <literal>publish_via_partition_root</literal> isdiff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 0a68c4b..0ced7da 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para>@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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.")); +This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.The whole FOR ALL TABLES IN SCHEMA thing seems pretty weird in several
aspects. Others have already commented about the syntax, which is
unlike what GRANT uses; I'm also surprised that we've gotten away with
it being superuser-only. Why are we building more superuser-only
features in this day and age? I think not even FOR ALL TABLES should
require superuser.
FYI, I've added this to the PG15 open items as there are some open
questions to resolve in this thread.
Jonathan
On Mon, Sep 19, 2022 at 8:46 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index 1ae3287..0ab768d 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -1120,6 +1120,11 @@ test_sub=# SELECT * FROM child ORDER BY a; </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para> + + <para> For partitioned tables, the publication parameter <literal>publish_via_partition_root</literal> determines which column list is used. If <literal>publish_via_partition_root</literal> isdiff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 0a68c4b..0ced7da 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -103,17 +103,17 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> </para><para> + Specifying a column list when the publication also publishes + <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported. + </para>@@ -733,6 +694,24 @@ CheckPubRelationColumnList(List *tables, const char *queryString,
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.")); +This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.
I agree that we have such checks at other places as well and one
somewhat similar is in ATPrepChangePersistence().
ATPrepChangePersistence()
{
...
...
/*
* Check that the table is not part of any publication when changing to
* UNLOGGED, as UNLOGGED tables can't be published.
*/
However, another angle to look at it is that we try to avoid adding
restrictions in other DDL commands for defined publications. I am not
sure but it appears to me Peter E. is not in favor of restrictions in
other DDLs. I think we don't have a strict rule in this regard, so we
are trying to see what makes the most sense based on feedback and do
it accordingly.
The whole FOR ALL TABLES IN SCHEMA thing seems pretty weird in several
aspects. Others have already commented about the syntax, which is
unlike what GRANT uses; I'm also surprised that we've gotten away with
it being superuser-only. Why are we building more superuser-only
features in this day and age? I think not even FOR ALL TABLES should
require superuser.
The intention was to be in sync with FOR ALL TABLES.
--
With Regards,
Amit Kapila.
On 9/19/22 4:52 PM, Jonathan S. Katz wrote:
On 9/19/22 11:16 AM, Alvaro Herrera wrote:
This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.The whole FOR ALL TABLES IN SCHEMA thing seems pretty weird in several
aspects. Others have already commented about the syntax, which is
unlike what GRANT uses; I'm also surprised that we've gotten away with
it being superuser-only. Why are we building more superuser-only
features in this day and age? I think not even FOR ALL TABLES should
require superuser.FYI, I've added this to the PG15 open items as there are some open
questions to resolve in this thread.
(Replying personally, not RMT).
I wanted to enumerate the concerns raised in this thread in the context
of the open item to understand what needs to be addressed, and also give
an opinion. I did read up on the original thread to better understand
context around decisions.
I believe the concerns are these 3 things:
1. Allowing calls that have "ALL TABLES IN SCHEMA" that include calls to
specific tables in schema
2. The syntax of the "ALL TABLES IN SCHEMA" and comparing it to similar
behaviors in PostgreSQL
3. Adding on an additional "superuser-only" feature
For #1 (allowing calls that have schema/table overlap...), there appears
to be both a patch that allows this (reversing[8]/messages/by-id/CALDaNm1BEXtvg=fq8FzM-FoYvETTEuvA_Gf8rCAjFr1VrB5aBA@mail.gmail.com), and a suggestion for
dealing with a corner-case that is reasonable, i.e. disallowing adding
schemas to a publication when specifying column-lists. Do we think we
can have consensus on this prior to the RC1 freeze?
For #2 ("ALL TABLES IN SCHEMA" syntax), this was heavily discussed on
the original thread[1]/messages/by-id/CAFiTN-u_m0cq7Rm5Bcu9EW4gSHG94WaLuxLfibwE-o7+Lea2GQ@mail.gmail.com[3]/messages/by-id/155565.1628954580@sss.pgh.pa.us[4]/messages/by-id/CAHut+PvNwzp-EdtsDNazwrNrV4ziqCovNdLywzOJKSy52LvRjw@mail.gmail.com[5]/messages/by-id/CAHut+Pt6Czj0KsE0ip6nMsPf4FatHgNDni-wSu2KkYNYF9mDAw@mail.gmail.com[7]/messages/by-id/202109241325.eag5g6mpvoup@alvherre.pgsql. I thought Tom's proposal on the
syntax[3]/messages/by-id/155565.1628954580@sss.pgh.pa.us was reasonable as it "future proofs" for when we allow other
schema-scoped objects to be published and give control over which ones
can be published.
The bigger issue seems to be around the behavior in regards to the
syntax. The current behavior is that when one specifies "ALL TABLES IN
SCHEMA", any future tables created in that schema are added to the
publication. While folks tried to find parallels to GRANT[6]/messages/by-id/CAA4eK1Lwtea0St1MV5nfSg9FrFeU04YKpHvhQ0i4W-tOBw=9Qw@mail.gmail.com, I think
this actually resembles how we handle partitions that are
published[9]/messages/by-id/CAJcOf-fyM3075t9+=B-BSFz2FG=5BnDSPX4YtL8k1nnK=wjgWA@mail.gmail.com[10]https://www.postgresql.org/docs/current/sql-createpublication.html, i.e.:
"When a partitioned table is added to a publication, all of its existing
and future partitions are implicitly considered to be part of the
publication."[10]https://www.postgresql.org/docs/current/sql-createpublication.html
Additionally, this is the behavior that is already present in "FOR ALL
TABLES":
"Marks the publication as one that replicates changes for all tables in
the database, including tables created in the future."[10]https://www.postgresql.org/docs/current/sql-createpublication.html
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."
For #3 (more superuser-only), in general I do agree that we shouldn't be
adding more of these. However, we have in this release, and not just to
this feature. ALTER SUBSCRIPTION ... SKIP[11]https://www.postgresql.org/docs/15/sql-altersubscription.html requires superuser. I
think it's easier for us to "relax" privileges (e.g. w/predefined roles)
than to make something "superuser-only" in the future, so I don't see
this being a blocker for v15. The feature will continue to work for
users even if we remove "superuser-only" in the future.
To summarize:
1. I do think we should fix the issue that Peter originally brought up
in this thread before v15. That is an open item.
2. I don't see why we need to change the syntax/behavior, I think that
will make this feature much harder to use.
3. I don't think we need to change the superuser requirement right now,
but we should do that for a future release.
Thanks,
Jonathan
[1]: /messages/by-id/CAFiTN-u_m0cq7Rm5Bcu9EW4gSHG94WaLuxLfibwE-o7+Lea2GQ@mail.gmail.com
/messages/by-id/CAFiTN-u_m0cq7Rm5Bcu9EW4gSHG94WaLuxLfibwE-o7+Lea2GQ@mail.gmail.com
[2]: /messages/by-id/C4D04B90-AC4D-42A7-B93C-4799CEDDDD96@enterprisedb.com
/messages/by-id/C4D04B90-AC4D-42A7-B93C-4799CEDDDD96@enterprisedb.com
[3]: /messages/by-id/155565.1628954580@sss.pgh.pa.us
[4]: /messages/by-id/CAHut+PvNwzp-EdtsDNazwrNrV4ziqCovNdLywzOJKSy52LvRjw@mail.gmail.com
/messages/by-id/CAHut+PvNwzp-EdtsDNazwrNrV4ziqCovNdLywzOJKSy52LvRjw@mail.gmail.com
[5]: /messages/by-id/CAHut+Pt6Czj0KsE0ip6nMsPf4FatHgNDni-wSu2KkYNYF9mDAw@mail.gmail.com
/messages/by-id/CAHut+Pt6Czj0KsE0ip6nMsPf4FatHgNDni-wSu2KkYNYF9mDAw@mail.gmail.com
[6]: /messages/by-id/CAA4eK1Lwtea0St1MV5nfSg9FrFeU04YKpHvhQ0i4W-tOBw=9Qw@mail.gmail.com
/messages/by-id/CAA4eK1Lwtea0St1MV5nfSg9FrFeU04YKpHvhQ0i4W-tOBw=9Qw@mail.gmail.com
[7]: /messages/by-id/202109241325.eag5g6mpvoup@alvherre.pgsql
/messages/by-id/202109241325.eag5g6mpvoup@alvherre.pgsql
[8]: /messages/by-id/CALDaNm1BEXtvg=fq8FzM-FoYvETTEuvA_Gf8rCAjFr1VrB5aBA@mail.gmail.com
/messages/by-id/CALDaNm1BEXtvg=fq8FzM-FoYvETTEuvA_Gf8rCAjFr1VrB5aBA@mail.gmail.com
[9]: /messages/by-id/CAJcOf-fyM3075t9+=B-BSFz2FG=5BnDSPX4YtL8k1nnK=wjgWA@mail.gmail.com
/messages/by-id/CAJcOf-fyM3075t9+=B-BSFz2FG=5BnDSPX4YtL8k1nnK=wjgWA@mail.gmail.com
[10]: https://www.postgresql.org/docs/current/sql-createpublication.html
[11]: https://www.postgresql.org/docs/15/sql-altersubscription.html
On 2022-Sep-20, Amit Kapila wrote:
On Mon, Sep 19, 2022 at 8:46 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.I agree that we have such checks at other places as well and one
somewhat similar is in ATPrepChangePersistence().ATPrepChangePersistence()
{
...
...
/*
* Check that the table is not part of any publication when changing to
* UNLOGGED, as UNLOGGED tables can't be published.
*/
Right, I think this is a sensible approach.
However, another angle to look at it is that we try to avoid adding
restrictions in other DDL commands for defined publications.
Well, it makes sense to avoid restrictions wherever possible. But here,
the consequence is that you end up with a restriction in the publication
definition that is not very sensible. Imagine if you said "you can't
add schema S because it contains an unlogged table". It's absurd.
Maybe this can be relaxed in a future release, but it's quite odd.
The intention was to be in sync with FOR ALL TABLES.
I guess we can change both (FOR ALL TABLES and IN SCHEMA) later.
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
On Tue, Sep 20, 2022 at 2:57 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
On 2022-Sep-20, Amit Kapila wrote:
On Mon, Sep 19, 2022 at 8:46 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
This seems a pretty arbitrary restriction. It feels like you're adding
this restriction precisely so that you don't have to write the code to
reject the ALTER .. SET SCHEMA if an incompatible configuration is
detected. But we already have such checks in several cases, so I don't
see why this one does not seem a good idea.I agree that we have such checks at other places as well and one
somewhat similar is in ATPrepChangePersistence().ATPrepChangePersistence()
{
...
...
/*
* Check that the table is not part of any publication when changing to
* UNLOGGED, as UNLOGGED tables can't be published.
*/Right, I think this is a sensible approach.
However, another angle to look at it is that we try to avoid adding
restrictions in other DDL commands for defined publications.Well, it makes sense to avoid restrictions wherever possible. But here,
the consequence is that you end up with a restriction in the publication
definition that is not very sensible. Imagine if you said "you can't
add schema S because it contains an unlogged table". It's absurd.Maybe this can be relaxed in a future release, but it's quite odd.
Yeah, we can relax it in a future release based on some field
experience, or maybe we can keep the current restriction of not
allowing to add a table when the schema of the table is part of the
same publication and try to relax that in a future release based on
field experience.
The intention was to be in sync with FOR ALL TABLES.
I guess we can change both (FOR ALL TABLES and IN SCHEMA) later.
That sounds reasonable.
--
With Regards,
Amit Kapila.
On Mon, Sep 19, 2022 at 11:03 PM Jonathan S. Katz <jkatz@postgresql.org> wrote:
For #1 (allowing calls that have schema/table overlap...), there appears
to be both a patch that allows this (reversing[8]), and a suggestion for
dealing with a corner-case that is reasonable, i.e. disallowing adding
schemas to a publication when specifying column-lists. Do we think we
can have consensus on this prior to the RC1 freeze?
I am not sure whether we can or should rush a fix in that fast, but I
agree with this direction.
For #2 ("ALL TABLES IN SCHEMA" syntax), this was heavily discussed on
the original thread[1][3][4][5][7]. I thought Tom's proposal on the
syntax[3] was reasonable as it "future proofs" for when we allow other
schema-scoped objects to be published and give control over which ones
can be published.
All right, well, I still don't like it and think it's confusing, but
perhaps I'm in the minority.
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."
Nah, there's room for multiple behaviors here. It's reasonable to want
to add all the tables currently in the schema to a publication (or
grant permissions on them) and it's reasonable to want to include all
current and future tables in the schema in a publication (or grant
permissions on them) too. The reason I don't like the ALL TABLES IN
SCHEMA syntax is that it sounds like the former, but actually is the
latter. Based on your link to the email from Tom, I understand now the
reason why it's like that, but it's still counterintuitive to me.
For #3 (more superuser-only), in general I do agree that we shouldn't be
adding more of these. However, we have in this release, and not just to
this feature. ALTER SUBSCRIPTION ... SKIP[11] requires superuser. I
think it's easier for us to "relax" privileges (e.g. w/predefined roles)
than to make something "superuser-only" in the future, so I don't see
this being a blocker for v15. The feature will continue to work for
users even if we remove "superuser-only" in the future.
Yeah, this is clearly not a release blocker, I think.
--
Robert Haas
EDB: http://www.enterprisedb.com
On 2022-Sep-13, Kyotaro Horiguchi wrote:
At Mon, 12 Sep 2022 04:26:48 +0000, "houzj.fnst@fujitsu.com" <houzj.fnst@fujitsu.com> wrote in
I feel we'd better compare the syntax with the existing publication command:
FOR ALL TABLES. If you create a publication FOR ALL TABLES, it means publishing
all the tables in the database *including* tables created in the future. I
think both the syntax and meaning of ALL TABLES IN SCHEMA are consistent with
the existing FOR ALL TABLES.IMHO, I feel closer to Robert. "ALL TABLES IN SCHEMA" sounds like the
concrete tables at the time of invocation. While I agree that it is
not directly comparable to GRANT,
What if we remove the ALL keyword from there? That would leave us with
"FOR TABLES IN SCHEMA", which seems to better convey that it doesn't
restrict to current tables in there.
but if I see "ALTER PUBLICATION p1 ADD SCHEMA s1", I automatically
translate that into "all tables in the schema s1 at the time of using
this publication".
... but that translation is wrong if replication supports other kinds of
objects, as it inevitably will in the near future. Clearly the fact
that we spell out TABLES there is important. When we add support for
sequences, we could have combinations
ADD [ALL] TABLES IN SCHEMA s
ADD [ALL] SEQUENCES IN SCHEMA s
ADD [ALL] TABLES AND SEQUENCES IN SCHEMA s
and at that point, the unadorned ADD SCHEMA one will become ambiguous.
At least, it would cause less confusion when it were "ALT PUB p1 DROP
SCEMA s1" aginst "DROP ALL TABLES IN SCHEMA s1".
I'm not sure what you mean here.
--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
"En las profundidades de nuestro inconsciente hay una obsesiva necesidad
de un universo lógico y coherente. Pero el universo real se halla siempre
un paso más allá de la lógica" (Irulan)
On Sep 19, 2022, at 8:03 PM, Jonathan S. Katz <jkatz@postgresql.org> wrote:
"When a partitioned table is added to a publication, all of its existing and future partitions are implicitly considered to be part of the publication."[10]
Additionally, this is the behavior that is already present in "FOR ALL TABLES":
"Marks the publication as one that replicates changes for all tables in the database, including tables created in the future."[10]
I don't think we should change this behavior that's already in logical replication.
The existing behavior in logical replication doesn't have any "IN SCHEMA" qualifiers.
While I understand the reasons why "GRANT ... ALL TABLES IN SCHEMA" has a different behavior (i.e. it's not applied to future objects) and do not advocate to change it, I have personally been affected where I thought a permission would be applied to all future objects, only to discover otherwise. I believe it's more intuitive to think that "ALL" applies to "everything, always."
The conversation is focusing on what "ALL TABLES" means, but the ambiguous part is what "IN SCHEMA" means. In GRANT it means "currently in schema, computed now." We are about to create confusion by adding the "IN SCHEMA" phrase to publication commands meaning "later in schema, computed then." A user who diligently consults the documentation for one command to discover what "IN SCHEMA" means may fairly, but wrongly, assume it means the same thing in another command.
—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On 9/20/22 10:55 AM, Mark Dilger wrote:
On Sep 19, 2022, at 8:03 PM, Jonathan S. Katz <jkatz@postgresql.org> wrote:
"When a partitioned table is added to a publication, all of its existing and future partitions are implicitly considered to be part of the publication."[10]
Additionally, this is the behavior that is already present in "FOR ALL TABLES":
"Marks the publication as one that replicates changes for all tables in the database, including tables created in the future."[10]
I don't think we should change this behavior that's already in logical replication.
The existing behavior in logical replication doesn't have any "IN SCHEMA" qualifiers.
This behavior exists "FOR ALL TABLES" without the "IN SCHEMA" qualifier.
This was discussed multiple times on the original thread[1]/messages/by-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com.
While I understand the reasons why "GRANT ... ALL TABLES IN SCHEMA" has a different behavior (i.e. it's not applied to future objects) and do not advocate to change it, I have personally been affected where I thought a permission would be applied to all future objects, only to discover otherwise. I believe it's more intuitive to think that "ALL" applies to "everything, always."
The conversation is focusing on what "ALL TABLES" means, but the ambiguous part is what "IN SCHEMA" means. In GRANT it means "currently in schema, computed now." We are about to create confusion by adding the "IN SCHEMA" phrase to publication commands meaning "later in schema, computed then." A user who diligently consults the documentation for one command to discover what "IN SCHEMA" means may fairly, but wrongly, assume it means the same thing in another command.
I tried to diligently read the sections where we talk about granting +
privileges[2]https://www.postgresql.org/docs/current/sql-grant.html[3]https://www.postgresql.org/docs/current/ddl-priv.html to see what it says about "ALL * IN SCHEMA". Unless I
missed it, and I read through it twice, it does not explicitly state
whether or not "GRANT" applies to all objects at only that given moment,
or to future objects of that type which are created in that schema.
Maybe the behavior is implied or is part of the standard, but it's not
currently documented. We do link to "ALTER DEFAULT PRIVILEGES" at the
bottom of the GRANT[2]https://www.postgresql.org/docs/current/sql-grant.html docs, but we don't give any indication as to why.
(This is also to say we should document in GRANT that ALL * IN SCHEMA
does not apply to future objects; if you need that behavior use ALTER
DEFAULT PRIVILEGES. Separate thread :)
I understand there is a risk of confusion of the similar grammar across
commands, but the current command in logical replication has this is
building on the existing behavior.
Thanks,
Jonathan
[1]: /messages/by-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
/messages/by-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
[2]: https://www.postgresql.org/docs/current/sql-grant.html
[3]: https://www.postgresql.org/docs/current/ddl-priv.html
(RMT hat on, unless otherwise noted)
On 9/20/22 9:42 AM, Robert Haas wrote:
On Mon, Sep 19, 2022 at 11:03 PM Jonathan S. Katz <jkatz@postgresql.org> wrote:
For #1 (allowing calls that have schema/table overlap...), there appears
to be both a patch that allows this (reversing[8]), and a suggestion for
dealing with a corner-case that is reasonable, i.e. disallowing adding
schemas to a publication when specifying column-lists. Do we think we
can have consensus on this prior to the RC1 freeze?I am not sure whether we can or should rush a fix in that fast, but I
agree with this direction.
The RMT met today to discuss this.
We did agree that the above is an open item that should be resolved
before this release. While it is an accepted pattern for us to "ERROR"
on unsupported behavior and then later introduce said behavior, we do
agree with Peter's original post in this thread and would like it resolved.
As for the state of the fix, the patch has been iterated on and Amit
felt ready to commit it[1]/messages/by-id/CAA4eK1LDhoBM8K5uVme8PZ+kxNOfVpRh=oO42JtFdqBgBuj1bA@mail.gmail.com. We do want to hear how others feel about
this, but the folks behind this feature have been working on this patch
since this was reported.
For #2 ("ALL TABLES IN SCHEMA" syntax), this was heavily discussed on
the original thread[1][3][4][5][7]. I thought Tom's proposal on the
syntax[3] was reasonable as it "future proofs" for when we allow other
schema-scoped objects to be published and give control over which ones
can be published.All right, well, I still don't like it and think it's confusing, but
perhaps I'm in the minority.
The RMT discussed this as well. The RMT feels that there should not be
any changes to syntax/behavior for this release. This doesn't preclude
future work in this area (e.g. having a toggle for "all future
behavior"), but based on all the discussions and existing behavior in
this feature, we do not see a need to make changes or delay the release
on this.
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."Nah, there's room for multiple behaviors here. It's reasonable to want
to add all the tables currently in the schema to a publication (or
grant permissions on them) and it's reasonable to want to include all
current and future tables in the schema in a publication (or grant
permissions on them) too. The reason I don't like the ALL TABLES IN
SCHEMA syntax is that it sounds like the former, but actually is the
latter. Based on your link to the email from Tom, I understand now the
reason why it's like that, but it's still counterintuitive to me.
<PersonalOpinion>
I understand your view on "multiple behaviors" and I do agree with your
reasoning. I still think we should leave this as is, but perhaps this
opens up an option we add later to specify the behavior.
</PersonalOpinion>
For #3 (more superuser-only), in general I do agree that we shouldn't be
adding more of these. However, we have in this release, and not just to
this feature. ALTER SUBSCRIPTION ... SKIP[11] requires superuser. I
think it's easier for us to "relax" privileges (e.g. w/predefined roles)
than to make something "superuser-only" in the future, so I don't see
this being a blocker for v15. The feature will continue to work for
users even if we remove "superuser-only" in the future.Yeah, this is clearly not a release blocker, I think.
The RMT concurs. We do recommend future work on "relaxing" the
superuser-only requirement.
Thanks,
Jonathan
[1]: /messages/by-id/CAA4eK1LDhoBM8K5uVme8PZ+kxNOfVpRh=oO42JtFdqBgBuj1bA@mail.gmail.com
/messages/by-id/CAA4eK1LDhoBM8K5uVme8PZ+kxNOfVpRh=oO42JtFdqBgBuj1bA@mail.gmail.com
On Sep 20, 2022, at 12:36 PM, Jonathan S. Katz <jkatz@postgresql.org> wrote:
This behavior exists "FOR ALL TABLES" without the "IN SCHEMA" qualifier. This was discussed multiple times on the original thread[1].
Yes, nobody is debating that as far as I can see. And I do take your point that this stuff was discussed in other threads quite a while back.
I tried to diligently read the sections where we talk about granting + privileges[2][3] to see what it says about "ALL * IN SCHEMA". Unless I missed it, and I read through it twice, it does not explicitly state whether or not "GRANT" applies to all objects at only that given moment, or to future objects of that type which are created in that schema. Maybe the behavior is implied or is part of the standard, but it's not currently documented.
Interesting. Thanks for that bit of research.
We do link to "ALTER DEFAULT PRIVILEGES" at the bottom of the GRANT[2] docs, but we don't give any indication as to why.
(This is also to say we should document in GRANT that ALL * IN SCHEMA does not apply to future objects;
Yes, I agree this should be documented.
if you need that behavior use ALTER DEFAULT PRIVILEGES. Separate thread :)
I understand there is a risk of confusion of the similar grammar across commands, but the current command in logical replication has this is building on the existing behavior.
I don't complain that it is buidling on the existing behavior. I'm *only* concerned about the keywords we're using for this. Consider the following:
-- AS ADMIN
CREATE USER bob NOSUPERUSER;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO bob;
SET ROLE bob;
CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;
We're going to have that fail in pg15 because the FOR ALL TABLES IN SCHEMA option is reserved to superusers. But we agreed that was a stop-gap solution that we'd potentially loosen in the future. Certainly we'll need wiggle room in the syntax to perform that loosening:
--- Must be superuser for this in pg15, and in subsequent releases.
CREATE PUBLICATION bobs_pub FOR ALL FUTURE TABLES IN SCHEMA foo;
--- Not supported in pg15, but reserved for some future pg versions to allow
--- non-superusers to create publications on tables currently in schema foo,
--- assuming they have sufficient privileges on those tables
CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;
Doing it this way makes the syntax consistent between the GRANT...TO bob and the CREATE PUBLICATION bobs_pub. Surely this makes more sense?
I'm not a huge fan of the keyword "FUTURE" here, but I found a reference to another database that uses that keyword for what I think is a similar purpose. We should choose *something* for this, though, if we want things to be rational going forward.
—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
[personal views, not RMT]
On 9/20/22 4:06 PM, Mark Dilger wrote:
I don't complain that it is buidling on the existing behavior. I'm *only* concerned about the keywords we're using for this. Consider the following:
-- AS ADMIN
CREATE USER bob NOSUPERUSER;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO bob;
SET ROLE bob;
CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;We're going to have that fail in pg15 because the FOR ALL TABLES IN SCHEMA option is reserved to superusers. But we agreed that was a stop-gap solution that we'd potentially loosen in the future. Certainly we'll need wiggle room in the syntax to perform that loosening:
--- Must be superuser for this in pg15, and in subsequent releases. CREATE PUBLICATION bobs_pub FOR ALL FUTURE TABLES IN SCHEMA foo;--- Not supported in pg15, but reserved for some future pg versions to allow --- non-superusers to create publications on tables currently in schema foo, --- assuming they have sufficient privileges on those tables CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;Doing it this way makes the syntax consistent between the GRANT...TO bob and the CREATE PUBLICATION bobs_pub. Surely this makes more sense?
When you put it that way, I see your point. However, for the
lesser-privileged user though, will the behavior be that it will
continue to add all future tables in a schema to the publication so long
as they have sufficient privileges on those tables? Or would that mirror
the current behavior with GRANT?
While I understand it makes it consistent, the one concern I raise is
that it means the less privileged user could have a less convenient user
experience than the privileged user. Perhaps that's OK, but worth noting.
I'm not a huge fan of the keyword "FUTURE" here, but I found a reference to another database that uses that keyword for what I think is a similar purpose.
I did try doing research on this prior, but hadn't thought to
incorporate "future" into my searches.
Doing so, I probably found the same database that you did that used the
"FUTURE" word for adding permissions to future objects (and this is
fresh, as the docs for it were published last week). That's definitely
interesting.
I did see some notes on a legacy database system that offered similar
advice to what we do for GRANT if you're not using ALTER DEFAULT PRIVILEGES.
We should choose *something* for this, though, if we want things to be rational going forward.
That all said, while I understand your point and open to the suggestion
on "FUTURE", I'm not convinced on the syntax change. But I'll sleep on it.
Jonathan
On Wednesday, September 21, 2022 4:06 AM Mark Dilger <mark.dilger@enterprisedb.com> wrote:
On Sep 20, 2022, at 12:36 PM, Jonathan S. Katz <jkatz@postgresql.org>
wrote:
This behavior exists "FOR ALL TABLES" without the "IN SCHEMA" qualifier.
This was discussed multiple times on the original thread[1].
Yes, nobody is debating that as far as I can see. And I do take your point that
this stuff was discussed in other threads quite a while back.I tried to diligently read the sections where we talk about granting +
privileges[2][3] to see what it says about "ALL * IN SCHEMA". Unless I missed it,
and I read through it twice, it does not explicitly state whether or not "GRANT"
applies to all objects at only that given moment, or to future objects of that
type which are created in that schema. Maybe the behavior is implied or is part
of the standard, but it's not currently documented.Interesting. Thanks for that bit of research.
We do link to "ALTER DEFAULT PRIVILEGES" at the bottom of the GRANT[2]
docs, but we don't give any indication as to why.
(This is also to say we should document in GRANT that ALL * IN SCHEMA does
not apply to future objects;
Yes, I agree this should be documented.
if you need that behavior use ALTER DEFAULT PRIVILEGES. Separate thread :)
I understand there is a risk of confusion of the similar grammar across
commands, but the current command in logical replication has this is building
on the existing behavior.I don't complain that it is buidling on the existing behavior. I'm *only*
concerned about the keywords we're using for this. Consider the following:-- AS ADMIN
CREATE USER bob NOSUPERUSER;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO bob;
SET ROLE bob;
CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;We're going to have that fail in pg15 because the FOR ALL TABLES IN SCHEMA
option is reserved to superusers. But we agreed that was a stop-gap solution
that we'd potentially loosen in the future. Certainly we'll need wiggle room in
the syntax to perform that loosening:--- Must be superuser for this in pg15, and in subsequent releases. CREATE PUBLICATION bobs_pub FOR ALL FUTURE TABLES IN SCHEMA foo;--- Not supported in pg15, but reserved for some future pg versions to allow --- non-superusers to create publications on tables currently in schema foo, --- assuming they have sufficient privileges on those tables CREATE PUBLICATION bobs_pub FOR ALL TABLES IN SCHEMA foo;Doing it this way makes the syntax consistent between the GRANT...TO bob and
the CREATE PUBLICATION bobs_pub. Surely this makes more sense?
Thanks for the suggestion.
My concern is that I am not sure do we really want to add a feature that only
publish all the current tables(not future tables).
I think, if possible, it would be better to find an approach that can release the
superuser restriction for both FOR ALL TABLES and FOR ALL TABLES IN SCHEMA in
the future release. I think another solution might be introduce a new
publication option (like: include_future).
When user execute:
CREATE PUBLICATION ... FOR ALL TABLES IN SCHEMA ... WITH (include_future)
it means we publish all current and future tables and require superuser. We can
set the default value of this option to 'true' and user can set it to false if
they only want to publish the current tables and don't want to use superuser.
And in this approach, we don't need to change the syntax.
Best regards,
Hou zj
On 2022-Sep-20, Robert Haas wrote:
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."Nah, there's room for multiple behaviors here. It's reasonable to want
to add all the tables currently in the schema to a publication (or
grant permissions on them) and it's reasonable to want to include all
current and future tables in the schema in a publication (or grant
permissions on them) too. The reason I don't like the ALL TABLES IN
SCHEMA syntax is that it sounds like the former, but actually is the
latter. Based on your link to the email from Tom, I understand now the
reason why it's like that, but it's still counterintuitive to me.
I already proposed elsewhere that we remove the ALL keyword from there,
which I think serves to reduce confusion (in particular it's no longer
parallel to the GRANT one). As in the attached.
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"No renuncies a nada. No te aferres a nada."
Attachments:
0001-remove-ALL-from-ALL-TABLES-IN-SCHEMA.patchtext/x-diff; charset=us-asciiDownload
From a72ceafe65c02998761cf21bec2820bf49b00a8f Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 21 Sep 2022 16:18:16 +0200
Subject: [PATCH] remove ALL from ALL TABLES IN SCHEMA
---
doc/src/sgml/logical-replication.sgml | 4 +-
doc/src/sgml/ref/alter_publication.sgml | 16 +--
doc/src/sgml/ref/create_publication.sgml | 14 +-
doc/src/sgml/ref/create_subscription.sgml | 2 +-
doc/src/sgml/system-views.sgml | 2 +-
src/backend/catalog/pg_publication.c | 4 +-
src/backend/commands/publicationcmds.c | 6 +-
src/backend/parser/gram.y | 18 +--
src/backend/replication/pgoutput/pgoutput.c | 3 +-
src/bin/pg_dump/pg_dump.c | 2 +-
src/bin/pg_dump/t/002_pg_dump.pl | 12 +-
src/bin/psql/tab-complete.c | 14 +-
src/test/regress/expected/alter_table.out | 2 +-
src/test/regress/expected/object_address.out | 2 +-
src/test/regress/expected/publication.out | 120 +++++++++---------
src/test/regress/sql/alter_table.sql | 2 +-
src/test/regress/sql/object_address.sql | 2 +-
src/test/regress/sql/publication.sql | 104 +++++++--------
.../t/025_rep_changes_for_schema.pl | 6 +-
src/test/subscription/t/028_row_filter.pl | 12 +-
src/test/subscription/t/031_column_list.pl | 4 +-
21 files changed, 175 insertions(+), 176 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 48fd8e33dc..7fe3a1043e 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -700,7 +700,7 @@ test_sub=# SELECT * FROM t3;
<listitem>
<para>
one of the publications was created using
- <literal>FOR ALL TABLES IN SCHEMA</literal> and the table belongs to
+ <literal>FOR TABLES IN SCHEMA</literal> and the table belongs to
the referred schema. This clause does not allow row filters.
</para>
</listitem>
@@ -1530,7 +1530,7 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER
Moreover, if untrusted users can create tables, use only
publications that list tables explicitly. That is to say, create a
subscription <literal>FOR ALL TABLES</literal> or
- <literal>FOR ALL TABLES IN SCHEMA</literal> only when superusers trust
+ <literal>FOR TABLES IN SCHEMA</literal> only when superusers trust
every user permitted to create a non-temp table on the publisher or the
subscriber.
</para>
diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml
index d8ed89ee91..fc2d6d4885 100644
--- a/doc/src/sgml/ref/alter_publication.sgml
+++ b/doc/src/sgml/ref/alter_publication.sgml
@@ -31,7 +31,7 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
<phrase>where <replaceable class="parameter">publication_object</replaceable> is one of:</phrase>
TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ] [ ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) ] [ WHERE ( <replaceable class="parameter">expression</replaceable> ) ] [, ... ]
- ALL TABLES IN SCHEMA { <replaceable class="parameter">schema_name</replaceable> | CURRENT_SCHEMA } [, ... ]
+ TABLES IN SCHEMA { <replaceable class="parameter">schema_name</replaceable> | CURRENT_SCHEMA } [, ... ]
</synopsis>
</refsynopsisdiv>
@@ -71,19 +71,19 @@ ALTER PUBLICATION <replaceable class="parameter">name</replaceable> RENAME TO <r
<para>
You must own the publication to use <command>ALTER PUBLICATION</command>.
Adding a table to a publication additionally requires owning that table.
- The <literal>ADD ALL TABLES IN SCHEMA</literal> and
- <literal>SET ALL TABLES IN SCHEMA</literal> to a publication requires the
+ The <literal>ADD TABLES IN SCHEMA</literal> and
+ <literal>SET TABLES IN SCHEMA</literal> to a publication requires the
invoking user to be a superuser. To alter the owner, you must also be a
direct or indirect member of the new owning role. The new owner must have
<literal>CREATE</literal> privilege on the database. Also, the new owner
- of a <literal>FOR ALL TABLES</literal> or <literal>FOR ALL TABLES IN
- SCHEMA</literal> publication must be a superuser. However, a superuser can
+ of a <literal>FOR ALL TABLES</literal> or <literal>FOR TABLES IN SCHEMA</literal>
+ publication must be a superuser. However, a superuser can
change the ownership of a publication regardless of these restrictions.
</para>
<para>
Adding/Setting a table that is part of schema specified in
- <literal>ALL TABLES IN SCHEMA</literal>, adding/setting a schema to a
+ <literal>TABLES IN SCHEMA</literal>, 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.
@@ -200,7 +200,7 @@ ALTER PUBLICATION mypublication SET TABLE users (user_id, firstname, lastname),
<structname>sales</structname> to the publication
<structname>sales_publication</structname>:
<programlisting>
-ALTER PUBLICATION sales_publication ADD ALL TABLES IN SCHEMA marketing, sales;
+ALTER PUBLICATION sales_publication ADD TABLES IN SCHEMA marketing, sales;
</programlisting>
</para>
@@ -210,7 +210,7 @@ ALTER PUBLICATION sales_publication ADD ALL TABLES IN SCHEMA marketing, sales;
<structname>production</structname> to the publication
<structname>production_publication</structname>:
<programlisting>
-ALTER PUBLICATION production_publication ADD TABLE users, departments, ALL TABLES IN SCHEMA production;
+ALTER PUBLICATION production_publication ADD TABLE users, departments, TABLES IN SCHEMA production;
</programlisting></para>
</refsect1>
diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 0a68c4bf73..2e097a81e5 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -29,7 +29,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
<phrase>where <replaceable class="parameter">publication_object</replaceable> is one of:</phrase>
TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ] [ ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) ] [ WHERE ( <replaceable class="parameter">expression</replaceable> ) ] [, ... ]
- ALL TABLES IN SCHEMA { <replaceable class="parameter">schema_name</replaceable> | CURRENT_SCHEMA } [, ... ]
+ TABLES IN SCHEMA { <replaceable class="parameter">schema_name</replaceable> | CURRENT_SCHEMA } [, ... ]
</synopsis>
</refsynopsisdiv>
@@ -112,7 +112,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
<para>
Specifying a table that is part of a schema specified by
- <literal>FOR ALL TABLES IN SCHEMA</literal> is not supported.
+ <literal>FOR TABLES IN SCHEMA</literal> is not supported.
</para>
</listitem>
</varlistentry>
@@ -128,7 +128,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
</varlistentry>
<varlistentry>
- <term><literal>FOR ALL TABLES IN SCHEMA</literal></term>
+ <term><literal>FOR TABLES IN SCHEMA</literal></term>
<listitem>
<para>
Marks the publication as one that replicates changes for all tables in
@@ -224,7 +224,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
<para>
If <literal>FOR TABLE</literal>, <literal>FOR ALL TABLES</literal> or
- <literal>FOR ALL TABLES IN SCHEMA</literal> are not specified, then the
+ <literal>FOR TABLES IN SCHEMA</literal> are not specified, then the
publication starts out with an empty set of tables. That is useful if
tables or schemas are to be added later.
</para>
@@ -243,7 +243,7 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
<para>
To add a table to a publication, the invoking user must have ownership
rights on the table. The <command>FOR ALL TABLES</command> and
- <command>FOR ALL TABLES IN SCHEMA</command> clauses require the invoking
+ <command>FOR TABLES IN SCHEMA</command> clauses require the invoking
user to be a superuser.
</para>
@@ -354,7 +354,7 @@ CREATE PUBLICATION insert_only FOR TABLE mydata
all changes for all the tables present in the schema
<structname>production</structname>:
<programlisting>
-CREATE PUBLICATION production_publication FOR TABLE users, departments, ALL TABLES IN SCHEMA production;
+CREATE PUBLICATION production_publication FOR TABLE users, departments, TABLES IN SCHEMA production;
</programlisting>
</para>
@@ -363,7 +363,7 @@ CREATE PUBLICATION production_publication FOR TABLE users, departments, ALL TABL
the schemas <structname>marketing</structname> and
<structname>sales</structname>:
<programlisting>
-CREATE PUBLICATION sales_publication FOR ALL TABLES IN SCHEMA marketing, sales;
+CREATE PUBLICATION sales_publication FOR TABLES IN SCHEMA marketing, sales;
</programlisting></para>
<para>
diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml
index 4e001f8111..bd12e71e33 100644
--- a/doc/src/sgml/ref/create_subscription.sgml
+++ b/doc/src/sgml/ref/create_subscription.sgml
@@ -372,7 +372,7 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl
publications has no <literal>WHERE</literal> clause (referring to that
publish operation) or the publication is declared as
<literal>FOR ALL TABLES</literal> or
- <literal>FOR ALL TABLES IN SCHEMA</literal>, rows are always published
+ <literal>FOR TABLES IN SCHEMA</literal>, rows are always published
regardless of the definition of the other expressions.
If the subscriber is a <productname>PostgreSQL</productname> version before
15 then any row filtering is ignored during the initial data synchronization
diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml
index 3f573a4f08..1ca7c3f9bf 100644
--- a/doc/src/sgml/system-views.sgml
+++ b/doc/src/sgml/system-views.sgml
@@ -2090,7 +2090,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
tables they contain. Unlike the underlying catalog
<link linkend="catalog-pg-publication-rel"><structname>pg_publication_rel</structname></link>,
this view expands publications defined as <literal>FOR ALL TABLES</literal>
- and <literal>FOR ALL TABLES IN SCHEMA</literal>, so for such publications
+ and <literal>FOR TABLES IN SCHEMA</literal>, so for such publications
there will be a row for each eligible table.
</para>
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 6af3570005..e27db27f04 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -837,7 +837,7 @@ GetAllTablesPublicationRelations(bool pubviaroot)
/*
* Gets the list of schema oids for a publication.
*
- * This should only be used FOR ALL TABLES IN SCHEMA publications.
+ * This should only be used FOR TABLES IN SCHEMA publications.
*/
List *
GetPublicationSchemas(Oid pubid)
@@ -957,7 +957,7 @@ GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
}
/*
- * Gets the list of all relations published by FOR ALL TABLES IN SCHEMA
+ * Gets the list of all relations published by FOR TABLES IN SCHEMA
* publication.
*/
List *
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 8b574b86c4..15ab5aa99e 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -847,11 +847,11 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
&schemaidlist);
- /* FOR ALL TABLES IN SCHEMA requires superuser */
+ /* FOR TABLES IN SCHEMA requires superuser */
if (schemaidlist != NIL && !superuser())
ereport(ERROR,
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to create FOR ALL TABLES IN SCHEMA publication"));
+ errmsg("must be superuser to create FOR TABLES IN SCHEMA publication"));
if (relations != NIL)
{
@@ -1979,7 +1979,7 @@ AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to change owner of publication \"%s\"",
NameStr(form->pubname)),
- errhint("The owner of a FOR ALL TABLES IN SCHEMA publication must be a superuser.")));
+ errhint("The owner of a FOR TABLES IN SCHEMA publication must be a superuser.")));
}
form->pubowner = newOwnerId;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d76c0af394..0d8d292850 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10340,7 +10340,7 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec
* pub_obj is one of:
*
* TABLE table [, ...]
- * ALL TABLES IN SCHEMA schema [, ...]
+ * TABLES IN SCHEMA schema [, ...]
*
*****************************************************************************/
@@ -10375,7 +10375,7 @@ CreatePublicationStmt:
;
/*
- * FOR TABLE and FOR ALL TABLES IN SCHEMA specifications
+ * FOR TABLE and FOR TABLES IN SCHEMA specifications
*
* This rule parses publication objects with and without keyword prefixes.
*
@@ -10397,18 +10397,18 @@ PublicationObjSpec:
$$->pubtable->columns = $3;
$$->pubtable->whereClause = $4;
}
- | ALL TABLES IN_P SCHEMA ColId
+ | TABLES IN_P SCHEMA ColId
{
$$ = makeNode(PublicationObjSpec);
$$->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA;
- $$->name = $5;
- $$->location = @5;
+ $$->name = $4;
+ $$->location = @4;
}
- | ALL TABLES IN_P SCHEMA CURRENT_SCHEMA
+ | TABLES IN_P SCHEMA CURRENT_SCHEMA
{
$$ = makeNode(PublicationObjSpec);
$$->pubobjtype = PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA;
- $$->location = @5;
+ $$->location = @4;
}
| ColId opt_column_list OptWhereClause
{
@@ -10484,7 +10484,7 @@ pub_obj_list: PublicationObjSpec
* pub_obj is one of:
*
* TABLE table_name [, ...]
- * ALL TABLES IN SCHEMA schema_name [, ...]
+ * TABLES IN SCHEMA schema_name [, ...]
*
*****************************************************************************/
@@ -18424,7 +18424,7 @@ preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid publication object list"),
- errdetail("One of TABLE or ALL TABLES IN SCHEMA must be specified before a standalone table or schema name."),
+ errdetail("One of TABLE or TABLES IN SCHEMA must be specified before a standalone table or schema name."),
parser_errposition(pubobj->location));
foreach(cell, pubobjspec_list)
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 880580ed00..92bbffbe7c 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1014,8 +1014,7 @@ pgoutput_column_list_init(PGOutputData *data, List *publications,
* need to check all the given publication-table mappings and report an
* error if any publications have a different column list.
*
- * FOR ALL TABLES and FOR ALL TABLES IN SCHEMA implies "don't use column
- * list".
+ * FOR ALL TABLES and FOR TABLES IN SCHEMA imply "don't use column list".
*/
foreach(lc, publications)
{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 67b6d9079e..65a5c5ec4c 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4317,7 +4317,7 @@ dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
query = createPQExpBuffer();
appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
- appendPQExpBuffer(query, "ADD ALL TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
+ appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
/*
* There is no point in creating drop query as the drop is done by schema
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 2873b662fb..31410c2a55 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -2544,23 +2544,23 @@ my %tests = (
unlike => { exclude_dump_test_schema => 1, },
},
- 'ALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA dump_test' => {
+ 'ALTER PUBLICATION pub3 ADD TABLES IN SCHEMA dump_test' => {
create_order => 51,
create_sql =>
- 'ALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA dump_test;',
+ 'ALTER PUBLICATION pub3 ADD TABLES IN SCHEMA dump_test;',
regexp => qr/^
- \QALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA dump_test;\E
+ \QALTER PUBLICATION pub3 ADD TABLES IN SCHEMA dump_test;\E
/xm,
like => { %full_runs, section_post_data => 1, },
unlike => { exclude_dump_test_schema => 1, },
},
- 'ALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA public' => {
+ 'ALTER PUBLICATION pub3 ADD TABLES IN SCHEMA public' => {
create_order => 52,
create_sql =>
- 'ALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA public;',
+ 'ALTER PUBLICATION pub3 ADD TABLES IN SCHEMA public;',
regexp => qr/^
- \QALTER PUBLICATION pub3 ADD ALL TABLES IN SCHEMA public;\E
+ \QALTER PUBLICATION pub3 ADD TABLES IN SCHEMA public;\E
/xm,
like => { %full_runs, section_post_data => 1, },
},
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f3465adb85..cb75238d27 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1820,7 +1820,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ADD", "DROP", "OWNER TO", "RENAME TO", "SET");
/* ALTER PUBLICATION <name> ADD */
else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD"))
- COMPLETE_WITH("ALL TABLES IN SCHEMA", "TABLE");
+ COMPLETE_WITH("TABLES IN SCHEMA", "TABLE");
else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD|SET", "TABLE") ||
(HeadMatches("ALTER", "PUBLICATION", MatchAny, "ADD|SET", "TABLE") &&
ends_with(prev_wd, ',')))
@@ -1844,10 +1844,10 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH(",");
/* ALTER PUBLICATION <name> DROP */
else if (Matches("ALTER", "PUBLICATION", MatchAny, "DROP"))
- COMPLETE_WITH("ALL TABLES IN SCHEMA", "TABLE");
+ COMPLETE_WITH("TABLES IN SCHEMA", "TABLE");
/* ALTER PUBLICATION <name> SET */
else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET"))
- COMPLETE_WITH("(", "ALL TABLES IN SCHEMA", "TABLE");
+ COMPLETE_WITH("(", "TABLES IN SCHEMA", "TABLE");
else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD|DROP|SET", "ALL", "TABLES", "IN", "SCHEMA"))
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_schemas
" AND nspname NOT LIKE E'pg\\\\_%%'",
@@ -2990,9 +2990,9 @@ psql_completion(const char *text, int start, int end)
/* CREATE PUBLICATION */
else if (Matches("CREATE", "PUBLICATION", MatchAny))
- COMPLETE_WITH("FOR TABLE", "FOR ALL TABLES", "FOR ALL TABLES IN SCHEMA", "WITH (");
+ COMPLETE_WITH("FOR TABLE", "FOR ALL TABLES", "FOR TABLES IN SCHEMA", "WITH (");
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR"))
- COMPLETE_WITH("TABLE", "ALL TABLES", "ALL TABLES IN SCHEMA");
+ COMPLETE_WITH("TABLE", "ALL TABLES", "TABLES IN SCHEMA");
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL"))
COMPLETE_WITH("TABLES", "TABLES IN SCHEMA");
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES"))
@@ -3015,7 +3015,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH(" WITH (");
/*
- * Complete "CREATE PUBLICATION <name> FOR ALL TABLES IN SCHEMA <schema>,
+ * Complete "CREATE PUBLICATION <name> FOR TABLES IN SCHEMA <schema>,
* ..."
*/
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES", "IN", "SCHEMA"))
@@ -3836,7 +3836,7 @@ psql_completion(const char *text, int start, int end)
"ALL PROCEDURES IN SCHEMA",
"ALL ROUTINES IN SCHEMA",
"ALL SEQUENCES IN SCHEMA",
- "ALL TABLES IN SCHEMA",
+ "TABLES IN SCHEMA",
"DATABASE",
"DOMAIN",
"FOREIGN DATA WRAPPER",
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index d63f4f1cba..656dac6801 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4593,7 +4593,7 @@ create schema alter1;
create schema alter2;
create table alter1.t1 (a int);
set client_min_messages = 'ERROR';
-create publication pub1 for table alter1.t1, all tables in schema alter2;
+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"
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 4117fc27c9..a453750658 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -45,7 +45,7 @@ CREATE TRANSFORM FOR int LANGUAGE SQL (
-- suppress warning that depends on wal_level
SET client_min_messages = 'ERROR';
CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable;
-CREATE PUBLICATION addr_pub_schema FOR ALL TABLES IN SCHEMA addr_nsp;
+CREATE PUBLICATION addr_pub_schema FOR TABLES IN SCHEMA addr_nsp;
RESET client_min_messages;
CREATE SUBSCRIPTION regress_addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE);
WARNING: tables were not subscribed, you will have to run ALTER SUBSCRIPTION ... REFRESH PUBLICATION to subscribe the tables
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index e6e082de2f..ce63511b94 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -70,22 +70,22 @@ ALTER PUBLICATION testpub_foralltables SET TABLE pub_test.testpub_nopk;
ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES
DETAIL: Tables cannot be added to or dropped from FOR ALL TABLES publications.
-- fail - can't add schema to 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables ADD ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables ADD TABLES IN SCHEMA pub_test;
ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES
DETAIL: Tables from schema cannot be added to, dropped from, or set on FOR ALL TABLES publications.
-- fail - can't drop schema from 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables DROP ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables DROP TABLES IN SCHEMA pub_test;
ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES
DETAIL: Tables from schema cannot be added to, dropped from, or set on FOR ALL TABLES publications.
-- fail - can't set schema to 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables SET ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables SET TABLES IN SCHEMA pub_test;
ERROR: publication "testpub_foralltables" is defined as FOR ALL TABLES
DETAIL: Tables from schema cannot be added to, dropped from, or set on FOR ALL TABLES publications.
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub_fortable FOR TABLE testpub_tbl1;
RESET client_min_messages;
-- should be able to add schema to 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable ADD ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable ADD TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
Publication testpub_fortable
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -97,7 +97,7 @@ Tables from schemas:
"pub_test"
-- should be able to drop schema from 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable DROP ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable DROP TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
Publication testpub_fortable
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -107,7 +107,7 @@ Tables:
"public.testpub_tbl1"
-- should be able to set schema to 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable SET ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable SET TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
Publication testpub_fortable
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -117,10 +117,10 @@ Tables from schemas:
"pub_test"
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pub_test;
+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
-CREATE PUBLICATION testpub_for_tbl_schema FOR ALL 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
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
@@ -363,13 +363,13 @@ Tables:
DROP PUBLICATION testpub_syntax2;
-- fail - schemas don't allow WHERE clause
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1 WHERE (a = 123);
+CREATE PUBLICATION testpub_syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1 WHERE (a = 123);
ERROR: syntax error at or near "WHERE"
-LINE 1: ...ntax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1 WHERE (a =...
+LINE 1: ...b_syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1 WHERE (a =...
^
-CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1, testpub_rf_schema1 WHERE (a = 123);
+CREATE PUBLICATION testpub_syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1, testpub_rf_schema1 WHERE (a = 123);
ERROR: WHERE clause not allowed for schema
-LINE 1: ...tax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1, testpub_rf...
+LINE 1: ..._syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1, testpub_rf...
^
RESET client_min_messages;
-- fail - duplicate tables are not allowed if that table has any WHERE clause
@@ -465,8 +465,8 @@ ALTER PUBLICATION testpub5 DROP TABLE testpub_rf_tbl1 WHERE (e < 27);
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;
-ALTER PUBLICATION testpub6 SET ALL TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99);
+CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2;
+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;
@@ -1119,13 +1119,13 @@ GRANT CREATE ON DATABASE regression TO regress_publication_user2;
SET ROLE regress_publication_user2;
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub2; -- ok
-CREATE PUBLICATION testpub3 FOR ALL TABLES IN SCHEMA pub_test; -- fail
-ERROR: must be superuser to create FOR ALL TABLES IN SCHEMA publication
+CREATE PUBLICATION testpub3 FOR TABLES IN SCHEMA pub_test; -- fail
+ERROR: must be superuser to create FOR TABLES IN SCHEMA publication
CREATE PUBLICATION testpub3; -- ok
RESET client_min_messages;
ALTER PUBLICATION testpub2 ADD TABLE testpub_tbl1; -- fail
ERROR: must be owner of table testpub_tbl1
-ALTER PUBLICATION testpub3 ADD ALL TABLES IN SCHEMA pub_test; -- fail
+ALTER PUBLICATION testpub3 ADD TABLES IN SCHEMA pub_test; -- fail
ERROR: must be superuser to add or set schemas
SET ROLE regress_publication_user;
GRANT regress_publication_user TO regress_publication_user2;
@@ -1137,14 +1137,14 @@ SET ROLE regress_publication_user;
CREATE ROLE regress_publication_user3;
GRANT regress_publication_user2 TO regress_publication_user3;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub4 FOR ALL TABLES IN SCHEMA pub_test;
+CREATE PUBLICATION testpub4 FOR TABLES IN SCHEMA pub_test;
RESET client_min_messages;
ALTER PUBLICATION testpub4 OWNER TO regress_publication_user3;
SET ROLE regress_publication_user3;
-- fail - new owner must be superuser
ALTER PUBLICATION testpub4 owner to regress_publication_user2; -- fail
ERROR: permission denied to change owner of publication "testpub4"
-HINT: The owner of a FOR ALL TABLES IN SCHEMA publication must be a superuser.
+HINT: The owner of a FOR TABLES IN SCHEMA publication must be a superuser.
ALTER PUBLICATION testpub4 owner to regress_publication_user; -- ok
SET ROLE regress_publication_user;
DROP PUBLICATION testpub4;
@@ -1193,7 +1193,7 @@ CREATE TABLE pub_test2.tbl1 (id serial primary key, data text);
CREATE TABLE "CURRENT_SCHEMA"."CURRENT_SCHEMA"(id int);
-- suppress warning that depends on wal_level
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub1_forschema FOR ALL TABLES IN SCHEMA pub_test1;
+CREATE PUBLICATION testpub1_forschema FOR TABLES IN SCHEMA pub_test1;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1202,7 +1202,7 @@ CREATE PUBLICATION testpub1_forschema FOR ALL TABLES IN SCHEMA pub_test1;
Tables from schemas:
"pub_test1"
-CREATE PUBLICATION testpub2_forschema FOR ALL TABLES IN SCHEMA pub_test1, pub_test2, pub_test3;
+CREATE PUBLICATION testpub2_forschema FOR TABLES IN SCHEMA pub_test1, pub_test2, pub_test3;
\dRp+ testpub2_forschema
Publication testpub2_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1214,10 +1214,10 @@ Tables from schemas:
"pub_test3"
-- check create publication on CURRENT_SCHEMA
-CREATE PUBLICATION testpub3_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA;
-CREATE PUBLICATION testpub4_forschema FOR ALL TABLES IN SCHEMA "CURRENT_SCHEMA";
-CREATE PUBLICATION testpub5_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA, "CURRENT_SCHEMA";
-CREATE PUBLICATION testpub6_forschema FOR ALL TABLES IN SCHEMA "CURRENT_SCHEMA", CURRENT_SCHEMA;
+CREATE PUBLICATION testpub3_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA;
+CREATE PUBLICATION testpub4_forschema FOR TABLES IN SCHEMA "CURRENT_SCHEMA";
+CREATE PUBLICATION testpub5_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA, "CURRENT_SCHEMA";
+CREATE PUBLICATION testpub6_forschema FOR TABLES IN SCHEMA "CURRENT_SCHEMA", CURRENT_SCHEMA;
CREATE PUBLICATION testpub_fortable FOR TABLE "CURRENT_SCHEMA"."CURRENT_SCHEMA";
RESET client_min_messages;
\dRp+ testpub3_forschema
@@ -1264,30 +1264,30 @@ Tables:
-- check create publication on CURRENT_SCHEMA where search_path is not set
SET SEARCH_PATH='';
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA;
ERROR: no schema has been selected for CURRENT_SCHEMA
RESET SEARCH_PATH;
--- check create publication on CURRENT_SCHEMA where TABLE/ALL TABLES in SCHEMA
+-- check create publication on CURRENT_SCHEMA where TABLE/TABLES in SCHEMA
-- is not specified
CREATE PUBLICATION testpub_forschema1 FOR CURRENT_SCHEMA;
ERROR: invalid publication object list
LINE 1: CREATE PUBLICATION testpub_forschema1 FOR CURRENT_SCHEMA;
^
-DETAIL: One of TABLE or ALL TABLES IN SCHEMA must be specified before a standalone table or schema name.
+DETAIL: One of TABLE or TABLES IN SCHEMA must be specified before a standalone table or schema name.
-- check create publication on CURRENT_SCHEMA along with FOR TABLE
CREATE PUBLICATION testpub_forschema1 FOR TABLE CURRENT_SCHEMA;
ERROR: syntax error at or near "CURRENT_SCHEMA"
LINE 1: CREATE PUBLICATION testpub_forschema1 FOR TABLE CURRENT_SCHE...
^
-- check create publication on a schema that does not exist
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA non_existent_schema;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA non_existent_schema;
ERROR: schema "non_existent_schema" does not exist
-- check create publication on a system schema
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pg_catalog;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pg_catalog;
ERROR: cannot add schema "pg_catalog" to publication
DETAIL: This operation is not supported for system schemas.
-- check create publication on an object which is not schema
-CREATE PUBLICATION testpub1_forschema1 FOR ALL TABLES IN SCHEMA testpub_view;
+CREATE PUBLICATION testpub1_forschema1 FOR TABLES IN SCHEMA testpub_view;
ERROR: schema "testpub_view" does not exist
-- dropping the schema should reflect the change in publication
DROP SCHEMA pub_test3;
@@ -1322,7 +1322,7 @@ Tables from schemas:
"pub_test2"
-- alter publication add schema
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA pub_test2;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1333,7 +1333,7 @@ Tables from schemas:
"pub_test2"
-- add non existent schema
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA non_existent_schema;
ERROR: schema "non_existent_schema" does not exist
\dRp+ testpub1_forschema
Publication testpub1_forschema
@@ -1345,7 +1345,7 @@ Tables from schemas:
"pub_test2"
-- add a schema which is already added to the publication
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA pub_test1;
ERROR: schema "pub_test1" is already member of publication "testpub1_forschema"
\dRp+ testpub1_forschema
Publication testpub1_forschema
@@ -1357,7 +1357,7 @@ Tables from schemas:
"pub_test2"
-- alter publication drop schema
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test2;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1367,7 +1367,7 @@ Tables from schemas:
"pub_test1"
-- drop schema that is not present in the publication
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test2;
ERROR: tables from schema "pub_test2" are not part of the publication
\dRp+ testpub1_forschema
Publication testpub1_forschema
@@ -1378,7 +1378,7 @@ Tables from schemas:
"pub_test1"
-- drop a schema that does not exist in the system
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA non_existent_schema;
ERROR: schema "non_existent_schema" does not exist
\dRp+ testpub1_forschema
Publication testpub1_forschema
@@ -1389,7 +1389,7 @@ Tables from schemas:
"pub_test1"
-- drop all schemas
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test1;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1398,7 +1398,7 @@ ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test1;
(1 row)
-- alter publication set multiple schema
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1, pub_test2;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test2;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1409,7 +1409,7 @@ Tables from schemas:
"pub_test2"
-- alter publication set non-existent schema
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA non_existent_schema;
ERROR: schema "non_existent_schema" does not exist
\dRp+ testpub1_forschema
Publication testpub1_forschema
@@ -1422,7 +1422,7 @@ Tables from schemas:
-- alter publication set it duplicate schemas should set the schemas after
-- removing the duplicate schemas
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1, pub_test1;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test1;
\dRp+ testpub1_forschema
Publication testpub1_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1432,16 +1432,16 @@ Tables from schemas:
"pub_test1"
-- Verify that it fails to add a schema with a column specification
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA foo (a, b);
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA foo (a, b);
ERROR: syntax error at or near "("
-LINE 1: ...TION testpub1_forschema ADD ALL TABLES IN SCHEMA foo (a, b);
+LINE 1: ...LICATION testpub1_forschema ADD TABLES IN SCHEMA foo (a, b);
^
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA foo, bar (a, b);
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA foo, bar (a, b);
ERROR: column specification not allowed for schema
-LINE 1: ... testpub1_forschema ADD ALL TABLES IN SCHEMA foo, bar (a, b)...
+LINE 1: ...TION testpub1_forschema ADD TABLES IN SCHEMA foo, bar (a, b)...
^
-- cleanup pub_test1 schema for invalidation tests
-ALTER PUBLICATION testpub2_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub2_forschema DROP TABLES IN SCHEMA pub_test1;
DROP PUBLICATION testpub3_forschema, testpub4_forschema, testpub5_forschema, testpub6_forschema, testpub_fortable;
DROP SCHEMA "CURRENT_SCHEMA" CASCADE;
NOTICE: drop cascades to table "CURRENT_SCHEMA"."CURRENT_SCHEMA"
@@ -1455,10 +1455,10 @@ INSERT INTO pub_test1.tbl VALUES(1, 'test');
UPDATE pub_test1.tbl SET id = 2;
ERROR: cannot update table "tbl" because it does not have a replica identity and publishes updates
HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test1;
-- success
UPDATE pub_test1.tbl SET id = 2;
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1;
-- fail
UPDATE pub_test1.tbl SET id = 2;
ERROR: cannot update table "tbl" because it does not have a replica identity and publishes updates
@@ -1472,7 +1472,7 @@ CREATE TABLE pub_testpart2.child_parent1 partition of pub_testpart1.parent1 for
INSERT INTO pub_testpart2.child_parent1 values(1);
UPDATE pub_testpart2.child_parent1 set a = 1;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpubpart_forschema FOR ALL TABLES IN SCHEMA pub_testpart1;
+CREATE PUBLICATION testpubpart_forschema FOR TABLES IN SCHEMA pub_testpart1;
RESET client_min_messages;
-- fail
UPDATE pub_testpart1.parent1 set a = 1;
@@ -1489,7 +1489,7 @@ CREATE TABLE pub_testpart1.child_parent2 partition of pub_testpart2.parent2 for
INSERT INTO pub_testpart1.child_parent2 values(1);
UPDATE pub_testpart1.child_parent2 set a = 1;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpubpart_forschema FOR ALL TABLES IN SCHEMA pub_testpart2;
+CREATE PUBLICATION testpubpart_forschema FOR TABLES IN SCHEMA pub_testpart2;
RESET client_min_messages;
-- fail
UPDATE pub_testpart2.child_parent1 set a = 1;
@@ -1501,7 +1501,7 @@ HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
UPDATE pub_testpart1.child_parent2 set a = 1;
ERROR: cannot update table "child_parent2" because it does not have a replica identity and publishes updates
HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
--- alter publication set 'ALL TABLES IN SCHEMA' on an empty publication.
+-- alter publication set 'TABLES IN SCHEMA' on an empty publication.
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub3_forschema;
RESET client_min_messages;
@@ -1512,7 +1512,7 @@ RESET client_min_messages;
regress_publication_user | f | t | t | t | t | f
(1 row)
-ALTER PUBLICATION testpub3_forschema SET ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub3_forschema SET TABLES IN SCHEMA pub_test1;
\dRp+ testpub3_forschema
Publication testpub3_forschema
Owner | All tables | Inserts | Updates | Deletes | Truncates | Via root
@@ -1521,10 +1521,10 @@ ALTER PUBLICATION testpub3_forschema SET ALL TABLES IN SCHEMA pub_test1;
Tables from schemas:
"pub_test1"
--- create publication including both 'FOR TABLE' and 'FOR ALL TABLES IN SCHEMA'
+-- create publication including both 'FOR TABLE' and 'FOR TABLES IN SCHEMA'
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_forschema_fortable FOR ALL TABLES IN SCHEMA pub_test1, TABLE pub_test2.tbl1;
-CREATE PUBLICATION testpub_fortable_forschema FOR TABLE pub_test2.tbl1, ALL TABLES IN SCHEMA pub_test1;
+CREATE PUBLICATION testpub_forschema_fortable FOR TABLES IN SCHEMA pub_test1, TABLE pub_test2.tbl1;
+CREATE PUBLICATION testpub_fortable_forschema FOR TABLE pub_test2.tbl1, TABLES IN SCHEMA pub_test1;
RESET client_min_messages;
\dRp+ testpub_forschema_fortable
Publication testpub_forschema_fortable
@@ -1546,13 +1546,13 @@ Tables:
Tables from schemas:
"pub_test1"
--- fail specifying table without any of 'FOR ALL TABLES IN SCHEMA' or
+-- fail specifying table without any of 'FOR TABLES IN SCHEMA' or
--'FOR TABLE' or 'FOR ALL TABLES'
CREATE PUBLICATION testpub_error FOR pub_test2.tbl1;
ERROR: invalid publication object list
LINE 1: CREATE PUBLICATION testpub_error FOR pub_test2.tbl1;
^
-DETAIL: One of TABLE or ALL TABLES IN SCHEMA must be specified before a standalone table or schema name.
+DETAIL: One of TABLE or TABLES IN SCHEMA must be specified before a standalone table or schema name.
DROP VIEW testpub_view;
DROP PUBLICATION testpub_default;
DROP PUBLICATION testpib_ins_trunct;
@@ -1585,7 +1585,7 @@ CREATE SCHEMA sch2;
CREATE TABLE sch1.tbl1 (a int) PARTITION BY RANGE(a);
CREATE TABLE sch2.tbl1_part1 PARTITION OF sch1.tbl1 FOR VALUES FROM (1) to (10);
-- Schema publication that does not include the schema that has the parent table
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
SELECT * FROM pg_publication_tables;
pubname | schemaname | tablename | attnames | rowfilter
---------+------------+------------+----------+-----------
@@ -1611,7 +1611,7 @@ SELECT * FROM pg_publication_tables;
DROP PUBLICATION pub;
-- Schema publication that does not include the schema that has the parent table
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
SELECT * FROM pg_publication_tables;
pubname | schemaname | tablename | attnames | rowfilter
---------+------------+------------+----------+-----------
@@ -1643,7 +1643,7 @@ CREATE TABLE sch1.tbl1_part1 PARTITION OF sch1.tbl1 FOR VALUES FROM (1) to (10);
CREATE TABLE sch1.tbl1_part2 PARTITION OF sch1.tbl1 FOR VALUES FROM (10) to (20);
CREATE TABLE sch1.tbl1_part3 (a int) PARTITION BY RANGE(a);
ALTER TABLE sch1.tbl1 ATTACH PARTITION sch1.tbl1_part3 FOR VALUES FROM (20) to (30);
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch1 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch1 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
SELECT * FROM pg_publication_tables;
pubname | schemaname | tablename | attnames | rowfilter
---------+------------+-----------+----------+-----------
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index e7013f5e15..8846c14dbb 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -3029,7 +3029,7 @@ create schema alter1;
create schema alter2;
create table alter1.t1 (a int);
set client_min_messages = 'ERROR';
-create publication pub1 for table alter1.t1, all tables in schema alter2;
+create publication pub1 for table alter1.t1, tables in schema alter2;
reset client_min_messages;
alter table alter1.t1 set schema alter2; -- should fail
drop publication pub1;
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index acd0468a9d..3324cb6dff 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -48,7 +48,7 @@ CREATE TRANSFORM FOR int LANGUAGE SQL (
-- suppress warning that depends on wal_level
SET client_min_messages = 'ERROR';
CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable;
-CREATE PUBLICATION addr_pub_schema FOR ALL TABLES IN SCHEMA addr_nsp;
+CREATE PUBLICATION addr_pub_schema FOR TABLES IN SCHEMA addr_nsp;
RESET client_min_messages;
CREATE SUBSCRIPTION regress_addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE);
CREATE STATISTICS addr_nsp.gentable_stat ON a, b FROM addr_nsp.gentable;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index a56387edee..231c9d5c53 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -52,30 +52,30 @@ ALTER PUBLICATION testpub_foralltables DROP TABLE testpub_tbl2;
ALTER PUBLICATION testpub_foralltables SET TABLE pub_test.testpub_nopk;
-- fail - can't add schema to 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables ADD ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables ADD TABLES IN SCHEMA pub_test;
-- fail - can't drop schema from 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables DROP ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables DROP TABLES IN SCHEMA pub_test;
-- fail - can't set schema to 'FOR ALL TABLES' publication
-ALTER PUBLICATION testpub_foralltables SET ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_foralltables SET TABLES IN SCHEMA pub_test;
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub_fortable FOR TABLE testpub_tbl1;
RESET client_min_messages;
-- should be able to add schema to 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable ADD ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable ADD TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
-- should be able to drop schema from 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable DROP ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable DROP TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
-- should be able to set schema to 'FOR TABLE' publication
-ALTER PUBLICATION testpub_fortable SET ALL TABLES IN SCHEMA pub_test;
+ALTER PUBLICATION testpub_fortable SET TABLES IN SCHEMA pub_test;
\dRp+ testpub_fortable
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pub_test;
+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
-CREATE PUBLICATION testpub_for_tbl_schema FOR ALL 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
ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk;
-- fail - can't drop a table from the schema publication which isn't in the
@@ -182,8 +182,8 @@ RESET client_min_messages;
DROP PUBLICATION testpub_syntax2;
-- fail - schemas don't allow WHERE clause
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1 WHERE (a = 123);
-CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_schema1, testpub_rf_schema1 WHERE (a = 123);
+CREATE PUBLICATION testpub_syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1 WHERE (a = 123);
+CREATE PUBLICATION testpub_syntax3 FOR TABLES IN SCHEMA testpub_rf_schema1, testpub_rf_schema1 WHERE (a = 123);
RESET client_min_messages;
-- fail - duplicate tables are not allowed if that table has any WHERE clause
SET client_min_messages = 'ERROR';
@@ -241,8 +241,8 @@ ALTER PUBLICATION testpub5 SET TABLE testpub_rf_tbl1 WHERE (ROW(a, 2) IS NULL);
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;
-ALTER PUBLICATION testpub6 SET ALL TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99);
+CREATE PUBLICATION testpub6 FOR TABLES IN SCHEMA testpub_rf_schema2;
+ALTER PUBLICATION testpub6 SET TABLES IN SCHEMA testpub_rf_schema2, TABLE testpub_rf_schema2.testpub_rf_tbl6 WHERE (i < 99);
RESET client_min_messages;
DROP TABLE testpub_rf_tbl1;
@@ -747,12 +747,12 @@ GRANT CREATE ON DATABASE regression TO regress_publication_user2;
SET ROLE regress_publication_user2;
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub2; -- ok
-CREATE PUBLICATION testpub3 FOR ALL TABLES IN SCHEMA pub_test; -- fail
+CREATE PUBLICATION testpub3 FOR TABLES IN SCHEMA pub_test; -- fail
CREATE PUBLICATION testpub3; -- ok
RESET client_min_messages;
ALTER PUBLICATION testpub2 ADD TABLE testpub_tbl1; -- fail
-ALTER PUBLICATION testpub3 ADD ALL TABLES IN SCHEMA pub_test; -- fail
+ALTER PUBLICATION testpub3 ADD TABLES IN SCHEMA pub_test; -- fail
SET ROLE regress_publication_user;
GRANT regress_publication_user TO regress_publication_user2;
@@ -766,7 +766,7 @@ SET ROLE regress_publication_user;
CREATE ROLE regress_publication_user3;
GRANT regress_publication_user2 TO regress_publication_user3;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub4 FOR ALL TABLES IN SCHEMA pub_test;
+CREATE PUBLICATION testpub4 FOR TABLES IN SCHEMA pub_test;
RESET client_min_messages;
ALTER PUBLICATION testpub4 OWNER TO regress_publication_user3;
SET ROLE regress_publication_user3;
@@ -813,17 +813,17 @@ CREATE TABLE "CURRENT_SCHEMA"."CURRENT_SCHEMA"(id int);
-- suppress warning that depends on wal_level
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub1_forschema FOR ALL TABLES IN SCHEMA pub_test1;
+CREATE PUBLICATION testpub1_forschema FOR TABLES IN SCHEMA pub_test1;
\dRp+ testpub1_forschema
-CREATE PUBLICATION testpub2_forschema FOR ALL TABLES IN SCHEMA pub_test1, pub_test2, pub_test3;
+CREATE PUBLICATION testpub2_forschema FOR TABLES IN SCHEMA pub_test1, pub_test2, pub_test3;
\dRp+ testpub2_forschema
-- check create publication on CURRENT_SCHEMA
-CREATE PUBLICATION testpub3_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA;
-CREATE PUBLICATION testpub4_forschema FOR ALL TABLES IN SCHEMA "CURRENT_SCHEMA";
-CREATE PUBLICATION testpub5_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA, "CURRENT_SCHEMA";
-CREATE PUBLICATION testpub6_forschema FOR ALL TABLES IN SCHEMA "CURRENT_SCHEMA", CURRENT_SCHEMA;
+CREATE PUBLICATION testpub3_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA;
+CREATE PUBLICATION testpub4_forschema FOR TABLES IN SCHEMA "CURRENT_SCHEMA";
+CREATE PUBLICATION testpub5_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA, "CURRENT_SCHEMA";
+CREATE PUBLICATION testpub6_forschema FOR TABLES IN SCHEMA "CURRENT_SCHEMA", CURRENT_SCHEMA;
CREATE PUBLICATION testpub_fortable FOR TABLE "CURRENT_SCHEMA"."CURRENT_SCHEMA";
RESET client_min_messages;
@@ -836,10 +836,10 @@ RESET client_min_messages;
-- check create publication on CURRENT_SCHEMA where search_path is not set
SET SEARCH_PATH='';
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA CURRENT_SCHEMA;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA CURRENT_SCHEMA;
RESET SEARCH_PATH;
--- check create publication on CURRENT_SCHEMA where TABLE/ALL TABLES in SCHEMA
+-- check create publication on CURRENT_SCHEMA where TABLE/TABLES in SCHEMA
-- is not specified
CREATE PUBLICATION testpub_forschema1 FOR CURRENT_SCHEMA;
@@ -847,13 +847,13 @@ CREATE PUBLICATION testpub_forschema1 FOR CURRENT_SCHEMA;
CREATE PUBLICATION testpub_forschema1 FOR TABLE CURRENT_SCHEMA;
-- check create publication on a schema that does not exist
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA non_existent_schema;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA non_existent_schema;
-- check create publication on a system schema
-CREATE PUBLICATION testpub_forschema FOR ALL TABLES IN SCHEMA pg_catalog;
+CREATE PUBLICATION testpub_forschema FOR TABLES IN SCHEMA pg_catalog;
-- check create publication on an object which is not schema
-CREATE PUBLICATION testpub1_forschema1 FOR ALL TABLES IN SCHEMA testpub_view;
+CREATE PUBLICATION testpub1_forschema1 FOR TABLES IN SCHEMA testpub_view;
-- dropping the schema should reflect the change in publication
DROP SCHEMA pub_test3;
@@ -867,52 +867,52 @@ ALTER SCHEMA pub_test1_renamed RENAME to pub_test1;
\dRp+ testpub2_forschema
-- alter publication add schema
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA pub_test2;
\dRp+ testpub1_forschema
-- add non existent schema
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA non_existent_schema;
\dRp+ testpub1_forschema
-- add a schema which is already added to the publication
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA pub_test1;
\dRp+ testpub1_forschema
-- alter publication drop schema
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test2;
\dRp+ testpub1_forschema
-- drop schema that is not present in the publication
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test2;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test2;
\dRp+ testpub1_forschema
-- drop a schema that does not exist in the system
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA non_existent_schema;
\dRp+ testpub1_forschema
-- drop all schemas
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test1;
\dRp+ testpub1_forschema
-- alter publication set multiple schema
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1, pub_test2;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test2;
\dRp+ testpub1_forschema
-- alter publication set non-existent schema
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA non_existent_schema;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA non_existent_schema;
\dRp+ testpub1_forschema
-- alter publication set it duplicate schemas should set the schemas after
-- removing the duplicate schemas
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1, pub_test1;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test1;
\dRp+ testpub1_forschema
-- Verify that it fails to add a schema with a column specification
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA foo (a, b);
-ALTER PUBLICATION testpub1_forschema ADD ALL TABLES IN SCHEMA foo, bar (a, b);
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA foo (a, b);
+ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA foo, bar (a, b);
-- cleanup pub_test1 schema for invalidation tests
-ALTER PUBLICATION testpub2_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub2_forschema DROP TABLES IN SCHEMA pub_test1;
DROP PUBLICATION testpub3_forschema, testpub4_forschema, testpub5_forschema, testpub6_forschema, testpub_fortable;
DROP SCHEMA "CURRENT_SCHEMA" CASCADE;
@@ -925,11 +925,11 @@ INSERT INTO pub_test1.tbl VALUES(1, 'test');
-- fail
UPDATE pub_test1.tbl SET id = 2;
-ALTER PUBLICATION testpub1_forschema DROP ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test1;
-- success
UPDATE pub_test1.tbl SET id = 2;
-ALTER PUBLICATION testpub1_forschema SET ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1;
-- fail
UPDATE pub_test1.tbl SET id = 2;
@@ -944,7 +944,7 @@ CREATE TABLE pub_testpart2.child_parent1 partition of pub_testpart1.parent1 for
INSERT INTO pub_testpart2.child_parent1 values(1);
UPDATE pub_testpart2.child_parent1 set a = 1;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpubpart_forschema FOR ALL TABLES IN SCHEMA pub_testpart1;
+CREATE PUBLICATION testpubpart_forschema FOR TABLES IN SCHEMA pub_testpart1;
RESET client_min_messages;
-- fail
@@ -960,7 +960,7 @@ CREATE TABLE pub_testpart1.child_parent2 partition of pub_testpart2.parent2 for
INSERT INTO pub_testpart1.child_parent2 values(1);
UPDATE pub_testpart1.child_parent2 set a = 1;
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpubpart_forschema FOR ALL TABLES IN SCHEMA pub_testpart2;
+CREATE PUBLICATION testpubpart_forschema FOR TABLES IN SCHEMA pub_testpart2;
RESET client_min_messages;
-- fail
@@ -968,24 +968,24 @@ UPDATE pub_testpart2.child_parent1 set a = 1;
UPDATE pub_testpart2.parent2 set a = 1;
UPDATE pub_testpart1.child_parent2 set a = 1;
--- alter publication set 'ALL TABLES IN SCHEMA' on an empty publication.
+-- alter publication set 'TABLES IN SCHEMA' on an empty publication.
SET client_min_messages = 'ERROR';
CREATE PUBLICATION testpub3_forschema;
RESET client_min_messages;
\dRp+ testpub3_forschema
-ALTER PUBLICATION testpub3_forschema SET ALL TABLES IN SCHEMA pub_test1;
+ALTER PUBLICATION testpub3_forschema SET TABLES IN SCHEMA pub_test1;
\dRp+ testpub3_forschema
--- create publication including both 'FOR TABLE' and 'FOR ALL TABLES IN SCHEMA'
+-- create publication including both 'FOR TABLE' and 'FOR TABLES IN SCHEMA'
SET client_min_messages = 'ERROR';
-CREATE PUBLICATION testpub_forschema_fortable FOR ALL TABLES IN SCHEMA pub_test1, TABLE pub_test2.tbl1;
-CREATE PUBLICATION testpub_fortable_forschema FOR TABLE pub_test2.tbl1, ALL TABLES IN SCHEMA pub_test1;
+CREATE PUBLICATION testpub_forschema_fortable FOR TABLES IN SCHEMA pub_test1, TABLE pub_test2.tbl1;
+CREATE PUBLICATION testpub_fortable_forschema FOR TABLE pub_test2.tbl1, TABLES IN SCHEMA pub_test1;
RESET client_min_messages;
\dRp+ testpub_forschema_fortable
\dRp+ testpub_fortable_forschema
--- fail specifying table without any of 'FOR ALL TABLES IN SCHEMA' or
+-- fail specifying table without any of 'FOR TABLES IN SCHEMA' or
--'FOR TABLE' or 'FOR ALL TABLES'
CREATE PUBLICATION testpub_error FOR pub_test2.tbl1;
@@ -1015,7 +1015,7 @@ CREATE SCHEMA sch2;
CREATE TABLE sch1.tbl1 (a int) PARTITION BY RANGE(a);
CREATE TABLE sch2.tbl1_part1 PARTITION OF sch1.tbl1 FOR VALUES FROM (1) to (10);
-- Schema publication that does not include the schema that has the parent table
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
SELECT * FROM pg_publication_tables;
DROP PUBLICATION pub;
@@ -1029,7 +1029,7 @@ SELECT * FROM pg_publication_tables;
DROP PUBLICATION pub;
-- Schema publication that does not include the schema that has the parent table
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch2 WITH (PUBLISH_VIA_PARTITION_ROOT=0);
SELECT * FROM pg_publication_tables;
DROP PUBLICATION pub;
@@ -1050,7 +1050,7 @@ CREATE TABLE sch1.tbl1_part1 PARTITION OF sch1.tbl1 FOR VALUES FROM (1) to (10);
CREATE TABLE sch1.tbl1_part2 PARTITION OF sch1.tbl1 FOR VALUES FROM (10) to (20);
CREATE TABLE sch1.tbl1_part3 (a int) PARTITION BY RANGE(a);
ALTER TABLE sch1.tbl1 ATTACH PARTITION sch1.tbl1_part3 FOR VALUES FROM (20) to (30);
-CREATE PUBLICATION pub FOR ALL TABLES IN SCHEMA sch1 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
+CREATE PUBLICATION pub FOR TABLES IN SCHEMA sch1 WITH (PUBLISH_VIA_PARTITION_ROOT=1);
SELECT * FROM pg_publication_tables;
RESET client_min_messages;
diff --git a/src/test/subscription/t/025_rep_changes_for_schema.pl b/src/test/subscription/t/025_rep_changes_for_schema.pl
index 627c63b529..4cfdb8b8ad 100644
--- a/src/test/subscription/t/025_rep_changes_for_schema.pl
+++ b/src/test/subscription/t/025_rep_changes_for_schema.pl
@@ -18,7 +18,7 @@ my $node_subscriber = PostgreSQL::Test::Cluster->new('subscriber');
$node_subscriber->init(allows_streaming => 'logical');
$node_subscriber->start;
-# Test replication with publications created using FOR ALL TABLES IN SCHEMA
+# Test replication with publications created using FOR TABLES IN SCHEMA
# option.
# Create schemas and tables on publisher
$node_publisher->safe_psql('postgres', "CREATE SCHEMA sch1");
@@ -56,7 +56,7 @@ $node_subscriber->safe_psql('postgres',
# Setup logical replication
my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
$node_publisher->safe_psql('postgres',
- "CREATE PUBLICATION tap_pub_schema FOR ALL TABLES IN SCHEMA sch1");
+ "CREATE PUBLICATION tap_pub_schema FOR TABLES IN SCHEMA sch1");
$node_subscriber->safe_psql('postgres',
"CREATE SUBSCRIPTION tap_sub_schema CONNECTION '$publisher_connstr' PUBLICATION tap_pub_schema"
@@ -190,7 +190,7 @@ is($result, qq(3),
$node_publisher->safe_psql(
'postgres', "
INSERT INTO sch1.tab1 VALUES(21);
- ALTER PUBLICATION tap_pub_schema DROP ALL TABLES IN SCHEMA sch1;
+ ALTER PUBLICATION tap_pub_schema DROP TABLES IN SCHEMA sch1;
INSERT INTO sch1.tab1 values(22);"
);
diff --git a/src/test/subscription/t/028_row_filter.pl b/src/test/subscription/t/028_row_filter.pl
index f5f8a67092..ba07ed37b7 100644
--- a/src/test/subscription/t/028_row_filter.pl
+++ b/src/test/subscription/t/028_row_filter.pl
@@ -77,9 +77,9 @@ $node_subscriber->safe_psql('postgres', "DROP TABLE tab_rf_x");
# ====================================================================
# ====================================================================
-# Testcase start: ALL TABLES IN SCHEMA
+# Testcase start: TABLES IN SCHEMA
#
-# The ALL TABLES IN SCHEMA test is independent of all other test cases so it
+# The TABLES IN SCHEMA test is independent of all other test cases so it
# cleans up after itself.
# create tables pub and sub
@@ -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 TABLES IN SCHEMA schema_rf_x"
);
$node_publisher->safe_psql('postgres',
"ALTER PUBLICATION tap_pub_allinschema ADD TABLE public.tab_rf_partition WHERE (x > 10)"
@@ -131,7 +131,7 @@ $node_subscriber->safe_psql('postgres',
# wait for initial table synchronization to finish
$node_subscriber->wait_for_subscription_sync($node_publisher, $appname);
-# The subscription of the ALL TABLES IN SCHEMA publication means there should be
+# The subscription of the TABLES IN SCHEMA publication means there should be
# no filtering on the tablesync COPY, so expect all 5 will be present.
$result = $node_subscriber->safe_psql('postgres',
"SELECT count(x) FROM schema_rf_x.tab_rf_x");
@@ -139,7 +139,7 @@ is($result, qq(5),
'check initial data copy from table tab_rf_x should not be filtered');
# Similarly, the table filter for tab_rf_x (after the initial phase) has no
-# effect when combined with the ALL TABLES IN SCHEMA. Meanwhile, the filter for
+# effect when combined with the TABLES IN SCHEMA. Meanwhile, the filter for
# the tab_rf_partition does work because that partition belongs to a different
# schema (and publish_via_partition_root = false).
# Expected:
@@ -175,7 +175,7 @@ $node_subscriber->safe_psql('postgres',
$node_subscriber->safe_psql('postgres', "DROP TABLE schema_rf_x.tab_rf_x");
$node_subscriber->safe_psql('postgres', "DROP SCHEMA schema_rf_x");
-# Testcase end: ALL TABLES IN SCHEMA
+# Testcase end: TABLES IN SCHEMA
# ====================================================================
# ======================================================
diff --git a/src/test/subscription/t/031_column_list.pl b/src/test/subscription/t/031_column_list.pl
index b6644556cf..3e4bfc2178 100644
--- a/src/test/subscription/t/031_column_list.pl
+++ b/src/test/subscription/t/031_column_list.pl
@@ -913,7 +913,7 @@ $node_publisher->safe_psql(
DROP TABLE test_mix_2;
CREATE TABLE test_mix_3 (a int PRIMARY KEY, b int, c int);
CREATE PUBLICATION pub_mix_5 FOR TABLE test_mix_3 (a, b, c);
- CREATE PUBLICATION pub_mix_6 FOR ALL TABLES IN SCHEMA public;
+ CREATE PUBLICATION pub_mix_6 FOR TABLES IN SCHEMA public;
-- initial data
INSERT INTO test_mix_3 VALUES (1, 2, 3);
@@ -1004,7 +1004,7 @@ $node_publisher->safe_psql(
CREATE TABLE s1.t (a int, b int, c int) PARTITION BY RANGE (a);
CREATE TABLE t_1 PARTITION OF s1.t FOR VALUES FROM (1) TO (10);
- CREATE PUBLICATION pub1 FOR ALL TABLES IN SCHEMA s1;
+ CREATE PUBLICATION pub1 FOR TABLES IN SCHEMA s1;
CREATE PUBLICATION pub2 FOR TABLE t_1(a, b, c);
-- initial data
--
2.30.2
On 9/21/22 10:24 AM, Alvaro Herrera wrote:
On 2022-Sep-20, Robert Haas wrote:
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."Nah, there's room for multiple behaviors here. It's reasonable to want
to add all the tables currently in the schema to a publication (or
grant permissions on them) and it's reasonable to want to include all
current and future tables in the schema in a publication (or grant
permissions on them) too. The reason I don't like the ALL TABLES IN
SCHEMA syntax is that it sounds like the former, but actually is the
latter. Based on your link to the email from Tom, I understand now the
reason why it's like that, but it's still counterintuitive to me.I already proposed elsewhere that we remove the ALL keyword from there,
which I think serves to reduce confusion (in particular it's no longer
parallel to the GRANT one). As in the attached.
[personal, not RMT hat]
I'd be OK with this. It would still allow for "FOR SEQUENCES IN SCHEMA" etc.
Jonathan
On Wed, Sep 21, 2022 at 8:24 PM Jonathan S. Katz <jkatz@postgresql.org> wrote:
On 9/21/22 10:24 AM, Alvaro Herrera wrote:
On 2022-Sep-20, Robert Haas wrote:
I don't think we should change this behavior that's already in logical
replication. While I understand the reasons why "GRANT ... ALL TABLES IN
SCHEMA" has a different behavior (i.e. it's not applied to future
objects) and do not advocate to change it, I have personally been
affected where I thought a permission would be applied to all future
objects, only to discover otherwise. I believe it's more intuitive to
think that "ALL" applies to "everything, always."Nah, there's room for multiple behaviors here. It's reasonable to want
to add all the tables currently in the schema to a publication (or
grant permissions on them) and it's reasonable to want to include all
current and future tables in the schema in a publication (or grant
permissions on them) too. The reason I don't like the ALL TABLES IN
SCHEMA syntax is that it sounds like the former, but actually is the
latter. Based on your link to the email from Tom, I understand now the
reason why it's like that, but it's still counterintuitive to me.I already proposed elsewhere that we remove the ALL keyword from there,
which I think serves to reduce confusion (in particular it's no longer
parallel to the GRANT one). As in the attached.
Thanks for working on this.
[personal, not RMT hat]
I'd be OK with this. It would still allow for "FOR SEQUENCES IN SCHEMA" etc.
I also think this is reasonable. It can later be extended to have an
option to exclude/include future tables with a publication option.
Also, if we want to keep it compatible with FOR ALL TABLES syntax, we
can later add ALL as an optional keyword in the syntax.
--
With Regards,
Amit Kapila.
On Wed, Sep 21, 2022 at 1:15 AM Jonathan S. Katz <jkatz@postgresql.org> wrote:
(RMT hat on, unless otherwise noted)
On 9/20/22 9:42 AM, Robert Haas wrote:
On Mon, Sep 19, 2022 at 11:03 PM Jonathan S. Katz <jkatz@postgresql.org> wrote:
For #1 (allowing calls that have schema/table overlap...), there appears
to be both a patch that allows this (reversing[8]), and a suggestion for
dealing with a corner-case that is reasonable, i.e. disallowing adding
schemas to a publication when specifying column-lists. Do we think we
can have consensus on this prior to the RC1 freeze?I am not sure whether we can or should rush a fix in that fast, but I
agree with this direction.The RMT met today to discuss this.
We did agree that the above is an open item that should be resolved
before this release. While it is an accepted pattern for us to "ERROR"
on unsupported behavior and then later introduce said behavior, we do
agree with Peter's original post in this thread and would like it resolved.
As there seems to be an agreement with this direction, I think it is
better to commit the patch in this release (before RC1) to avoid users
seeing any behavior change in a later release. If the proposed
behavior for one of the cases (disallowing adding schemas to a
publication when specifying column-lists) turns out to be too
restrictive for users, we can make it less restrictive in a future
release. I am planning to commit the current patch [1]/messages/by-id/OS0PR01MB57162E862758402F978725CD944B9@OS0PR01MB5716.jpnprd01.prod.outlook.com tomorrow unless
RMT or anyone else thinks otherwise.
[1]: /messages/by-id/OS0PR01MB57162E862758402F978725CD944B9@OS0PR01MB5716.jpnprd01.prod.outlook.com
--
With Regards,
Amit Kapila.
FWIW I put this to CI:
https://cirrus-ci.com/build/5823276948652032 (master)
and everything appears to be OK. If anybody has reservations about this
grammar change, please speak up soon, as there's not much time before RC1.
The one for 15 just started running:
https://cirrus-ci.com/build/4735322423558144
--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
"El miedo atento y previsor es la madre de la seguridad" (E. Burke)
On Sep 22, 2022, at 8:02 AM, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
FWIW I put this to CI:
https://cirrus-ci.com/build/5823276948652032 (master)and everything appears to be OK. If anybody has reservations about this
grammar change, please speak up soon, as there's not much time before RC1.The one for 15 just started running:
https://cirrus-ci.com/build/4735322423558144
[personal hat, not RMT]
Looks like it passed. No objections.
Jonathan