* we don't need to if there's no BR trigger defined on the
                  * partition.
                  */
 -               if (resultRelInfo->ri_PartitionCheck &&
 +               if (resultRelInfo->ri_RelationDesc->rd_rel->relispartition &&
                     (proute == NULL || has_before_insert_row_trig))
                     ExecPartitionCheck(resultRelInfo, myslot, estate, true);
  
                           Relation partition_root,
                   int instrument_options)
  {
 -   List       *partition_check = NIL;
 -
     MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
     resultRelInfo->type = T_ResultRelInfo;
     resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
      resultRelInfo->ri_ReturningSlot = NULL;
     resultRelInfo->ri_TrigOldSlot = NULL;
     resultRelInfo->ri_TrigNewSlot = NULL;
 -
 -   /*
 -    * Partition constraint, which also includes the partition constraint of
 -    * all the ancestors that are partitions.  Note that it will be checked
 -    * even in the case of tuple-routing where this table is the target leaf
 -    * partition, if there any BR triggers defined on the table.  Although
 -    * tuple-routing implicitly preserves the partition constraint of the
 -    * target partition for a given row, the BR triggers may change the row
 -    * such that the constraint is no longer satisfied, which we must fail for
 -    * by checking it explicitly.
 -    *
 -    * If this is a partitioned table, the partition constraint (if any) of a
 -    * given row will be checked just before performing tuple-routing.
 -    */
 -   partition_check = RelationGetPartitionQual(resultRelationDesc);
 -
 -   resultRelInfo->ri_PartitionCheck = partition_check;
     resultRelInfo->ri_PartitionRoot = partition_root;
     resultRelInfo->ri_PartitionInfo = NULL; /* may be set later */
     resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
    * ExecPartitionCheck --- check that tuple meets the partition constraint.
   *
   * Returns true if it meets the partition constraint.  If the constraint
 - * fails and we're asked to emit to error, do so and don't return; otherwise
 + * fails and we're asked to emit an error, do so and don't return; otherwise
   * return false.
   */
  bool
   
     /*
      * If first time through, build expression state tree for the partition
 -    * check expression.  Keep it in the per-query memory context so they'll
 -    * survive throughout the query.
 +    * check expression.  (In the corner case where the partition check
 +    * expression is empty, ie there's a default partition and nothing else,
 +    * we'll be fooled into executing this code each time through.  But it's
 +    * pretty darn cheap in that case, so we don't worry about it.)
      */
     if (resultRelInfo->ri_PartitionCheckExpr == NULL)
     {
 -       List       *qual = resultRelInfo->ri_PartitionCheck;
 +       /*
 +        * Ensure that the qual tree and prepared expression are in the
 +        * query-lifespan context.
 +        */
 +       MemoryContext oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
 +       List       *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc);
  
         resultRelInfo->ri_PartitionCheckExpr = ExecPrepareCheck(qual, estate);
 +       MemoryContextSwitchTo(oldcxt);
     }
  
     /*
      Bitmapset  *insertedCols;
     Bitmapset  *updatedCols;
  
 -   Assert(constr || resultRelInfo->ri_PartitionCheck);
 +   Assert(constr);             /* we should not be called otherwise */
  
 -   if (constr && constr->has_not_null)
 +   if (constr->has_not_null)
     {
         int         natts = tupdesc->natts;
         int         attrChk;
          }
     }
  
 -   if (constr && constr->num_check > 0)
 +   if (constr->num_check > 0)
     {
         const char *failed;
  
              * First check the root table's partition constraint, if any.  No point in
      * routing the tuple if it doesn't belong in the root table itself.
      */
 -   if (rootResultRelInfo->ri_PartitionCheck)
 +   if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
         ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
  
     /* start with the root partitioned table */
                 /* Check the constraints of the tuple */
         if (rel->rd_att->constr)
             ExecConstraints(resultRelInfo, slot, estate);
 -       if (resultRelInfo->ri_PartitionCheck)
 +       if (rel->rd_rel->relispartition)
             ExecPartitionCheck(resultRelInfo, slot, estate, true);
  
         /* OK, store the tuple and create index entries for it */
          /* Check the constraints of the tuple */
         if (rel->rd_att->constr)
             ExecConstraints(resultRelInfo, slot, estate);
 -       if (resultRelInfo->ri_PartitionCheck)
 +       if (rel->rd_rel->relispartition)
             ExecPartitionCheck(resultRelInfo, slot, estate, true);
  
         simple_table_tuple_update(rel, tid, slot, estate->es_snapshot,
                  * one; except that if we got here via tuple-routing, we don't need to
          * if there's no BR trigger defined on the partition.
          */
 -       if (resultRelInfo->ri_PartitionCheck &&
 +       if (resultRelationDesc->rd_rel->relispartition &&
             (resultRelInfo->ri_PartitionRoot == NULL ||
              (resultRelInfo->ri_TrigDesc &&
               resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
           * row.  So skip the WCO checks if the partition constraint fails.
          */
         partition_constraint_failed =
 -           resultRelInfo->ri_PartitionCheck &&
 +           resultRelationDesc->rd_rel->relispartition &&
             !ExecPartitionCheck(resultRelInfo, slot, estate, false);
  
         if (!partition_constraint_failed &&
                          * Does the updated tuple still satisfy the current
                  * partition's constraint?
                  */
 -               if (partrelinfo->ri_PartitionCheck == NULL ||
 +               if (!partrel->rd_rel->relispartition ||
                     ExecPartitionCheck(partrelinfo, remoteslot_part, estate,
                                        false))
                 {
             /* ON CONFLICT evaluation state */
     OnConflictSetState *ri_onConflict;
  
 -   /* partition check expression */
 -   List       *ri_PartitionCheck;
 -
 -   /* partition check expression state */
 +   /* partition check expression state (NULL if not set up yet) */
     ExprState  *ri_PartitionCheckExpr;
  
 -   /* relation descriptor for root partitioned table */
 +   /* relation descriptor for partitioned table's root, if any */
     Relation    ri_PartitionRoot;
  
 -   /* Additional information specific to partition tuple routing */
 +   /* info for partition tuple routing (NULL if not set up yet) */
     struct PartitionRoutingInfo *ri_PartitionInfo;
  
 -   /* For use by copy.c when performing multi-inserts */
 +   /* for use by copy.c when performing multi-inserts */
     struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer;
  } ResultRelInfo;