Hi Shubham,

here are my review comments for patch v4-0001.

======
src/backend/replication/logical/relation.c

logicalrep_report_missing_and_gen_attrs:

1.
 static void
-logicalrep_report_missing_attrs(LogicalRepRelation *remoterel,
- Bitmapset *missingatts)
+logicalrep_report_missing_and_gen_attrs(LogicalRepRelation *remoterel,
+ Bitmapset *atts,
+ bool ismissing)


Maybe the function should be called
'logicalrep_report_missing_or_gen_attrs' (not 'and')

~

2.
- if (!bms_is_empty(missingatts))
+ if (!bms_is_empty(atts))

I felt this should be an Assert because the code becomes easier to
read if you check this before making the call in the first place. See
my NITPICKS patch.

~

3.
+ if (attcnt == 1)
+ appendStringInfo(&attsbuf, _("\"%s\""),
  remoterel->attnames[i]);
  else
- appendStringInfo(&missingattsbuf, _(", \"%s\""),
+ appendStringInfo(&attsbuf, _(", \"%s\""),
  remoterel->attnames[i]);
  }

This code can be simplified (e.g. remove the 'else' etc if you just
check > 1 instead). See my NITPICKS patch.

SUGGESTION
if (attcnt > 1)
  appendStringInfo(&attsbuf, _(", "));

appendStringInfo(&attsbuf, _("\"%s\""), remoterel->attnames[i]);

~~~

logicalrep_rel_open:

4.
+ /*
+ * Include it in generatedattrs if publishing to a generated
+ * column.
+ */
+ if (attr->attgenerated)
+ generatedattrs = bms_add_member(generatedattrs, attnum);

That comment can be simpler if indeed it is needed at all.

SUGGESTION:
/* Remember which subscriber columns are generated. */

~

5.
As I reported above (#2), I think it is better to check for empty BMS
in the caller because then the code is easier to read. Also, you need
to comment on which of these 2 errors will take precedence because if
there are simultaneous problems you are still only reporting one kind
of error at a time.

SUGGESTION:
/*
 * Report any missing or generated columns. Note, if there are both
 * kinds then the 'missing' error takes precedence.
 */
if (!bms_is_empty(missingatts))
  logicalrep_report_missing_and_gen_attrs(remoterel, missingatts,
                                          true);
if (!bms_is_empty(generatedattrs))
  logicalrep_report_missing_and_gen_attrs(remoterel, generatedattrs,
                                          false);

======
src/test/subscription/t/011_generated.pl

6.
+# =============================================================================
+# The following test cases exercise logical replication for the combinations
+# where there is a generated column on one or both sides of pub/sub:
+# - regular -> generated and generated -> generated
+# - regular -> missing
+# =============================================================================


6a.
This comment is not quite right. You can't say "where there is a
generated column on one or both sides of pub/sub" because that is not
true for the "regular -> missing" case. See NITPICKS for a suggested
comment.

~

6b.
IMO you should also be testing the "generated -> missing" combination.
You don't need more tests -- just more columns.

~

6c
You also need to include a test where there are BOTH generated and
missing to show the 'missing' error takes precedence. Again, you don't
need more separate test cases to achieve this -- just need more
columns in the tables.

~~~

7.
+# --------------------------------------------------
+# A "regular -> generated" and "generated -> generated" replication fails,
+# reporting an error that the generated column on the subscriber side
+# cannot be replicated.

/and/or/

~~~

8.
+# --------------------------------------------------
+# A "regular -> missing" replication fails, reporting an error
+# that the subscriber side is missing replicated columns.
+#
+# Testcase: regular -> missing
+# Publisher table has regular columns 'c2' and 'c3'.
+# Subscriber table is missing columns 'c2' and 'c3'.
+# --------------------------------------------------

I've also added the "generated -> missing" combination and addressed
the review comment about intercluding a test where there are BOTH
missing and generated columns, so you can see which error takes
precedence. Please see the NITPICKS diff.

======
Kind Regards,
Peter Smith.
Fujitsu Australia
diff --git a/src/backend/replication/logical/relation.c 
b/src/backend/replication/logical/relation.c
index 2c7be7d..21f4f12 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -224,49 +224,46 @@ logicalrep_rel_att_by_name(LogicalRepRelation *remoterel, 
const char *attname)
  * generated columns.'
  */
 static void
-logicalrep_report_missing_and_gen_attrs(LogicalRepRelation *remoterel,
+logicalrep_report_missing_or_gen_attrs(LogicalRepRelation *remoterel,
                                                                                
Bitmapset *atts,
                                                                                
bool ismissing)
 {
-       if (!bms_is_empty(atts))
-       {
-               StringInfoData attsbuf;
-               int                     attcnt = 0;
-               int                     i;
+       StringInfoData attsbuf;
+       int                     attcnt = 0;
+       int                     i;
 
-               initStringInfo(&attsbuf);
+       Assert(!bms_is_empty(atts));
 
-               i = -1;
-               while ((i = bms_next_member(atts, i)) >= 0)
-               {
-                       attcnt++;
-                       if (attcnt == 1)
-                               appendStringInfo(&attsbuf, _("\"%s\""),
-                                                                
remoterel->attnames[i]);
-                       else
-                               appendStringInfo(&attsbuf, _(", \"%s\""),
-                                                                
remoterel->attnames[i]);
-               }
+       initStringInfo(&attsbuf);
 
-               if (ismissing)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg_plural("logical replication 
target relation \"%s.%s\" is missing replicated column: %s",
-                                                                  "logical 
replication target relation \"%s.%s\" is missing replicated columns: %s",
-                                                                  attcnt,
-                                                                  
remoterel->nspname,
-                                                                  
remoterel->relname,
-                                                                  
attsbuf.data)));
-               else
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg_plural("cannot replicate to 
target relation \"%s.%s\" generated column: %s",
-                                                                  "cannot 
replicate to target relation \"%s.%s\" generated columns: %s",
-                                                                  attcnt,
-                                                                  
remoterel->nspname,
-                                                                  
remoterel->relname,
-                                                                  
attsbuf.data)));
+       i = -1;
+       while ((i = bms_next_member(atts, i)) >= 0)
+       {
+               attcnt++;
+               if (attcnt > 1)
+                       appendStringInfo(&attsbuf, _(", "));
+
+               appendStringInfo(&attsbuf, _("\"%s\""), remoterel->attnames[i]);
        }
+
+       if (ismissing)
+               ereport(ERROR,
+                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg_plural("logical replication target 
relation \"%s.%s\" is missing replicated column: %s",
+                                                          "logical replication 
target relation \"%s.%s\" is missing replicated columns: %s",
+                                                          attcnt,
+                                                          remoterel->nspname,
+                                                          remoterel->relname,
+                                                          attsbuf.data)));
+       else
+               ereport(ERROR,
+                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg_plural("cannot replicate to target 
relation \"%s.%s\" generated column: %s",
+                                                          "cannot replicate to 
target relation \"%s.%s\" generated columns: %s",
+                                                          attcnt,
+                                                          remoterel->nspname,
+                                                          remoterel->relname,
+                                                          attsbuf.data)));
 }
 
 /*
@@ -447,10 +444,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE 
lockmode)
                        entry->attrmap->attnums[i] = attnum;
                        if (attnum >= 0)
                        {
-                               /*
-                                * Include it in generatedattrs if publishing 
to a generated
-                                * column.
-                                */
+                               /* Remember which subscriber columns are 
generated. */
                                if (attr->attgenerated)
                                        generatedattrs = 
bms_add_member(generatedattrs, attnum);
 
@@ -458,12 +452,16 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE 
lockmode)
                        }
                }
 
-               /* Report replicating to generated columns. */
-               logicalrep_report_missing_and_gen_attrs(remoterel, 
generatedattrs,
-                                                                               
                false);
-               /* Report missing columns. */
-               logicalrep_report_missing_and_gen_attrs(remoterel, missingatts,
-                                                                               
                true);
+               /*
+                * Report any missing or generated columns. Note, if there are 
both
+                * kinds then the 'missing' error takes precedence.
+                */
+               if (!bms_is_empty(missingatts))
+                       logicalrep_report_missing_or_gen_attrs(remoterel, 
missingatts,
+                                                                               
                        true);
+               if (!bms_is_empty(generatedattrs))
+                       logicalrep_report_missing_or_gen_attrs(remoterel, 
generatedattrs,
+                                                                               
                        false);
 
                /* be tidy */
                bms_free(generatedattrs);
diff --git a/src/test/subscription/t/011_generated.pl 
b/src/test/subscription/t/011_generated.pl
index 2a2df36..5a360de 100644
--- a/src/test/subscription/t/011_generated.pl
+++ b/src/test/subscription/t/011_generated.pl
@@ -327,14 +327,17 @@ $node_subscriber->safe_psql('postgres', "DROP 
SUBSCRIPTION sub1");
 $node_publisher->safe_psql('postgres', "DROP PUBLICATION pub1");
 
 # =============================================================================
-# The following test cases exercise logical replication for the combinations
-# where there is a generated column on one or both sides of pub/sub:
-# - regular -> generated and generated -> generated
+# The following tests for expected errors when attempting to replicate to a
+# missing or a generated subscriber column. Test the folowing combinations
+# - regular -> generated
+# - generated -> generated
 # - regular -> missing
+# - generated -> missing
+# - test if both errors exist, then the missing error is reported first
 # =============================================================================
 
 # --------------------------------------------------
-# A "regular -> generated" and "generated -> generated" replication fails,
+# A "regular -> generated" or "generated -> generated" replication fails,
 # reporting an error that the generated column on the subscriber side
 # cannot be replicated.
 #
@@ -369,33 +372,37 @@ $node_subscriber->safe_psql('postgres', "DROP 
SUBSCRIPTION sub1");
 $node_publisher->safe_psql('postgres', "DROP PUBLICATION pub1");
 
 # --------------------------------------------------
-# A "regular -> missing" replication fails, reporting an error
-# that the subscriber side is missing replicated columns.
+# A "regular -> missing" or "generated -> missing" replication fails,
+# reporting an error that the subscriber side is missing replicated columns.
 #
-# Testcase: regular -> missing
-# Publisher table has regular columns 'c2' and 'c3'.
-# Subscriber table is missing columns 'c2' and 'c3'.
+# Testcase: regular -> missing and generated -> missing
+# Publisher table has regular column 'c4' and generated column 'c5'.
+# Subscriber table is missing columns 'c4' and 'c5'.
+#
+# Notice how the first 3 columns of t2 are identical to the previous test,
+# so this table also has generated column errors, but they are not reported
+# because the 'missing' column error takes precedence.
 # --------------------------------------------------
 
 # Create table and publication. Insert data into the table.
 $node_publisher->safe_psql(
        'postgres', qq(
-       CREATE TABLE t2(c1 int, c2 int, c3 int);
-       CREATE PUBLICATION pub1 for table t2(c1, c2, c3);
+       CREATE TABLE t2(c1 int, c2 int, c3 int GENERATED ALWAYS AS (c1 * 2) 
STORED, c4 int, c5 int GENERATED ALWAYS AS (c1 * 2) STORED);
+       CREATE PUBLICATION pub1 for table t2(c1, c2, c3, c4, c5);
        INSERT INTO t2 VALUES (1);
 ));
 
 # Create table and subscription.
 $node_subscriber->safe_psql(
        'postgres', qq(
-       CREATE TABLE t2(c1 int);
+       CREATE TABLE t2(c1 int, c2 int GENERATED ALWAYS AS (c1 + 2) STORED, c3 
int GENERATED ALWAYS AS (c1 + 2) STORED);
        CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION 
pub1;
 ));
 
 # Verify that an error occurs.
 $offset = -s $node_subscriber->logfile;
 $node_subscriber->wait_for_log(
-       qr/ERROR: ( [A-Z0-9]:)? logical replication target relation "public.t2" 
is missing replicated columns: "c2", "c3"/,
+       qr/ERROR: ( [A-Z0-9]:)? logical replication target relation "public.t2" 
is missing replicated columns: "c4", "c5"/,
        $offset);
 
 # cleanup

Reply via email to