From 69f9ecae2113d1423917ae2bbfae8ca2e123db7b Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Sat, 28 Feb 2026 12:24:41 +0530 Subject: [PATCH v52 3/3] Support DROP EXCEPT TABLE in ALTER PUBLICATION Extend ALTER PUBLICATION to support DROP EXCEPT TABLE for publications defined with FOR ALL TABLES. --- doc/src/sgml/ref/alter_publication.sgml | 11 +++---- src/backend/parser/gram.y | 11 ++----- src/bin/psql/tab-complete.in.c | 6 ++-- src/test/regress/expected/publication.out | 22 +++++++++----- src/test/regress/sql/publication.sql | 3 +- .../t/037_rep_changes_except_table.pl | 29 +++++++++++++++++++ 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/doc/src/sgml/ref/alter_publication.sgml b/doc/src/sgml/ref/alter_publication.sgml index fefc4fcbf6d..0b4a5785b0f 100644 --- a/doc/src/sgml/ref/alter_publication.sgml +++ b/doc/src/sgml/ref/alter_publication.sgml @@ -41,7 +41,7 @@ ALTER PUBLICATION name RENAME TO and publication_drop_object is one of: - TABLE [ ONLY ] table_name [ * ] [, ... ] + [ EXCEPT ] TABLE [ ONLY ] table_name [ * ] [, ... ] TABLES IN SCHEMA { schema_name | CURRENT_SCHEMA } [, ... ] and table_and_columns is: @@ -63,10 +63,11 @@ ALTER PUBLICATION name RENAME TO SET clause will replace the list of except tables/tables/schemas in the publication with the specified list; the existing except tables/ tables/schemas that were present in the publication - will be removed. The ADD and DROP - clauses will add and remove one or more tables/schemas from the publication. - Note that adding tables/schemas to a publication that is already subscribed - to will require an + will be removed. The ADD clauses will add one or more + tables/schemas to the publication. The DROP clauses + will remove one or more except tables/tables/schemas from the publication. + Note that adding tables/schemas or dropping except tables to a publication + that is already subscribed to will require an ALTER SUBSCRIPTION ... REFRESH PUBLICATION action on the subscribing side in order to become effective. Note also that diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0544908fcb9..37dece5ed98 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11032,7 +11032,7 @@ AlterPublicationStmt: if (has_except_table) ereport(ERROR, errcode(ERRCODE_SYNTAX_ERROR), - errmsg("EXCEPT TABLE clause allowed only for SET clause")); + errmsg("EXCEPT TABLE clause allowed only for SET/DROP clause")); n->action = AP_AddObjects; $$ = (Node *) n; @@ -11049,18 +11049,11 @@ AlterPublicationStmt: } | ALTER PUBLICATION name DROP pub_obj_list { - bool has_except_table = false; AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; n->pubobjects = $5; - has_except_table = preprocess_pubobj_list(n->pubobjects, - yyscanner); - if (has_except_table) - ereport(ERROR, - errcode(ERRCODE_SYNTAX_ERROR), - errmsg("EXCEPT TABLE clause allowed only for SET clause")); - + preprocess_pubobj_list(n->pubobjects, yyscanner); n->action = AP_DropObjects; $$ = (Node *) n; } diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 0fc16a3e110..0a3705bb8c6 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2317,8 +2317,10 @@ match_previous_words(int pattern_id, COMPLETE_WITH(","); /* ALTER PUBLICATION DROP */ else if (Matches("ALTER", "PUBLICATION", MatchAny, "DROP")) - COMPLETE_WITH("TABLES IN SCHEMA", "TABLE"); - /* ALTER PUBLICATION SET */ + COMPLETE_WITH("EXCEPT", "TABLES IN SCHEMA", "TABLE"); + else if (Matches("ALTER", "PUBLICATION", MatchAny, "DROP", "EXCEPT")) + COMPLETE_WITH("TABLE"); + /* ALTER PUBLICATION SET */ else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET")) COMPLETE_WITH("(", "EXCEPT", "TABLES IN SCHEMA", "TABLE"); else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET", "EXCEPT")) diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index 098a470e19f..2ca08fb3125 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -128,10 +128,11 @@ Tables from schemas: -- fail - can't add an EXCEPT TABLE to 'FOR TABLE' publication ALTER PUBLICATION testpub_fortable ADD EXCEPT TABLE testpub_tbl1; -ERROR: EXCEPT TABLE clause allowed only for SET clause +ERROR: EXCEPT TABLE clause allowed only for SET/DROP clause -- fail - can't drop an EXCEPT TABLE from 'FOR TABLE' publication ALTER PUBLICATION testpub_fortable DROP EXCEPT TABLE testpub_tbl1; -ERROR: EXCEPT TABLE clause allowed only for SET clause +ERROR: publication "testpub_fortable" is defined as NON FOR ALL TABLES +DETAIL: EXCEPT Tables cannot be added to or dropped from non FOR ALL TABLES publications. -- fail - can't set an EXCEPT TABLE to 'FOR TABLE' publication ALTER PUBLICATION testpub_fortable SET EXCEPT TABLE testpub_tbl1; ERROR: publication "testpub_fortable" is defined as NON FOR ALL TABLES @@ -225,10 +226,11 @@ Not-null constraints: -- fail - can't add an EXCEPT TABLE to schema publication ALTER PUBLICATION testpub_forschema ADD EXCEPT TABLE pub_test.testpub_nopk; -ERROR: EXCEPT TABLE clause allowed only for SET clause +ERROR: EXCEPT TABLE clause allowed only for SET/DROP clause -- fail - can't drop an EXCEPT TABLE from schema publication ALTER PUBLICATION testpub_forschema DROP EXCEPT TABLE pub_test.testpub_nopk; -ERROR: EXCEPT TABLE clause allowed only for SET clause +ERROR: publication "testpub_forschema" is defined as NON FOR ALL TABLES +DETAIL: EXCEPT Tables cannot be added to or dropped from non FOR ALL TABLES publications. -- fail - can't set an EXCEPT TABLE to schema publication ALTER PUBLICATION testpub_forschema SET EXCEPT TABLE pub_test.testpub_nopk; ERROR: publication "testpub_forschema" is defined as NON FOR ALL TABLES @@ -285,12 +287,18 @@ ALTER PUBLICATION testpub_foralltables_excepttable SET EXCEPT TABLE testpub_tbl1 Except tables: "public.testpub_tbl1" --- fail - Dropping EXCEPT table is not supported. +-- Drop table from the EXCEPT list of a FOR ALL TABLES publication. ALTER PUBLICATION testpub_foralltables_excepttable DROP EXCEPT TABLE testpub_tbl1; -ERROR: EXCEPT TABLE clause allowed only for SET clause +\dRp+ testpub_foralltables_excepttable + Publication testpub_foralltables_excepttable + Owner | All tables | All sequences | Inserts | Updates | Deletes | Truncates | Generated columns | Via root +--------------------------+------------+---------------+---------+---------+---------+-----------+-------------------+---------- + regress_publication_user | t | f | t | t | t | t | none | f +(1 row) + -- fail - Adding EXCEPT table is not supported. ALTER PUBLICATION testpub_foralltables_excepttable ADD EXCEPT TABLE testpub_tbl1; -ERROR: EXCEPT TABLE clause allowed only for SET clause +ERROR: EXCEPT TABLE clause allowed only for SET/DROP clause RESET client_min_messages; DROP TABLE testpub_tbl2; DROP PUBLICATION testpub_foralltables, testpub_fortable, testpub_forschema, testpub_for_tbl_schema, testpub_foralltables_excepttable, testpub_foralltables_excepttable1; diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 957b2d183f9..a62fa0ac84d 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -138,8 +138,9 @@ CREATE PUBLICATION testpub_foralltables_excepttable1 FOR ALL TABLES EXCEPT TABLE ALTER PUBLICATION testpub_foralltables_excepttable SET EXCEPT TABLE testpub_tbl1; \dRp+ testpub_foralltables_excepttable --- fail - Dropping EXCEPT table is not supported. +-- Drop table from the EXCEPT list of a FOR ALL TABLES publication. ALTER PUBLICATION testpub_foralltables_excepttable DROP EXCEPT TABLE testpub_tbl1; +\dRp+ testpub_foralltables_excepttable -- fail - Adding EXCEPT table is not supported. ALTER PUBLICATION testpub_foralltables_excepttable ADD EXCEPT TABLE testpub_tbl1; diff --git a/src/test/subscription/t/037_rep_changes_except_table.pl b/src/test/subscription/t/037_rep_changes_except_table.pl index 794204b70c7..03d05487a9a 100644 --- a/src/test/subscription/t/037_rep_changes_except_table.pl +++ b/src/test/subscription/t/037_rep_changes_except_table.pl @@ -166,6 +166,35 @@ $result = $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM sch1.child1"); is($result, qq(10), 'check replicated inserts on subscriber'); +# Remove sch1.tab1 from the publication's EXCEPT list so that it becomes part +# of the ALL TABLES publication. +$node_publisher->safe_psql('postgres', + "ALTER PUBLICATION tap_pub_schema DROP EXCEPT TABLE sch1.tab1, sch1.parent, only sch1.parent1"); + +# Refresh the subscription so the subscriber picks up the updated +# publication definition and initiates table synchronization. +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION tap_sub_schema REFRESH PUBLICATION"); + +# Wait for initial table sync to finish +$node_subscriber->wait_for_subscription_sync($node_publisher, + 'tap_sub_schema'); + +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM sch1.tab1"); +is($result, qq(20), 'check replicated inserts on subscriber'); + +# Insert additional rows on the publisher after synchronization. +$node_publisher->safe_psql('postgres', + "INSERT INTO sch1.tab1 VALUES(generate_series(21,30))"); + +$node_publisher->wait_for_catchup('tap_sub_schema'); + +# Verify that the new inserts are also replicated. +$result = + $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM sch1.tab1"); +is($result, qq(30), 'check replicated inserts on subscriber'); + # cleanup $node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub_schema"); $node_publisher->safe_psql( -- 2.43.0