Hi, here are my review comments for patch v31-0002.

======

1. General.

IMO patches 0001 and 0002 should be merged when next posted. IIUC the
reason for the split was only because there were 2 different authors
but that seems to be not relevant anymore.

======
Commit message

2.
When 'copy_data' is true, during the initial sync, the data is replicated from
the publisher to the subscriber using the COPY command. The normal COPY
command does not copy generated columns, so when 'publish_generated_columns'
is true, we need to copy using the syntax:
'COPY (SELECT column_name FROM table_name) TO STDOUT'.

~

2a.
Should clarify that 'copy_data' is a SUBSCRIPTION parameter.

2b.
Should clarify that 'publish_generated_columns' is a PUBLICATION parameter.

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

make_copy_attnamelist:

3.
- for (i = 0; i < rel->remoterel.natts; i++)
+ desc = RelationGetDescr(rel->localrel);
+ localgenlist = palloc0(rel->remoterel.natts * sizeof(bool));

Each time I review this code I am tricked into thinking it is wrong to
use rel->remoterel.natts here for the localgenlist. AFAICT the code is
actually fine because you do not store *all* the subscriber gencols in
'localgenlist' -- you only store those with matching names on the
publisher table. It might be good if you could add an explanatory
comment about that to prevent any future doubts.

~~~

4.
+ if (!remotegenlist[remote_attnum])
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("logical replication target relation \"%s.%s\" has a
generated column \"%s\" "
+ "but corresponding column on source relation is not a generated column",
+ rel->remoterel.nspname, rel->remoterel.relname, NameStr(attr->attname))));

This error message has lots of good information. OTOH, I think when
copy_data=false the error would report the subscriber column just as
"missing", which is maybe less helpful. Perhaps that other
copy_data=false "missing" case can be improved to share the same error
message that you have here.

~~~

fetch_remote_table_info:

5.
IIUC, this logic needs to be more sophisticated to handle the case
that was being discussed earlier with Sawada-san [1]. e.g. when the
same table has gencols but there are multiple subscribed publications
where the 'publish_generated_columns' parameter differs.

Also, you'll need test cases for this scenario, because it is too
difficult to judge correctness just by visual inspection of the code.

~~~~

6.
nit - Change 'hasgencolpub' to 'has_pub_with_pubgencols' for
readability, and initialize it to 'false' to make it easy to use
later.

~~~

7.
- * Get column lists for each relation.
+ * Get column lists for each relation and check if any of the publication
+ * has generated column option.

and

+ /* Check if any of the publication has generated column option */
+ if (server_version >= 180000)

nit - tweak the comments to name the publication parameter properly.

~~~

8.
foreach(lc, MySubscription->publications)
{
if (foreach_current_index(lc) > 0)
appendStringInfoString(&pub_names, ", ");
appendStringInfoString(&pub_names, quote_literal_cstr(strVal(lfirst(lc))));
}

I know this is existing code, but shouldn't all this be done by using
the purpose-built function 'get_publications_str'

~~~

9.
+ ereport(ERROR,
+ errcode(ERRCODE_CONNECTION_FAILURE),
+ errmsg("could not fetch gencolumns information from publication list: %s",
+    pub_names.data));

and

+ errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("failed to fetch tuple for gencols from publication list: %s",
+    pub_names.data));

nit - /gencolumns information/generated column publication
information/ to make the errmsg more human-readable

~~~

10.
+ bool gencols_allowed = server_version >= 180000 && hasgencolpub;
+
+ if (!gencols_allowed)
+ appendStringInfo(&cmd, " AND a.attgenerated = ''");

Can the 'gencols_allowed' var be removed, and the condition just be
replaced with if (!has_pub_with_pubgencols)? It seems equivalent
unless I am mistaken.

======

Please refer to the attachment which implements some of the nits
mentioned above.

======
[1] 
https://www.postgresql.org/message-id/CAD21AoBun9crSWaxteMqyu8A_zme2ppa2uJvLJSJC2E3DJxQVA%40mail.gmail.com

Kind Regards,
Peter Smith.
Fujitsu Australia
diff --git a/src/backend/replication/logical/tablesync.c 
b/src/backend/replication/logical/tablesync.c
index 723c44c..6d17984 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -850,7 +850,7 @@ fetch_remote_table_info(char *nspname, char *relname, bool 
**remotegenlist_res,
        Oid                     qualRow[] = {TEXTOID};
        bool            isnull;
        bool       *remotegenlist;
-       bool            hasgencolpub;
+       bool            has_pub_with_pubgencols = false;
        int                     natt;
        ListCell   *lc;
        Bitmapset  *included_cols = NULL;
@@ -897,8 +897,8 @@ fetch_remote_table_info(char *nspname, char *relname, bool 
**remotegenlist_res,
 
 
        /*
-        * Get column lists for each relation and check if any of the 
publication
-        * has generated column option.
+        * Get column lists for each relation, and check if any of the 
publications
+        * have the 'publish_generated_columns' parameter enabled.
         *
         * We need to do this before fetching info about column names and types,
         * so that we can skip columns that should not be replicated.
@@ -989,7 +989,10 @@ fetch_remote_table_info(char *nspname, char *relname, bool 
**remotegenlist_res,
 
                walrcv_clear_result(pubres);
 
-               /* Check if any of the publication has generated column option 
*/
+               /*
+                * Check if any of the publications have the 
'publish_generated_columns'
+                * parameter enabled.
+                */
                if (server_version >= 180000)
                {
                        WalRcvExecResult *gencolres;
@@ -1006,17 +1009,17 @@ fetch_remote_table_info(char *nspname, char *relname, 
bool **remotegenlist_res,
                        if (gencolres->status != WALRCV_OK_TUPLES)
                                ereport(ERROR,
                                                
errcode(ERRCODE_CONNECTION_FAILURE),
-                                               errmsg("could not fetch 
gencolumns information from publication list: %s",
+                                               errmsg("could not fetch 
generated column publication information from publication list: %s",
                                                           pub_names.data));
 
                        tslot = MakeSingleTupleTableSlot(gencolres->tupledesc, 
&TTSOpsMinimalTuple);
                        if (!tuplestore_gettupleslot(gencolres->tuplestore, 
true, false, tslot))
                                ereport(ERROR,
                                                
errcode(ERRCODE_UNDEFINED_OBJECT),
-                                               errmsg("failed to fetch tuple 
for gencols from publication list: %s",
+                                               errmsg("failed to fetch tuple 
for generated column publication information from publication list: %s",
                                                           pub_names.data));
 
-                       hasgencolpub = DatumGetBool(slot_getattr(tslot, 1, 
&isnull));
+                       has_pub_with_pubgencols = 
DatumGetBool(slot_getattr(tslot, 1, &isnull));
                        Assert(!isnull);
 
                        ExecClearTuple(tslot);
@@ -1048,7 +1051,7 @@ fetch_remote_table_info(char *nspname, char *relname, 
bool **remotegenlist_res,
 
        if (server_version >= 120000)
        {
-               bool            gencols_allowed = server_version >= 180000 && 
hasgencolpub;
+               bool            gencols_allowed = server_version >= 180000 && 
has_pub_with_pubgencols;
 
                if (!gencols_allowed)
                        appendStringInfo(&cmd, " AND a.attgenerated = ''");

Reply via email to