Correctly mark pg_subscription_rel.srsublsn as nullable.
authorTom Lane
Mon, 20 Jul 2020 18:55:56 +0000 (14:55 -0400)
committerTom Lane
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 918b58242f157fecbff0f7594f45c2654cfd54d2..a15d76a0e93a5e4d331cc2fa9def5cd5bbb60658 100644 (file)
@@ -7620,7 +7620,9 @@ SCRAM-SHA-256$<iteration count>:&l
        srsublsn pg_lsn
       
       
-       End LSN for s and r states.
+       Remote LSN of the state change used for synchronization coordination
+       when in s or r states,
+       otherwise null
       
      
     
index cb1573111545d331f7a546e9f725314cd5958c2d..0d23b20d62dcff7c543b282d53d6ed05a6441722 100644 (file)
@@ -451,13 +451,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);
    }
@@ -503,13 +510,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 9d9334272e85eb97e5c29c95da64f596498ecc2b..282019c49d4654cbf86f7abd5afb78d58b3d1cb1 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202007191
+#define CATALOG_VERSION_NO 202007201
 
 #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;