Correctly mark pg_subscription_rel.srsublsn as nullable.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 20 Jul 2020 18:55:56 +0000 (14:55 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 20 Jul 2020 18:55:56 +0000 (14:55 -0400)
The code has always set this column to NULL when it's not valid,
but the catalog header's description failed to reflect that,
as did the SGML docs, as did some of the code.  To prevent future
coding errors of the same ilk, let's hide the field from C code
as though it were variable-length (which, in a sense, it is).

As with commit 72eab84a5, we can only fix this cleanly in HEAD
and v13; the problem extends further back but we'll need some
klugery in the released branches.

Discussion: https://postgr.es/m/367660.1595202498@sss.pgh.pa.us

doc/src/sgml/catalogs.sgml
src/backend/catalog/pg_subscription.c
src/include/catalog/catversion.h
src/include/catalog/pg_subscription_rel.h

index 048ff284f76d97784ca7a598e2607cc5258a6c3a..a99c681887b5cacf8a2fa62e74c97bd2b204a8db 100644 (file)
@@ -7631,7 +7631,9 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        <structfield>srsublsn</structfield> <type>pg_lsn</type>
       </para>
       <para>
-       End LSN for <literal>s</literal> and <literal>r</literal> states.
+       Remote LSN of the state change used for synchronization coordination
+       when in <literal>s</literal> or <literal>r</literal> states,
+       otherwise null
       </para></entry>
      </row>
     </tbody>
index e6afb3203e9f16c8127f8016f9736293635c9fe7..90bf5cf0c6defa5ae2004a59f5f3ce1acf23e901 100644 (file)
@@ -452,13 +452,20 @@ GetSubscriptionRelations(Oid subid)
    {
        Form_pg_subscription_rel subrel;
        SubscriptionRelState *relstate;
+       Datum       d;
+       bool        isnull;
 
        subrel = (Form_pg_subscription_rel) GETSTRUCT(tup);
 
        relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState));
        relstate->relid = subrel->srrelid;
        relstate->state = subrel->srsubstate;
-       relstate->lsn = subrel->srsublsn;
+       d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup,
+                           Anum_pg_subscription_rel_srsublsn, &isnull);
+       if (isnull)
+           relstate->lsn = InvalidXLogRecPtr;
+       else
+           relstate->lsn = DatumGetLSN(d);
 
        res = lappend(res, relstate);
    }
@@ -504,13 +511,20 @@ GetSubscriptionNotReadyRelations(Oid subid)
    {
        Form_pg_subscription_rel subrel;
        SubscriptionRelState *relstate;
+       Datum       d;
+       bool        isnull;
 
        subrel = (Form_pg_subscription_rel) GETSTRUCT(tup);
 
        relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState));
        relstate->relid = subrel->srrelid;
        relstate->state = subrel->srsubstate;
-       relstate->lsn = subrel->srsublsn;
+       d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup,
+                           Anum_pg_subscription_rel_srsublsn, &isnull);
+       if (isnull)
+           relstate->lsn = InvalidXLogRecPtr;
+       else
+           relstate->lsn = DatumGetLSN(d);
 
        res = lappend(res, relstate);
    }
index dab7f4f47131cfadca4897205ade7c137cb43ade..ed3aef93d04da77ddd2a200c7dcc3610cb7c6d3a 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202007192
+#define CATALOG_VERSION_NO 202007202
 
 #endif
index c44df04c72115703321ae5a8b2d46517dd62ddea..f384f4e7fa6574affa1278f46505adc98ab22c05 100644 (file)
@@ -33,8 +33,18 @@ CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId)
    Oid         srsubid;        /* Oid of subscription */
    Oid         srrelid;        /* Oid of relation */
    char        srsubstate;     /* state of the relation in subscription */
-   XLogRecPtr  srsublsn;       /* remote lsn of the state change used for
-                                * synchronization coordination */
+
+   /*
+    * Although srsublsn is a fixed-width type, it is allowed to be NULL, so
+    * we prevent direct C code access to it just as for a varlena field.
+    */
+#ifdef CATALOG_VARLEN          /* variable-length fields start here */
+
+   XLogRecPtr  srsublsn BKI_FORCE_NULL;    /* remote LSN of the state change
+                                            * used for synchronization
+                                            * coordination, or NULL if not
+                                            * valid */
+#endif
 } FormData_pg_subscription_rel;
 
 typedef FormData_pg_subscription_rel *Form_pg_subscription_rel;