Fix use of relcache TriggerDesc field introduced by commit 05c8482f7f.
authorAmit Kapila <akapila@postgresql.org>
Fri, 12 Mar 2021 09:44:41 +0000 (15:14 +0530)
committerAmit Kapila <akapila@postgresql.org>
Fri, 12 Mar 2021 09:44:41 +0000 (15:14 +0530)
The commit added code which used a relcache TriggerDesc field across
another cache access, which it shouldn't because the relcache doesn't
guarantee it won't get moved.

Diagnosed-by: Tom Lane
Author: Greg Nancarrow
Reviewed-by: Hou Zhijie, Amit Kapila
Discussion: https://postgr.es/m/2309260.1615485644@sss.pgh.pa.us

src/backend/optimizer/util/clauses.c

index 7e25f94293e99e220dc4af5bd74e4338cd04f5b2..12754fdb2bac2ad2e8fed372dc4be4f2676f7402 100644 (file)
@@ -114,7 +114,7 @@ static bool target_rel_max_parallel_hazard(max_parallel_hazard_context *context)
 static bool target_rel_max_parallel_hazard_recurse(Relation relation,
                                                                                                   CmdType command_type,
                                                                                                   max_parallel_hazard_context *context);
-static bool target_rel_trigger_max_parallel_hazard(TriggerDesc *trigdesc,
+static bool target_rel_trigger_max_parallel_hazard(Relation rel,
                                                                                                   max_parallel_hazard_context *context);
 static bool target_rel_index_max_parallel_hazard(Relation rel,
                                                                                                 max_parallel_hazard_context *context);
@@ -926,7 +926,7 @@ target_rel_max_parallel_hazard_recurse(Relation rel,
        /*
         * If any triggers exist, check that they are parallel-safe.
         */
-       if (target_rel_trigger_max_parallel_hazard(rel->trigdesc, context))
+       if (target_rel_trigger_max_parallel_hazard(rel, context))
                return true;
 
        /*
@@ -952,23 +952,29 @@ target_rel_max_parallel_hazard_recurse(Relation rel,
 /*
  * target_rel_trigger_max_parallel_hazard
  *
- * Finds the maximum parallel-mode hazard level for the specified trigger data.
+ * Finds the maximum parallel-mode hazard level for the specified relation's
+ * trigger data.
  */
 static bool
-target_rel_trigger_max_parallel_hazard(TriggerDesc *trigdesc,
+target_rel_trigger_max_parallel_hazard(Relation rel,
                                                                           max_parallel_hazard_context *context)
 {
        int                     i;
 
-       if (trigdesc == NULL)
+       if (rel->trigdesc == NULL)
                return false;
 
-       for (i = 0; i < trigdesc->numtriggers; i++)
+       /*
+        * Care is needed here to avoid using the same relcache TriggerDesc field
+        * across other cache accesses, because relcache doesn't guarantee that it
+        * won't move.
+        */
+       for (i = 0; i < rel->trigdesc->numtriggers; i++)
        {
                int                     trigtype;
-               Trigger    *trigger = &trigdesc->triggers[i];
+               Oid                     tgfoid = rel->trigdesc->triggers[i].tgfoid;
 
-               if (max_parallel_hazard_test(func_parallel(trigger->tgfoid), context))
+               if (max_parallel_hazard_test(func_parallel(tgfoid), context))
                        return true;
 
                /*
@@ -977,7 +983,7 @@ target_rel_trigger_max_parallel_hazard(TriggerDesc *trigdesc,
                 * on insert/update and this isn't supported in a parallel worker (but
                 * is safe in the parallel leader).
                 */
-               trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+               trigtype = RI_FKey_trigger_type(tgfoid);
                if (trigtype == RI_TRIGGER_FK)
                {
                        if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))