v50-0002-fixes-0001.patch

text/x-patch

Filename: v50-0002-fixes-0001.patch
Type: text/x-patch
Part: 1
Message: Re: row filtering for logical replication

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v50-0002
Subject: fixes 0001
File+
doc/src/sgml/ref/create_publication.sgml 3 4
doc/src/sgml/ref/create_subscription.sgml 12 11
src/backend/commands/publicationcmds.c 3 3
src/backend/replication/pgoutput/pgoutput.c 5 5
src/test/regress/expected/publication.out 5 5
src/test/regress/sql/publication.sql 2 2
From a71668b85eac7b59b33a0fdd57e242f278b61107 Mon Sep 17 00:00:00 2001
From: Euler Taveira <euler.taveira@enterprisedb.com>
Date: Fri, 17 Dec 2021 16:06:51 -0300
Subject: [PATCH v50 2/8] fixes 0001

---
 doc/src/sgml/ref/create_publication.sgml    |  7 +++----
 doc/src/sgml/ref/create_subscription.sgml   | 23 +++++++++++----------
 src/backend/commands/publicationcmds.c      |  6 +++---
 src/backend/replication/pgoutput/pgoutput.c | 10 ++++-----
 src/test/regress/expected/publication.out   | 10 ++++-----
 src/test/regress/sql/publication.sql        |  4 ++--
 6 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml
index 5aeee2309d..1c0d6111ca 100644
--- a/doc/src/sgml/ref/create_publication.sgml
+++ b/doc/src/sgml/ref/create_publication.sgml
@@ -239,10 +239,9 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
    <command>DELETE</command> operations to be published. 
    For publication of <command>INSERT</command> operations, any column
    may be used in the <literal>WHERE</literal> clause.
-   If nullable columns are present in the <literal>WHERE</literal> clause,
-   possible NULL values should be accounted for in expressions, to avoid
-   unexpected results, because <literal>NULL</literal> values can cause 
-   those expressions to evaluate to false. 
+   A nullable column in the <literal>WHERE</literal> clause could cause the
+   expression to evaluate to false; avoid using columns without not-null
+   constraints in the <literal>WHERE</literal> clause.
    A <literal>WHERE</literal> clause allows simple expressions. The simple
    expression cannot contain any aggregate or window functions, non-immutable
    functions, user-defined types, operators or functions.
diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml
index db255f323a..17c4606785 100644
--- a/doc/src/sgml/ref/create_subscription.sgml
+++ b/doc/src/sgml/ref/create_subscription.sgml
@@ -328,17 +328,18 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl
   <para>
    If any table in the publication has a <literal>WHERE</literal> clause, rows
    that do not satisfy the <replaceable class="parameter">expression</replaceable>
-   will not be published (i.e. they will be filtered out).
-   If the subscription has several publications in which the same table has been
-   published with different <literal>WHERE</literal> clauses, those expressions
-   (for the same publish operation) get OR'ed together so that rows satisfying any
-   of the expressions will be published. Also, if one of the publications for the
-   same table has no <literal>WHERE</literal> clause at all, or is a <literal>FOR
-   ALL TABLES</literal> or <literal>FOR ALL TABLES IN SCHEMA</literal> publication,
-   then all other <literal>WHERE</literal> clauses (for the same publish operation)
-   become redundant.
-   If the subscriber is a <productname>PostgreSQL</productname> version before 15
-   then any row filtering is ignored during the initial data synchronization phase.
+   will not be published. If the subscription has several publications in which
+   the same table has been published with different <literal>WHERE</literal>
+   clauses, a row will be published if any of the expressions (referring to that
+   publish operation) is satisfied. In this case of different
+   <literal>WHERE</literal> clauses, if one of the 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
+   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
+   phase.
   </para>
 
  </refsect1>
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 9ca743c6d2..a43ad41c6b 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -983,11 +983,11 @@ OpenTableList(List *tables)
 		 */
 		if (list_member_oid(relids, myrelid))
 		{
-			/* Disallow duplicate tables if there are any with row-filters. */
+			/* Disallow duplicate tables if there are any with row filters. */
 			if (t->whereClause || list_member_oid(relids_with_rf, myrelid))
 				ereport(ERROR,
 						(errcode(ERRCODE_DUPLICATE_OBJECT),
-						 errmsg("conflicting or redundant row-filters for \"%s\"",
+						 errmsg("conflicting or redundant WHERE clauses for table \"%s\"",
 								RelationGetRelationName(rel))));
 
 			table_close(rel, ShareUpdateExclusiveLock);
@@ -1164,7 +1164,7 @@ PublicationDropTables(Oid pubid, List *rels, bool missing_ok)
 		if (pubrel->whereClause)
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("invalid use of WHERE row-filter in ALTER PUBLICATION ... DROP TABLE")));
+					 errmsg("cannot use a WHERE clause when removing a table from publication")));
 
 		ObjectAddressSet(obj, PublicationRelRelationId, prid);
 		performDeletion(&obj, DROP_CASCADE, 0);
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 2fa08e7278..be5ec1d28f 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -698,7 +698,7 @@ pgoutput_row_filter_init_expr(Node *rfnode)
 	if (expr == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_CANNOT_COERCE),
-				 errmsg("row filter returns type %s that cannot be cast to the expected type %s",
+				 errmsg("row filter returns type %s that cannot be coerced to the expected type %s",
 						format_type_be(exprtype),
 						format_type_be(BOOLOID)),
 				 errhint("You will need to rewrite the row filter.")));
@@ -814,7 +814,7 @@ pgoutput_row_filter(enum ReorderBufferChangeType changetype, PGOutputData *data,
 			bool		rfisnull;
 
 			/*
-			 * Lookup if there is a row-filter, and if yes remember it in a list (per
+			 * Lookup if there is a row filter, and if yes remember it in a list (per
 			 * pubaction). If no, then remember there was no filter for this pubaction.
 			 * Code following this 'publications' loop will combine all filters.
 			 */
@@ -848,7 +848,7 @@ pgoutput_row_filter(enum ReorderBufferChangeType changetype, PGOutputData *data,
 				}
 				else
 				{
-					/* Remember which pubactions have no row-filter. */
+					/* Remember which pubactions have no row filter. */
 					if (pub->pubactions.pubinsert)
 						no_filter[idx_ins] = true;
 					if (pub->pubactions.pubupdate)
@@ -856,7 +856,7 @@ pgoutput_row_filter(enum ReorderBufferChangeType changetype, PGOutputData *data,
 					if (pub->pubactions.pubdelete)
 						no_filter[idx_del] = true;
 
-					/* Quick exit loop if all pubactions have no row-filter. */
+					/* Quick exit loop if all pubactions have no row filter. */
 					if (no_filter[idx_ins] && no_filter[idx_upd] && no_filter[idx_del])
 					{
 						ReleaseSysCache(rftuple);
@@ -947,7 +947,7 @@ pgoutput_row_filter(enum ReorderBufferChangeType changetype, PGOutputData *data,
 	ExecStoreHeapTuple(newtuple ? newtuple : oldtuple, ecxt->ecxt_scantuple, false);
 
 	/*
-	 * NOTE: Multiple publication row-filters have already been combined to a
+	 * NOTE: Multiple publication row filters have already been combined to a
 	 * single exprstate (for this pubaction).
 	 */
 	if (entry->exprstate[changetype])
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 5a49003ae4..02491c4b6b 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -333,7 +333,7 @@ Tables:
     "testpub_rf_myschema.testpub_rf_tbl5" WHERE (h < 999)
 
 DROP PUBLICATION testpub_syntax2;
--- fail - schemas are not allowed WHERE row-filter
+-- fail - schemas don't allow WHERE clause
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_myschema WHERE (a = 123);
 ERROR:  syntax error at or near "WHERE"
@@ -344,12 +344,12 @@ ERROR:  WHERE clause for schema not allowed
 LINE 1: ...ax3 FOR ALL TABLES IN SCHEMA testpub_rf_myschema, testpub_rf...
                                                              ^
 RESET client_min_messages;
--- fail - duplicate tables are not allowed if that table has any WHERE row-filters
+-- fail - duplicate tables are not allowed if that table has any WHERE clause
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_dups FOR TABLE testpub_rf_tbl1 WHERE (a = 1), testpub_rf_tbl1 WITH (publish = 'insert');
-ERROR:  conflicting or redundant row-filters for "testpub_rf_tbl1"
+ERROR:  conflicting or redundant WHERE clauses for table "testpub_rf_tbl1"
 CREATE PUBLICATION testpub_dups FOR TABLE testpub_rf_tbl1, testpub_rf_tbl1 WHERE (a = 2) WITH (publish = 'insert');
-ERROR:  conflicting or redundant row-filters for "testpub_rf_tbl1"
+ERROR:  conflicting or redundant WHERE clauses for table "testpub_rf_tbl1"
 RESET client_min_messages;
 -- fail - aggregate functions not allowed in WHERE clause
 ALTER PUBLICATION  testpub5 SET TABLE testpub_rf_tbl3 WHERE (e < AVG(e));
@@ -370,7 +370,7 @@ LINE 1: ...ICATION testpub6 FOR TABLE testpub_rf_tbl3 WHERE (e =#> 27);
                                                                ^
 -- fail - WHERE not allowed in DROP
 ALTER PUBLICATION testpub5 DROP TABLE testpub_rf_tbl3 WHERE (e < 27);
-ERROR:  invalid use of WHERE row-filter in ALTER PUBLICATION ... DROP TABLE
+ERROR:  cannot use a WHERE clause when removing a table from publication
 -- fail - cannot ALTER SET table which is a member of a pre-existing schema
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub7 FOR ALL TABLES IN SCHEMA testpub_rf_myschema1;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 47bdba86ac..9185d5a1d2 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -171,12 +171,12 @@ CREATE PUBLICATION testpub_syntax2 FOR TABLE testpub_rf_tbl1, testpub_rf_myschem
 RESET client_min_messages;
 \dRp+ testpub_syntax2
 DROP PUBLICATION testpub_syntax2;
--- fail - schemas are not allowed WHERE row-filter
+-- fail - schemas don't allow WHERE clause
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_myschema WHERE (a = 123);
 CREATE PUBLICATION testpub_syntax3 FOR ALL TABLES IN SCHEMA testpub_rf_myschema, testpub_rf_myschema WHERE (a = 123);
 RESET client_min_messages;
--- fail - duplicate tables are not allowed if that table has any WHERE row-filters
+-- fail - duplicate tables are not allowed if that table has any WHERE clause
 SET client_min_messages = 'ERROR';
 CREATE PUBLICATION testpub_dups FOR TABLE testpub_rf_tbl1 WHERE (a = 1), testpub_rf_tbl1 WITH (publish = 'insert');
 CREATE PUBLICATION testpub_dups FOR TABLE testpub_rf_tbl1, testpub_rf_tbl1 WHERE (a = 2) WITH (publish = 'insert');
-- 
2.20.1