]> granicus.if.org Git - postgresql/commitdiff
Flush relcache entries when their FKs are meddled with
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 21 Jan 2019 22:34:11 +0000 (19:34 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Mon, 21 Jan 2019 22:34:11 +0000 (19:34 -0300)
Back in commit 100340e2dcd0, we made relcache entries keep lists of the
foreign keys applying to the relation -- but we forgot to update
CacheInvalidateHeapTuple to flush those entries when new FKs got created
or existing ones updated/deleted.  No bugs appear to have been reported
that would be explained by this ommission, but I noticed the problem
while working on an unrelated bugfix which clearly showed it.  Fix by
adding relcache flush on relevant foreign key changes.

Backpatch to 9.6, like the aforementioned commit.

Discussion: https://postgr.es/m/201901211927.7mmhschxlejh@alvherre.pgsql
Reviewed-by: Tom Lane
src/backend/utils/cache/inval.c

index ca283f82d2ef0c9acbd3e50e0e87d7ae3ad6e75d..8e9125a12df8611d5cc10caf5f8e17a53643b0ff 100644 (file)
@@ -53,7 +53,7 @@
  *
  *     Also, whenever we see an operation on a pg_class or pg_attribute tuple,
  *     we register a relcache flush operation for the relation described by that
- *     tuple.
+ *     tuple.  Likewise for pg_constraint tuples for foreign keys on relations.
  *
  *     We keep the relcache flush requests in lists separate from the catcache
  *     tuple flush requests.  This allows us to issue all the pending catcache
@@ -98,6 +98,7 @@
 #include "access/htup_details.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
+#include "catalog/pg_constraint.h"
 #include "miscadmin.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
@@ -1193,6 +1194,23 @@ CacheInvalidateHeapTuple(Relation relation,
                relationId = indextup->indexrelid;
                databaseId = MyDatabaseId;
        }
+       else if (tupleRelId == ConstraintRelationId)
+       {
+               Form_pg_constraint constrtup = (Form_pg_constraint) GETSTRUCT(tuple);
+
+               /*
+                * Foreign keys are part of relcache entries, too, so send out an
+                * inval for the table that the FK applies to.
+                */
+               if (constrtup->contype == CONSTRAINT_FOREIGN &&
+                       OidIsValid(constrtup->conrelid))
+               {
+                       relationId = constrtup->conrelid;
+                       databaseId = MyDatabaseId;
+               }
+               else
+                       return;
+       }
        else
                return;