On 2018/04/15 9:17, Alvaro Herrera wrote:
> Amit Langote wrote:
>> On Sat, Apr 14, 2018 at 11:48 PM, Amit Langote <amitlangot...@gmail.com> 
>> wrote:
>>> Hi.
>>>
>>> Thanks for taking care of few things I left like those PartitionKey
>>> accessors in rel.h.
>>
>> Forgot to mention -- there are some files that still include
>> catalog/partition.h but no longer need to.  Find a delta patch
>> attached that applies on your v6.
> 
> Thanks!  I pushed this now, putting back the enum in parsenodes and
> including this delta patch of yours.

Not sure if you were intending to discuss the remaining portion of the
changes I proposed last week (patch 0002 posted at [1]), but I'm posting
those patches here for discussion.  I've divided the patch further.

0001-Make-copying-of-cached-partitioning-info-more-con.patch

    Make copying of cached partitioning info more consistent

    Currently there are many callers that hold onto pointers that
    point into the partitioning related information cached in relcache.
    There are others, such as the planner, who copy important information
    before using it.

    Make everyone copy!

    Now because no part of the backend relies on the guarantee that
    pointers to partitioning info in relcache points to same memory even
    across relcache flushes, we don't need special guards as implemented
    in RelationClearRelation() to provide the aforementioned guarantee.

0002-Cache-all-partitioning-info-under-one-memory-cont.patch

    Cache all partitioning info under one memory context

    Instead of having one for PartitionKey and another for PartitionDesc,
    use just one.  Also, instead of allocating partition constraint
    expression tree directly under CacheMemoryContext, do it under the
    aforementioned context.

0003-Cache-partsupfunc-separately-from-PartitionKey.patch

    Cache partsupfunc separately from PartitionKey

    Callers who want to use partsupfunc now have to copy them separately
    from PartitionKey, which makes copying the latter a bit cheaper.


I think going the way of 0001 might seem counter to what we may *really*
want to do in this regard, which is to make it so that we can use (keep
around) the pointer to partition info in relcache, instead of copying the
information in it piece by piece for every query.  Robert's email from a
couple of months ago (that he also recently mentioned) brought this up wrt
to relcache data usage within the planner:

* RelOptInfo -> Relation *
https://www.postgresql.org/message-id/CA%2BTgmoYKToP4-adCFFRNrO21OGuH%3Dphx-fiB1dYoqksNYX6YHQ%40mail.gmail.com

Thanks,
Amit

[1]
https://www.postgresql.org/message-id/CA%2BHiwqFo_NbJfS%2BY%3DtE94Tn5EVHXN02JkmGjwV4xT6fU3oc5OQ%40mail.gmail.com
From 56b8ef3454103349afa0dd9f5c0335f8ffc1629a Mon Sep 17 00:00:00 2001
From: Amit <amitlangot...@gmail.com>
Date: Sat, 14 Apr 2018 00:22:55 +0900
Subject: [PATCH v1 1/3] Make copying of cached partitioning info more
 consistent

Currently there are many callers that hold onto pointers that
point into the partitioning related information cached in relcache.
There are others, such as the planner, who copy important information
before using the information.

Make everyone copy!

Now because no part of the backend relies on the guarantee that
pointers to partitioning info in relcache points to same memory even
across relcache flushes, we don't need special guards as implemented
in RelationClearRelation() to provide the aforementioned guarantee.
---
 src/backend/catalog/heap.c             |   2 +-
 src/backend/catalog/partition.c        |  20 +----
 src/backend/catalog/pg_constraint.c    |   9 ++-
 src/backend/commands/indexcmds.c       |   8 +-
 src/backend/commands/tablecmds.c       |  75 ++++++++----------
 src/backend/commands/trigger.c         |  23 +++---
 src/backend/executor/execPartition.c   |  63 ++++++++-------
 src/backend/optimizer/prep/prepunion.c |  14 ++--
 src/backend/optimizer/util/plancat.c   |  75 ++++++------------
 src/backend/parser/parse_utilcmd.c     |   4 +-
 src/backend/partitioning/partbounds.c  |  38 +++++----
 src/backend/partitioning/partprune.c   |  25 +++---
 src/backend/utils/cache/partcache.c    | 140 ++++++++++++++++++++++++++++++++-
 src/backend/utils/cache/relcache.c     |  95 ++--------------------
 src/include/catalog/partition.h        |   2 -
 src/include/executor/execPartition.h   |  10 ++-
 src/include/partitioning/partbounds.h  |   2 +-
 src/include/partitioning/partprune.h   |   2 +-
 src/include/utils/partcache.h          |   5 ++
 src/include/utils/rel.h                |  12 ---
 20 files changed, 318 insertions(+), 306 deletions(-)

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 39813de991..bdb47001c8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -3473,7 +3473,7 @@ StorePartitionBound(Relation rel, Relation parent, 
PartitionBoundSpec *bound)
         * relcache entry for that partition every time a partition is added or
         * removed.
         */
-       defaultPartOid = 
get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
+       defaultPartOid = RelationGetDefaultPartitionOid(parent);
        if (OidIsValid(defaultPartOid))
                CacheInvalidateRelcacheByRelid(defaultPartOid);
 
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index de801ad788..3c76b6c69a 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -256,27 +256,11 @@ has_partition_attrs(Relation rel, Bitmapset *attnums, 
bool *used_in_expr)
 }
 
 /*
- * get_default_oid_from_partdesc
- *
- * Given a partition descriptor, return the OID of the default partition, if
- * one exists; else, return InvalidOid.
- */
-Oid
-get_default_oid_from_partdesc(PartitionDesc partdesc)
-{
-       if (partdesc && partdesc->boundinfo &&
-               partition_bound_has_default(partdesc->boundinfo))
-               return partdesc->oids[partdesc->boundinfo->default_index];
-
-       return InvalidOid;
-}
-
-/*
  * get_default_partition_oid
  *
  * Given a relation OID, return the OID of the default partition, if one
- * exists.  Use get_default_oid_from_partdesc where possible, for
- * efficiency.
+ * exists.  If you have the parent relation open, use
+ * RelationGetDefaultPartitionOid() instead.
  */
 Oid
 get_default_partition_oid(Oid parentId)
diff --git a/src/backend/catalog/pg_constraint.c 
b/src/backend/catalog/pg_constraint.c
index c5b5395791..686d0aa580 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -32,6 +32,7 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
+#include "utils/partcache.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
@@ -625,12 +626,14 @@ CloneForeignKeyConstraints(Oid parentId, Oid relationId, 
List **cloned)
 
        if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
-               PartitionDesc   partdesc = RelationGetPartitionDesc(rel);
+               int                     nparts = RelationGetPartitionCount(rel);
+               Oid                *partoids = RelationGetPartitionOids(rel);
                int                     i;
 
-               for (i = 0; i < partdesc->nparts; i++)
+               Assert(partoids != NULL || nparts == 0);
+               for (i = 0; i < nparts; i++)
                        CloneForeignKeyConstraints(RelationGetRelid(rel),
-                                                                          
partdesc->oids[i],
+                                                                          
partoids[i],
                                                                           
cloned);
        }
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f2dcc1c51f..e335dfecc4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -878,15 +878,12 @@ DefineIndex(Oid relationId,
                 */
                if (!stmt->relation || stmt->relation->inh)
                {
-                       PartitionDesc partdesc = RelationGetPartitionDesc(rel);
-                       int                     nparts = partdesc->nparts;
-                       Oid                *part_oids = palloc(sizeof(Oid) * 
nparts);
+                       int                     nparts = 
RelationGetPartitionCount(rel);
+                       Oid                *part_oids = 
RelationGetPartitionOids(rel);
                        bool            invalidate_parent = false;
                        TupleDesc       parentDesc;
                        Oid                *opfamOids;
 
-                       memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
-
                        parentDesc = CreateTupleDescCopy(RelationGetDescr(rel));
                        opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
                        for (i = 0; i < numberOfKeyAttributes; i++)
@@ -902,6 +899,7 @@ DefineIndex(Oid relationId,
                         * If none matches, build a new index by calling 
ourselves
                         * recursively with the same options (except for the 
index name).
                         */
+                       Assert(part_oids != NULL || nparts == 0);
                        for (i = 0; i < nparts; i++)
                        {
                                Oid             childRelid = part_oids[i];
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c1a9bda433..fe4265d4bb 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -829,8 +829,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
                 * the places such that lock parent, lock default partition and 
then
                 * lock the partition so as to avoid a deadlock.
                 */
-               defaultPartOid =
-                       
get_default_oid_from_partdesc(RelationGetPartitionDesc(parent));
+               defaultPartOid = RelationGetDefaultPartitionOid(parent);
                if (OidIsValid(defaultPartOid))
                        defaultRel = heap_open(defaultPartOid, 
AccessExclusiveLock);
 
@@ -5864,18 +5863,14 @@ ATPrepDropNotNull(Relation rel, bool recurse, bool 
recursing)
         * If the parent is a partitioned table, like check constraints, we do 
not
         * support removing the NOT NULL while partitions exist.
         */
-       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-       {
-               PartitionDesc partdesc = RelationGetPartitionDesc(rel);
-
-               Assert(partdesc != NULL);
-               if (partdesc->nparts > 0 && !recurse && !recursing)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                                        errmsg("cannot remove constraint from 
only the partitioned table when partitions exist"),
-                                        errhint("Do not specify the ONLY 
keyword.")));
-       }
+       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+               RelationGetPartitionCount(rel) > 0 && !recurse && !recursing)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                                errmsg("cannot remove constraint from only the 
partitioned table when partitions exist"),
+                                errhint("Do not specify the ONLY keyword.")));
 }
+
 static ObjectAddress
 ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 {
@@ -6009,16 +6004,12 @@ ATPrepSetNotNull(Relation rel, bool recurse, bool 
recursing)
         * constraints must be added to the child tables.  Complain if requested
         * otherwise and partitions exist.
         */
-       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-       {
-               PartitionDesc partdesc = RelationGetPartitionDesc(rel);
-
-               if (partdesc && partdesc->nparts > 0 && !recurse && !recursing)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                                        errmsg("cannot add constraint to only 
the partitioned table when partitions exist"),
-                                        errhint("Do not specify the ONLY 
keyword.")));
-       }
+       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+               RelationGetPartitionCount(rel) > 0 && !recurse && !recursing)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                                errmsg("cannot add constraint to only the 
partitioned table when partitions exist"),
+                                errhint("Do not specify the ONLY keyword.")));
 }
 
 /*
@@ -7699,13 +7690,13 @@ ATAddForeignKeyConstraint(List **wqueue, 
AlteredTableInfo *tab, Relation rel,
         */
        if (recurse && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
-               PartitionDesc partdesc;
+               int                     nparts = RelationGetPartitionCount(rel);
+               Oid                *partoids = RelationGetPartitionOids(rel);
 
-               partdesc = RelationGetPartitionDesc(rel);
-
-               for (i = 0; i < partdesc->nparts; i++)
+               Assert(partoids != NULL || nparts == 0);
+               for (i = 0; i < nparts; i++)
                {
-                       Oid                     partitionId = partdesc->oids[i];
+                       Oid                     partitionId = partoids[i];
                        Relation        partition = heap_open(partitionId, 
lockmode);
                        AlteredTableInfo *childtab;
                        ObjectAddress childAddr;
@@ -13989,10 +13980,12 @@ QueuePartitionConstraintValidation(List **wqueue, 
Relation scanrel,
        }
        else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
-               PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
+               int                     nparts = 
RelationGetPartitionCount(scanrel);
+               Oid                *partoids = 
RelationGetPartitionOids(scanrel);
                int                     i;
 
-               for (i = 0; i < partdesc->nparts; i++)
+               Assert(partoids != NULL || nparts == 0);
+               for (i = 0; i < nparts; i++)
                {
                        Relation        part_rel;
                        bool            found_whole_row;
@@ -14001,7 +13994,7 @@ QueuePartitionConstraintValidation(List **wqueue, 
Relation scanrel,
                        /*
                         * This is the minimum lock we need to prevent 
deadlocks.
                         */
-                       part_rel = heap_open(partdesc->oids[i], 
AccessExclusiveLock);
+                       part_rel = heap_open(partoids[i], AccessExclusiveLock);
 
                        /*
                         * Adjust the constraint for scanrel so that it matches 
this
@@ -14051,8 +14044,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, 
PartitionCmd *cmd)
         * We must lock the default partition if one exists, because attaching a
         * new partition will change its partition constraint.
         */
-       defaultPartOid =
-               get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
+       defaultPartOid = RelationGetDefaultPartitionOid(rel);
        if (OidIsValid(defaultPartOid))
                LockRelationOid(defaultPartOid, AccessExclusiveLock);
 
@@ -14628,8 +14620,7 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
         * We must lock the default partition, because detaching this partition
         * will change its partition constraint.
         */
-       defaultPartOid =
-               get_default_oid_from_partdesc(RelationGetPartitionDesc(rel));
+       defaultPartOid = RelationGetDefaultPartitionOid(rel);
        if (OidIsValid(defaultPartOid))
                LockRelationOid(defaultPartOid, AccessExclusiveLock);
 
@@ -14830,8 +14821,9 @@ ATExecAttachPartitionIdx(List **wqueue, Relation 
parentIdx, RangeVar *name)
                AttrNumber *attmap;
                bool            found;
                int                     i;
-               PartitionDesc partDesc;
-               Oid                     constraintOid,
+               int                     nparts = 
RelationGetPartitionCount(parentTbl);
+               Oid                *partoids = 
RelationGetPartitionOids(parentTbl),
+                                       constraintOid,
                                        cldConstrId = InvalidOid;
 
                /*
@@ -14849,11 +14841,11 @@ ATExecAttachPartitionIdx(List **wqueue, Relation 
parentIdx, RangeVar *name)
                                                           
RelationGetRelationName(partIdx))));
 
                /* Make sure it indexes a partition of the other index's table 
*/
-               partDesc = RelationGetPartitionDesc(parentTbl);
                found = false;
-               for (i = 0; i < partDesc->nparts; i++)
+               Assert(partoids != NULL || nparts == 0);
+               for (i = 0; i < nparts; i++)
                {
-                       if (partDesc->oids[i] == state.partitionOid)
+                       if (partoids[i] == state.partitionOid)
                        {
                                found = true;
                                break;
@@ -14984,6 +14976,7 @@ validatePartitionedIndex(Relation partedIdx, Relation 
partedTbl)
        int                             tuples = 0;
        HeapTuple               inhTup;
        bool                    updated = false;
+       int                             nparts = 
RelationGetPartitionCount(partedTbl);
 
        Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
 
@@ -15023,7 +15016,7 @@ validatePartitionedIndex(Relation partedIdx, Relation 
partedTbl)
         * If we found as many inherited indexes as the partitioned table has
         * partitions, we're good; update pg_index to set indisvalid.
         */
-       if (tuples == RelationGetPartitionDesc(partedTbl)->nparts)
+       if (tuples == nparts)
        {
                Relation        idxRel;
                HeapTuple       newtup;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 02d2a0ffd7..5081f46dda 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -55,6 +55,7 @@
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/partcache.h"
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
@@ -1087,7 +1088,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char 
*queryString,
         */
        if (partition_recurse)
        {
-               PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+               int                     nparts = RelationGetPartitionCount(rel);
+               Oid                *partoids = RelationGetPartitionOids(rel);
                List       *idxs = NIL;
                List       *childTbls = NIL;
                ListCell   *l;
@@ -1119,7 +1121,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char 
*queryString,
                oldcxt = MemoryContextSwitchTo(perChildCxt);
 
                /* Iterate to create the trigger on each existing partition */
-               for (i = 0; i < partdesc->nparts; i++)
+               Assert(partoids != NULL || nparts == 0);
+               for (i = 0; i < nparts; i++)
                {
                        Oid                     indexOnChild = InvalidOid;
                        ListCell   *l2;
@@ -1128,14 +1131,14 @@ CreateTrigger(CreateTrigStmt *stmt, const char 
*queryString,
                        Node       *qual;
                        bool            found_whole_row;
 
-                       childTbl = heap_open(partdesc->oids[i], 
ShareRowExclusiveLock);
+                       childTbl = heap_open(partoids[i], 
ShareRowExclusiveLock);
 
                        /* Find which of the child indexes is the one on this 
partition */
                        if (OidIsValid(indexOid))
                        {
                                forboth(l, idxs, l2, childTbls)
                                {
-                                       if (lfirst_oid(l2) == partdesc->oids[i])
+                                       if (lfirst_oid(l2) == partoids[i])
                                        {
                                                indexOnChild = lfirst_oid(l);
                                                break;
@@ -1144,7 +1147,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char 
*queryString,
                                if (!OidIsValid(indexOnChild))
                                        elog(ERROR, "failed to find index 
matching index \"%s\" in partition \"%s\"",
                                                 get_rel_name(indexOid),
-                                                
get_rel_name(partdesc->oids[i]));
+                                                get_rel_name(partoids[i]));
                        }
 
                        /*
@@ -1172,7 +1175,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char 
*queryString,
                                elog(ERROR, "unexpected whole-row reference 
found in trigger WHEN clause");
 
                        CreateTrigger(childStmt, queryString,
-                                                 partdesc->oids[i], refRelOid,
+                                                 partoids[i], refRelOid,
                                                  InvalidOid, indexOnChild,
                                                  funcoid, trigoid, qual,
                                                  isInternal, true);
@@ -1855,14 +1858,16 @@ EnableDisableTrigger(Relation rel, const char *tgname,
                        if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
                                (TRIGGER_FOR_ROW(oldtrig->tgtype)))
                        {
-                               PartitionDesc partdesc = 
RelationGetPartitionDesc(rel);
+                               int             nparts = 
RelationGetPartitionCount(rel);
+                               Oid        *partoids = 
RelationGetPartitionOids(rel);
                                int                     i;
 
-                               for (i = 0; i < partdesc->nparts; i++)
+                               Assert(partoids != NULL || nparts == 0);
+                               for (i = 0; i < nparts; i++)
                                {
                                        Relation        part;
 
-                                       part = relation_open(partdesc->oids[i], 
lockmode);
+                                       part = relation_open(partoids[i], 
lockmode);
                                        EnableDisableTrigger(part, 
NameStr(oldtrig->tgname),
                                                                                
 fires_when, skip_system, lockmode);
                                        heap_close(part, NoLock);       /* keep 
lock till commit */
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index 218645d43b..f04bd276ee 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -40,8 +40,8 @@ static void FormPartitionKeyDatum(PartitionDispatch pd,
                                          EState *estate,
                                          Datum *values,
                                          bool *isnull);
-static int get_partition_for_tuple(Relation relation, Datum *values,
-                                               bool *isnull);
+static int get_partition_for_tuple(PartitionDispatch pd, Datum *values,
+                                         bool *isnull);
 static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
                                                                         Datum 
*values,
                                                                         bool 
*isnull,
@@ -208,13 +208,11 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, 
PartitionDispatch *pd,
        parent = pd[0];
        while (true)
        {
-               PartitionDesc partdesc;
                TupleTableSlot *myslot = parent->tupslot;
                TupleConversionMap *map = parent->tupmap;
                int                     cur_index = -1;
 
                rel = parent->reldesc;
-               partdesc = RelationGetPartitionDesc(rel);
 
                /*
                 * Convert the tuple to this parent's layout so that we can do 
certain
@@ -245,13 +243,13 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, 
PartitionDispatch *pd,
                 * Nothing for get_partition_for_tuple() to do if there are no
                 * partitions to begin with.
                 */
-               if (partdesc->nparts == 0)
+               if (parent->nparts == 0)
                {
                        result = -1;
                        break;
                }
 
-               cur_index = get_partition_for_tuple(rel, values, isnull);
+               cur_index = get_partition_for_tuple(parent, values, isnull);
 
                /*
                 * cur_index < 0 means we failed to find a partition of this 
parent.
@@ -881,8 +879,10 @@ get_partition_dispatch_recurse(Relation rel, Relation 
parent,
                                                           List **pds, List 
**leaf_part_oids)
 {
        TupleDesc       tupdesc = RelationGetDescr(rel);
-       PartitionDesc partdesc = RelationGetPartitionDesc(rel);
        PartitionKey partkey = RelationGetPartitionKey(rel);
+       int                     nparts = RelationGetPartitionCount(rel);
+       Oid                *partoids = RelationGetPartitionOids(rel);
+       PartitionBoundInfo boundinfo = RelationGetPartitionBounds(rel);
        PartitionDispatch pd;
        int                     i;
 
@@ -894,7 +894,8 @@ get_partition_dispatch_recurse(Relation rel, Relation 
parent,
        pd->reldesc = rel;
        pd->key = partkey;
        pd->keystate = NIL;
-       pd->partdesc = partdesc;
+       pd->nparts = nparts;
+       pd->boundinfo = boundinfo;
        if (parent != NULL)
        {
                /*
@@ -939,10 +940,10 @@ get_partition_dispatch_recurse(Relation rel, Relation 
parent,
         * the tree.  This value is used to continue the search in the next 
level
         * of the partition tree.
         */
-       pd->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
-       for (i = 0; i < partdesc->nparts; i++)
+       pd->indexes = (int *) palloc(nparts * sizeof(int));
+       for (i = 0; i < nparts; i++)
        {
-               Oid                     partrelid = partdesc->oids[i];
+               Oid                     partrelid = partoids[i];
 
                if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
                {
@@ -1034,23 +1035,22 @@ FormPartitionKeyDatum(PartitionDispatch pd,
  *             Finds partition of relation which accepts the partition key 
specified
  *             in values and isnull
  *
- * Return value is index of the partition (>= 0 and < partdesc->nparts) if one
- * found or -1 if none found.
+ * Return value is index of the partition (>= 0 and < nparts) if one found or
+ * -1 if none found.
  */
-int
-get_partition_for_tuple(Relation relation, Datum *values, bool *isnull)
+static int
+get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
 {
        int                     bound_offset;
        int                     part_index = -1;
-       PartitionKey key = RelationGetPartitionKey(relation);
-       PartitionDesc partdesc = RelationGetPartitionDesc(relation);
+       PartitionKey key = pd->key;
+       PartitionBoundInfo boundinfo = pd->boundinfo;
 
        /* Route as appropriate based on partitioning strategy. */
        switch (key->strategy)
        {
                case PARTITION_STRATEGY_HASH:
                        {
-                               PartitionBoundInfo boundinfo = 
partdesc->boundinfo;
                                int                     greatest_modulus = 
get_hash_partition_greatest_modulus(boundinfo);
                                uint64          rowHash = 
compute_hash_value(key->partnatts,
                                                                                
                                 key->partsupfunc,
@@ -1063,8 +1063,8 @@ get_partition_for_tuple(Relation relation, Datum *values, 
bool *isnull)
                case PARTITION_STRATEGY_LIST:
                        if (isnull[0])
                        {
-                               if 
(partition_bound_accepts_nulls(partdesc->boundinfo))
-                                       part_index = 
partdesc->boundinfo->null_index;
+                               if (partition_bound_accepts_nulls(boundinfo))
+                                       part_index = boundinfo->null_index;
                        }
                        else
                        {
@@ -1072,10 +1072,10 @@ get_partition_for_tuple(Relation relation, Datum 
*values, bool *isnull)
 
                                bound_offset = 
partition_list_bsearch(key->partsupfunc,
                                                                                
                          key->partcollation,
-                                                                               
                          partdesc->boundinfo,
+                                                                               
                          boundinfo,
                                                                                
                          values[0], &equal);
                                if (bound_offset >= 0 && equal)
-                                       part_index = 
partdesc->boundinfo->indexes[bound_offset];
+                                       part_index = 
boundinfo->indexes[bound_offset];
                        }
                        break;
 
@@ -1102,7 +1102,7 @@ get_partition_for_tuple(Relation relation, Datum *values, 
bool *isnull)
                                {
                                        bound_offset = 
partition_range_datum_bsearch(key->partsupfunc,
                                                                                
                                                 key->partcollation,
-                                                                               
                                                 partdesc->boundinfo,
+                                                                               
                                                 boundinfo,
                                                                                
                                                 key->partnatts,
                                                                                
                                                 values,
                                                                                
                                                 &equal);
@@ -1113,7 +1113,7 @@ get_partition_for_tuple(Relation relation, Datum *values, 
bool *isnull)
                                         * bound of the partition we're looking 
for, if there
                                         * actually exists one.
                                         */
-                                       part_index = 
partdesc->boundinfo->indexes[bound_offset + 1];
+                                       part_index = 
boundinfo->indexes[bound_offset + 1];
                                }
                        }
                        break;
@@ -1128,7 +1128,7 @@ get_partition_for_tuple(Relation relation, Datum *values, 
bool *isnull)
         * the default partition, if there is one.
         */
        if (part_index < 0)
-               part_index = partdesc->boundinfo->default_index;
+               part_index = boundinfo->default_index;
 
        return part_index;
 }
@@ -1147,7 +1147,7 @@ ExecBuildSlotPartitionKeyDescription(Relation rel,
                                                                         int 
maxfieldlen)
 {
        StringInfoData buf;
-       PartitionKey key = RelationGetPartitionKey(rel);
+       PartitionKey    key = RelationGetPartitionKey(rel);
        int                     partnatts = get_partition_natts(key);
        int                     i;
        Oid                     relid = RelationGetRelid(rel);
@@ -1395,9 +1395,10 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                PartitionPruneInfo *pinfo = (PartitionPruneInfo *) lfirst(lc);
                PartitionPruningData *pprune = &prunedata[i];
                PartitionPruneContext *context = &pprune->context;
-               PartitionDesc partdesc;
                Relation        rel;
                PartitionKey partkey;
+               int                     nparts;
+               PartitionBoundInfo boundinfo;
                int                     partnatts;
 
                pprune->present_parts = bms_copy(pinfo->present_parts);
@@ -1419,8 +1420,10 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                 */
                rel = relation_open(pinfo->reloid, NoLock);
 
+               /* Copy data from relcache into current memory context. */
                partkey = RelationGetPartitionKey(rel);
-               partdesc = RelationGetPartitionDesc(rel);
+               nparts = RelationGetPartitionCount(rel);
+               boundinfo = RelationGetPartitionBounds(rel);
 
                context->strategy = partkey->strategy;
                context->partnatts = partnatts = partkey->partnatts;
@@ -1428,8 +1431,8 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                context->partopcintype = partkey->partopcintype;
                context->partcollation = partkey->partcollation;
                context->partsupfunc = partkey->partsupfunc;
-               context->nparts = pinfo->nparts;
-               context->boundinfo = partition_bounds_copy(partdesc->boundinfo, 
partkey);
+               context->nparts = nparts;
+               context->boundinfo = boundinfo;
                context->planstate = planstate;
                context->safeparams = NULL; /* empty for now */
 
diff --git a/src/backend/optimizer/prep/prepunion.c 
b/src/backend/optimizer/prep/prepunion.c
index 8d86e98adc..8af2e21b27 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -49,6 +49,7 @@
 #include "parser/parse_coerce.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
+#include "utils/partcache.h"
 #include "utils/rel.h"
 #include "utils/selfuncs.h"
 
@@ -1584,7 +1585,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry 
*rte, Index rti)
        oldrelation = heap_open(parentOID, NoLock);
 
        /* Scan the inheritance set and expand it */
-       if (RelationGetPartitionDesc(oldrelation) != NULL)
+       if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
                Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
 
@@ -1675,13 +1676,11 @@ expand_partitioned_rtentry(PlannerInfo *root, 
RangeTblEntry *parentrte,
        RangeTblEntry *childrte;
        Index           childRTindex;
        bool            has_child = false;
-       PartitionDesc partdesc = RelationGetPartitionDesc(parentrel);
+       int                     nparts = RelationGetPartitionCount(parentrel);
+       Oid                *partoids = RelationGetPartitionOids(parentrel);
 
        check_stack_depth();
 
-       /* A partitioned table should always have a partition descriptor. */
-       Assert(partdesc);
-
        Assert(parentrte->inh);
 
        /*
@@ -1700,9 +1699,10 @@ expand_partitioned_rtentry(PlannerInfo *root, 
RangeTblEntry *parentrte,
                                                                        
top_parentrc, parentrel,
                                                                        
appinfos, &childrte, &childRTindex);
 
-       for (i = 0; i < partdesc->nparts; i++)
+       Assert(partoids != NULL || nparts == 0);
+       for (i = 0; i < nparts; i++)
        {
-               Oid                     childOID = partdesc->oids[i];
+               Oid                     childOID = partoids[i];
                Relation        childrel;
 
                /* Open rel; we already have required locks */
diff --git a/src/backend/optimizer/util/plancat.c 
b/src/backend/optimizer/util/plancat.c
index 1ff0ef4866..cfda6f2a34 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -27,7 +27,6 @@
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
-#include "catalog/partition.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_statistic_ext.h"
 #include "foreign/fdwapi.h"
@@ -72,8 +71,9 @@ static List *build_index_tlist(PlannerInfo *root, 
IndexOptInfo *index,
 static List *get_relation_statistics(RelOptInfo *rel, Relation relation);
 static void set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel,
                                                        Relation relation);
-static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel);
-static void set_baserel_partition_key_exprs(Relation relation,
+static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel,
+                                                       PartitionKey partkey);
+static void set_baserel_partition_key_exprs(PartitionKey partkey,
                                                                RelOptInfo 
*rel);
 
 /*
@@ -1871,18 +1871,19 @@ static void
 set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel,
                                                        Relation relation)
 {
-       PartitionDesc partdesc;
-       PartitionKey partkey;
+       PartitionKey partkey = RelationGetPartitionKey(relation);
+       int             nparts = RelationGetPartitionCount(relation);
+       PartitionBoundInfo boundinfo = RelationGetPartitionBounds(relation);
 
        Assert(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+       Assert(partkey != NULL);
+       Assert(boundinfo != NULL || nparts == 0);
 
-       partdesc = RelationGetPartitionDesc(relation);
-       partkey = RelationGetPartitionKey(relation);
-       rel->part_scheme = find_partition_scheme(root, relation);
-       Assert(partdesc != NULL && rel->part_scheme != NULL);
-       rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
-       rel->nparts = partdesc->nparts;
-       set_baserel_partition_key_exprs(relation, rel);
+       rel->part_scheme = find_partition_scheme(root, relation, partkey);
+       Assert(rel->part_scheme != NULL);
+       rel->boundinfo = boundinfo;
+       rel->nparts = nparts;
+       set_baserel_partition_key_exprs(partkey, rel);
        rel->partition_qual = RelationGetPartitionQual(relation);
 }
 
@@ -1892,9 +1893,9 @@ set_relation_partition_info(PlannerInfo *root, RelOptInfo 
*rel,
  * Find or create a PartitionScheme for this Relation.
  */
 static PartitionScheme
-find_partition_scheme(PlannerInfo *root, Relation relation)
+find_partition_scheme(PlannerInfo *root, Relation rel,
+                                         PartitionKey partkey)
 {
-       PartitionKey partkey = RelationGetPartitionKey(relation);
        ListCell   *lc;
        int                     partnatts,
                                i;
@@ -1935,10 +1936,7 @@ find_partition_scheme(PlannerInfo *root, Relation 
relation)
 
                /*
                 * If partopfamily and partopcintype matched, must have the same
-                * partition comparison functions.  Note that we cannot reliably
-                * Assert the equality of function structs themselves for they 
might
-                * be different across PartitionKey's, so just Assert for the 
function
-                * OIDs.
+                * partition comparison functions.
                 */
 #ifdef USE_ASSERT_CHECKING
                for (i = 0; i < partkey->partnatts; i++)
@@ -1951,40 +1949,18 @@ find_partition_scheme(PlannerInfo *root, Relation 
relation)
        }
 
        /*
-        * Did not find matching partition scheme. Create one copying relevant
-        * information from the relcache. We need to copy the contents of the
-        * array since the relcache entry may not survive after we have closed 
the
-        * relation.
+        * Did not find matching partition scheme. Create one usinng the
+        * relevant information copied from the relcache.
         */
        part_scheme = (PartitionScheme) palloc0(sizeof(PartitionSchemeData));
        part_scheme->strategy = partkey->strategy;
        part_scheme->partnatts = partkey->partnatts;
-
-       part_scheme->partopfamily = (Oid *) palloc(sizeof(Oid) * partnatts);
-       memcpy(part_scheme->partopfamily, partkey->partopfamily,
-                  sizeof(Oid) * partnatts);
-
-       part_scheme->partopcintype = (Oid *) palloc(sizeof(Oid) * partnatts);
-       memcpy(part_scheme->partopcintype, partkey->partopcintype,
-                  sizeof(Oid) * partnatts);
-
-       part_scheme->partcollation = (Oid *) palloc(sizeof(Oid) * partnatts);
-       memcpy(part_scheme->partcollation, partkey->partcollation,
-                  sizeof(Oid) * partnatts);
-
-       part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts);
-       memcpy(part_scheme->parttyplen, partkey->parttyplen,
-                  sizeof(int16) * partnatts);
-
-       part_scheme->parttypbyval = (bool *) palloc(sizeof(bool) * partnatts);
-       memcpy(part_scheme->parttypbyval, partkey->parttypbyval,
-                  sizeof(bool) * partnatts);
-
-       part_scheme->partsupfunc = (FmgrInfo *)
-               palloc(sizeof(FmgrInfo) * partnatts);
-       for (i = 0; i < partnatts; i++)
-               fmgr_info_copy(&part_scheme->partsupfunc[i], 
&partkey->partsupfunc[i],
-                                          CurrentMemoryContext);
+       part_scheme->partopfamily = partkey->partopfamily;
+       part_scheme->partopcintype = partkey->partopcintype;
+       part_scheme->partcollation = partkey->partcollation;
+       part_scheme->parttyplen = partkey->parttyplen;
+       part_scheme->parttypbyval = partkey->parttypbyval;
+       part_scheme->partsupfunc = partkey->partsupfunc;
 
        /* Add the partitioning scheme to PlannerInfo. */
        root->part_schemes = lappend(root->part_schemes, part_scheme);
@@ -2000,10 +1976,9 @@ find_partition_scheme(PlannerInfo *root, Relation 
relation)
  * nodes.  All Var nodes are restamped with the relid of given relation.
  */
 static void
-set_baserel_partition_key_exprs(Relation relation,
+set_baserel_partition_key_exprs(PartitionKey partkey,
                                                                RelOptInfo *rel)
 {
-       PartitionKey partkey = RelationGetPartitionKey(relation);
        int                     partnatts;
        int                     cnt;
        List      **partexprs;
diff --git a/src/backend/parser/parse_utilcmd.c 
b/src/backend/parser/parse_utilcmd.c
index c6f3628def..7b505ad8aa 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3557,7 +3557,7 @@ transformPartitionCmd(CreateStmtContext *cxt, 
PartitionCmd *cmd)
        {
                case RELKIND_PARTITIONED_TABLE:
                        /* transform the partition bound, if any */
-                       Assert(RelationGetPartitionKey(parentRel) != NULL);
+                       Assert(parentRel->rd_partkey != NULL);
                        if (cmd->bound != NULL)
                                cxt->partbound = 
transformPartitionBound(cxt->pstate, parentRel,
                                                                                
                                 cmd->bound);
@@ -3598,7 +3598,7 @@ transformPartitionBound(ParseState *pstate, Relation 
parent,
                                                PartitionBoundSpec *spec)
 {
        PartitionBoundSpec *result_spec;
-       PartitionKey key = RelationGetPartitionKey(parent);
+       PartitionKey    key = RelationGetPartitionKey(parent);
        char            strategy = get_partition_strategy(key);
        int                     partnatts = get_partition_natts(key);
        List       *partexprs = get_partition_exprs(key);
diff --git a/src/backend/partitioning/partbounds.c 
b/src/backend/partitioning/partbounds.c
index 229ce3ff5c..0d2064d617 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -307,9 +307,10 @@ void
 check_new_partition_bound(char *relname, Relation parent,
                                                  PartitionBoundSpec *spec)
 {
-       PartitionKey key = RelationGetPartitionKey(parent);
-       PartitionDesc partdesc = RelationGetPartitionDesc(parent);
-       PartitionBoundInfo boundinfo = partdesc->boundinfo;
+       PartitionKey    key = RelationGetPartitionKey(parent);
+       int                             nparts = 
RelationGetPartitionCount(parent);
+       Oid                        *partoids = RelationGetPartitionOids(parent);
+       PartitionBoundInfo boundinfo = RelationGetPartitionBounds(parent);
        ParseState *pstate = make_parsestate(NULL);
        int                     with = -1;
        bool            overlap = false;
@@ -329,7 +330,7 @@ check_new_partition_bound(char *relname, Relation parent,
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                 errmsg("partition \"%s\" conflicts with 
existing default partition \"%s\"",
-                                               relname, 
get_rel_name(partdesc->oids[boundinfo->default_index])),
+                                               relname, 
get_rel_name(partoids[boundinfo->default_index])),
                                 parser_errposition(pstate, spec->location)));
        }
 
@@ -340,7 +341,7 @@ check_new_partition_bound(char *relname, Relation parent,
                                Assert(spec->strategy == 
PARTITION_STRATEGY_HASH);
                                Assert(spec->remainder >= 0 && spec->remainder 
< spec->modulus);
 
-                               if (partdesc->nparts > 0)
+                               if (nparts > 0)
                                {
                                        Datum     **datums = boundinfo->datums;
                                        int                     ndatums = 
boundinfo->ndatums;
@@ -421,7 +422,7 @@ check_new_partition_bound(char *relname, Relation parent,
                        {
                                Assert(spec->strategy == 
PARTITION_STRATEGY_LIST);
 
-                               if (partdesc->nparts > 0)
+                               if (nparts > 0)
                                {
                                        ListCell   *cell;
 
@@ -491,7 +492,7 @@ check_new_partition_bound(char *relname, Relation parent,
                                                         
parser_errposition(pstate, spec->location)));
                                }
 
-                               if (partdesc->nparts > 0)
+                               if (nparts > 0)
                                {
                                        int                     offset;
                                        bool            equal;
@@ -583,7 +584,7 @@ check_new_partition_bound(char *relname, Relation parent,
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                 errmsg("partition \"%s\" would overlap 
partition \"%s\"",
-                                               relname, 
get_rel_name(partdesc->oids[with])),
+                                               relname, 
get_rel_name(partoids[with])),
                                 parser_errposition(pstate, spec->location)));
        }
 }
@@ -1431,8 +1432,7 @@ get_qual_for_list(Relation parent, PartitionBoundSpec 
*spec)
        {
                int                     i;
                int                     ndatums = 0;
-               PartitionDesc pdesc = RelationGetPartitionDesc(parent);
-               PartitionBoundInfo boundinfo = pdesc->boundinfo;
+               PartitionBoundInfo boundinfo = 
RelationGetPartitionBounds(parent);
 
                if (boundinfo)
                {
@@ -1631,11 +1631,11 @@ get_qual_for_range(Relation parent, PartitionBoundSpec 
*spec,
        if (spec->is_default)
        {
                List       *or_expr_args = NIL;
-               PartitionDesc pdesc = RelationGetPartitionDesc(parent);
-               Oid                *inhoids = pdesc->oids;
-               int                     nparts = pdesc->nparts,
+               Oid                *inhoids = RelationGetPartitionOids(parent);
+               int                     nparts = 
RelationGetPartitionCount(parent),
                                        i;
 
+               Assert(inhoids != NULL || nparts == 0);
                for (i = 0; i < nparts; i++)
                {
                        Oid                     inhrelid = inhoids[i];
@@ -2156,11 +2156,17 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
                parent = try_relation_open(parentId, AccessShareLock);
                if (parent == NULL)
                        PG_RETURN_NULL();
-               key = RelationGetPartitionKey(parent);
 
                /* Reject parent table that is not hash-partitioned. */
-               if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
-                       key->strategy != PARTITION_STRATEGY_HASH)
+               if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+                       ereport(ERROR,
+                                       
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("\"%s\" is not a hash 
partitioned table",
+                                                       
get_rel_name(parentId))));
+               key = RelationGetPartitionKey(parent);
+               Assert(key != NULL);
+
+               if (key->strategy != PARTITION_STRATEGY_HASH)
                        ereport(ERROR,
                                        
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                         errmsg("\"%s\" is not a hash 
partitioned table",
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index 7666c6c412..f047e6e827 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -54,7 +54,6 @@
 #include "optimizer/predtest.h"
 #include "optimizer/prep.h"
 #include "partitioning/partprune.h"
-#include "partitioning/partbounds.h"
 #include "rewrite/rewriteManip.h"
 #include "utils/lsyscache.h"
 
@@ -1962,8 +1961,8 @@ 
get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
  *
  * 'nvalues', the number of Datums in the 'values' array.
  *
- * 'partsupfunc' contains partition hashing functions that can produce correct
- * hash for the type of the values contained in 'values'.
+ * 'partsupfunc' contains partition hashing functions that can produce
+ * correct hash for the type of the values contained in 'values'.
  *
  * 'nullkeys' is the set of partition keys that are null.
  */
@@ -2000,7 +1999,8 @@ get_matching_hash_bounds(PartitionPruneContext *context,
                        isnull[i] = bms_is_member(i, nullkeys);
 
                greatest_modulus = 
get_hash_partition_greatest_modulus(boundinfo);
-               rowHash = compute_hash_value(partnatts, partsupfunc, values, 
isnull);
+               rowHash = compute_hash_value(partnatts, partsupfunc, values,
+                                                                        
isnull);
 
                if (partindices[rowHash % greatest_modulus] >= 0)
                        result->bound_offsets =
@@ -2029,8 +2029,8 @@ get_matching_hash_bounds(PartitionPruneContext *context,
  *
  * 'nvalues', if non-zero, should be exactly 1, because of list partitioning.
  *
- * 'partsupfunc' contains the list partitioning comparison function to be used
- * to perform partition_list_bsearch
+ * 'partsupfunc' contains the list partitioning comparison function to be
+ * used to perform partition_list_bsearch
  *
  * 'nullkeys' is the set of partition keys that are null.
  */
@@ -2102,8 +2102,8 @@ get_matching_list_bounds(PartitionPruneContext *context,
                result->bound_offsets = bms_add_range(NULL, 0,
                                                                                
          boundinfo->ndatums - 1);
 
-               off = partition_list_bsearch(partsupfunc, partcollation, 
boundinfo,
-                                                                        value, 
&is_equal);
+               off = partition_list_bsearch(partsupfunc, partcollation,
+                                                                        
boundinfo, value, &is_equal);
                if (off >= 0 && is_equal)
                {
 
@@ -2231,9 +2231,9 @@ get_matching_list_bounds(PartitionPruneContext *context,
  *
  * 'nvalues', number of Datums in 'values' array. Must be <= 
context->partnatts.
  *
- * 'partsupfunc' contains the range partitioning comparison functions to be
- * used to perform partition_range_datum_bsearch or partition_rbound_datum_cmp
- * using.
+ * 'partsupfunc' contains the range partitioning comparison functions to
+ * be used to perform partition_range_datum_bsearch or
+ * partition_rbound_datum_cmp using.
  *
  * 'nullkeys' is the set of partition keys that are null.
  */
@@ -2797,7 +2797,8 @@ perform_pruning_base_step(PartitionPruneContext *context,
                                cmpfn = lfirst_oid(lc2);
                                Assert(OidIsValid(cmpfn));
                                if (cmpfn != context->partsupfunc[keyno].fn_oid)
-                                       fmgr_info(cmpfn, &partsupfunc[keyno]);
+                                       fmgr_info_cxt(cmpfn, 
&partsupfunc[keyno],
+                                                                 
CurrentMemoryContext);
                                else
                                        fmgr_info_copy(&partsupfunc[keyno],
                                                                   
&context->partsupfunc[keyno],
diff --git a/src/backend/utils/cache/partcache.c 
b/src/backend/utils/cache/partcache.c
index e2f677a46a..0c8bbec12d 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -36,20 +36,19 @@
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
-
-static List *generate_partition_qual(Relation rel);
 static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
                                                           void *arg);
 static int32 qsort_partition_rbound_cmp(const void *a, const void *b,
                                                   void *arg);
-
+static PartitionKey partition_key_copy(PartitionKey fromkey);
+static List *generate_partition_qual(Relation rel);
 
 /*
  * RelationBuildPartitionKey
  *             Build and attach to relcache partition key data of relation
  *
- * Partitioning key data is a complex structure; to avoid complicated logic to
+ * Partition key data is of complex structure; to avoid complicated logic to
  * free individual elements whenever the relcache entry is flushed, we give it
  * its own memory context, child of CacheMemoryContext, which can easily be
  * deleted on its own.  To avoid leaking memory in that context in case of an
@@ -165,6 +164,7 @@ RelationBuildPartitionKey(Relation relation)
        key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
        key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char));
        key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid));
+
        MemoryContextSwitchTo(oldcxt);
 
        /* determine support function number to search for */
@@ -206,6 +206,11 @@ RelationBuildPartitionKey(Relation relation)
                                                        procnum,
                                                        
format_type_be(opclassform->opcintype))));
 
+               /*
+                * Actually, we never use one of these FmgrInfo's without 
copying
+                * first to the caller's memory context, so setting the memory 
context
+                * here may seem pointless.
+                */
                fmgr_info_cxt(funcid, &key->partsupfunc[i], partkeycxt);
 
                /* Collation */
@@ -791,6 +796,73 @@ RelationBuildPartitionDesc(Relation rel)
 }
 
 /*
+ * Functions to get a copy of partitioning infomation cached in RelationData.
+ */
+
+PartitionKey
+RelationGetPartitionKey(Relation relation)
+{
+       PartitionKey partkey = relation->rd_partkey;
+
+       return partkey ? partition_key_copy(partkey) : NULL;
+}
+
+int
+RelationGetPartitionCount(Relation relation)
+{
+       PartitionDesc partdesc = relation->rd_partdesc;
+
+       return partdesc->nparts;
+}
+
+Oid *
+RelationGetPartitionOids(Relation relation)
+{
+       PartitionDesc partdesc = relation->rd_partdesc;
+       Oid *result = NULL;
+
+       Assert(partdesc != NULL);
+       if (partdesc->nparts > 0)
+       {
+               result = palloc(partdesc->nparts * sizeof(Oid));
+               memcpy(result, partdesc->oids, partdesc->nparts * sizeof(Oid));
+       }
+
+       return result;
+}
+
+PartitionBoundInfo
+RelationGetPartitionBounds(Relation relation)
+{
+       PartitionDesc partdesc = relation->rd_partdesc;
+
+       return partdesc->boundinfo
+                               ? partition_bounds_copy(partdesc->boundinfo,
+                                                                               
relation->rd_partkey)
+                               : NULL;
+}
+
+/*
+ * RelationGetDefaultPartitionOid
+ *
+ * Return the OID of the default partition, if one exists; else InvalidOid.
+ */
+Oid
+RelationGetDefaultPartitionOid(Relation rel)
+{
+       PartitionBoundInfo boundinfo;
+
+       /* Shouldn't be here otherwise! */
+       Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+       boundinfo = rel->rd_partdesc->boundinfo;
+
+       if (boundinfo && partition_bound_has_default(boundinfo))
+               return rel->rd_partdesc->oids[boundinfo->default_index];
+
+       return InvalidOid;
+}
+
+/*
  * RelationGetPartitionQual
  *
  * Returns a list of partition quals
@@ -839,6 +911,66 @@ get_partition_qual_relid(Oid relid)
 }
 
 /*
+ * partition_key_copy
+ *
+ * The copy is allocated in the current memory context.
+ */
+static PartitionKey
+partition_key_copy(PartitionKey fromkey)
+{
+       PartitionKey newkey;
+       int                     n,
+                               i;
+
+       Assert(fromkey != NULL);
+
+       newkey = (PartitionKey) palloc(sizeof(PartitionKeyData));
+
+       newkey->strategy = fromkey->strategy;
+       newkey->partnatts = n = fromkey->partnatts;
+
+       newkey->partattrs = (AttrNumber *) palloc(n * sizeof(AttrNumber));
+       memcpy(newkey->partattrs, fromkey->partattrs, n * sizeof(AttrNumber));
+
+       newkey->partexprs = copyObject(fromkey->partexprs);
+
+       newkey->partopfamily = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->partopfamily, fromkey->partopfamily, n * sizeof(Oid));
+
+       newkey->partopcintype = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->partopcintype, fromkey->partopcintype, n * sizeof(Oid));
+
+       newkey->partsupfunc = (FmgrInfo *) palloc(n * sizeof(FmgrInfo));
+       for (i = 0; i < fromkey->partnatts; i++)
+               fmgr_info_copy(&newkey->partsupfunc[i],
+                                          &fromkey->partsupfunc[i],
+                                          CurrentMemoryContext);
+
+       newkey->partcollation = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->partcollation, fromkey->partcollation, n * sizeof(Oid));
+
+       newkey->parttypid = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->parttypid, fromkey->parttypid, n * sizeof(Oid));
+
+       newkey->parttypmod = (int32 *) palloc(n * sizeof(int32));
+       memcpy(newkey->parttypmod, fromkey->parttypmod, n * sizeof(int32));
+
+       newkey->parttyplen = (int16 *) palloc(n * sizeof(int16));
+       memcpy(newkey->parttyplen, fromkey->parttyplen, n * sizeof(int16));
+
+       newkey->parttypbyval = (bool *) palloc(n * sizeof(bool));
+       memcpy(newkey->parttypbyval, fromkey->parttypbyval, n * sizeof(bool));
+
+       newkey->parttypalign = (char *) palloc(n * sizeof(bool));
+       memcpy(newkey->parttypalign, fromkey->parttypalign, n * sizeof(char));
+
+       newkey->parttypcoll = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->parttypcoll, fromkey->parttypcoll, n * sizeof(Oid));
+
+       return newkey;
+}
+
+/*
  * generate_partition_qual
  *
  * Generate partition predicate from rel's partition bound expression. The
diff --git a/src/backend/utils/cache/relcache.c 
b/src/backend/utils/cache/relcache.c
index 22ff36714c..86bff9c53b 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -43,7 +43,6 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
-#include "catalog/partition.h"
 #include "catalog/pg_am.h"
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
@@ -287,9 +286,6 @@ static OpClassCacheEnt *LookupOpclassInfo(Oid 
operatorClassOid,
                                  StrategyNumber numSupport);
 static void RelationCacheInitFileRemoveInDir(const char *tblspcpath);
 static void unlink_initfile(const char *initfilename);
-static bool equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
-                                       PartitionDesc partdesc2);
-
 
 /*
  *             ScanPgRelation
@@ -1002,60 +998,6 @@ equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc 
*rsdesc2)
 }
 
 /*
- * equalPartitionDescs
- *             Compare two partition descriptors for logical equality
- */
-static bool
-equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
-                                       PartitionDesc partdesc2)
-{
-       int                     i;
-
-       if (partdesc1 != NULL)
-       {
-               if (partdesc2 == NULL)
-                       return false;
-               if (partdesc1->nparts != partdesc2->nparts)
-                       return false;
-
-               Assert(key != NULL || partdesc1->nparts == 0);
-
-               /*
-                * Same oids? If the partitioning structure did not change, 
that is,
-                * no partitions were added or removed to the relation, the 
oids array
-                * should still match element-by-element.
-                */
-               for (i = 0; i < partdesc1->nparts; i++)
-               {
-                       if (partdesc1->oids[i] != partdesc2->oids[i])
-                               return false;
-               }
-
-               /*
-                * Now compare partition bound collections.  The logic to 
iterate over
-                * the collections is private to partition.c.
-                */
-               if (partdesc1->boundinfo != NULL)
-               {
-                       if (partdesc2->boundinfo == NULL)
-                               return false;
-
-                       if (!partition_bounds_equal(key->partnatts, 
key->parttyplen,
-                                                                               
key->parttypbyval,
-                                                                               
partdesc1->boundinfo,
-                                                                               
partdesc2->boundinfo))
-                               return false;
-               }
-               else if (partdesc2->boundinfo != NULL)
-                       return false;
-       }
-       else if (partdesc2 != NULL)
-               return false;
-
-       return true;
-}
-
-/*
  *             RelationBuildDesc
  *
  *             Build a relation descriptor.  The caller must hold at least
@@ -1183,7 +1125,10 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
        relation->rd_fkeylist = NIL;
        relation->rd_fkeyvalid = false;
 
-       /* if a partitioned table, initialize key and partition descriptor info 
*/
+       /*
+        * If we need to initialize partitioning info, do that in a dedicated
+        * context that's attached to the cache context.
+        */
        if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
                RelationBuildPartitionKey(relation);
@@ -1193,8 +1138,8 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
        {
                relation->rd_partkeycxt = NULL;
                relation->rd_partkey = NULL;
-               relation->rd_partdesc = NULL;
                relation->rd_pdcxt = NULL;
+               relation->rd_partdesc = NULL;
        }
 
        /*
@@ -2369,8 +2314,6 @@ RelationClearRelation(Relation relation, bool rebuild)
                bool            keep_tupdesc;
                bool            keep_rules;
                bool            keep_policies;
-               bool            keep_partkey;
-               bool            keep_partdesc;
 
                /* Build temporary entry, but don't link it into hashtable */
                newrel = RelationBuildDesc(save_relid, false);
@@ -2401,10 +2344,6 @@ RelationClearRelation(Relation relation, bool rebuild)
                keep_tupdesc = equalTupleDescs(relation->rd_att, 
newrel->rd_att);
                keep_rules = equalRuleLocks(relation->rd_rules, 
newrel->rd_rules);
                keep_policies = equalRSDesc(relation->rd_rsdesc, 
newrel->rd_rsdesc);
-               keep_partkey = (relation->rd_partkey != NULL);
-               keep_partdesc = equalPartitionDescs(relation->rd_partkey,
-                                                                               
        relation->rd_partdesc,
-                                                                               
        newrel->rd_partdesc);
 
                /*
                 * Perform swapping of the relcache entry contents.  Within this
@@ -2459,18 +2398,6 @@ RelationClearRelation(Relation relation, bool rebuild)
                SWAPFIELD(Oid, rd_toastoid);
                /* pgstat_info must be preserved */
                SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
-               /* partition key must be preserved, if we have one */
-               if (keep_partkey)
-               {
-                       SWAPFIELD(PartitionKey, rd_partkey);
-                       SWAPFIELD(MemoryContext, rd_partkeycxt);
-               }
-               /* preserve old partdesc if no logical change */
-               if (keep_partdesc)
-               {
-                       SWAPFIELD(PartitionDesc, rd_partdesc);
-                       SWAPFIELD(MemoryContext, rd_pdcxt);
-               }
 
 #undef SWAPFIELD
 
@@ -3708,19 +3635,11 @@ RelationCacheInitializePhase3(void)
                /*
                 * Reload the partition key and descriptor for a partitioned 
table.
                 */
-               if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-                       relation->rd_partkey == NULL)
+               if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                {
                        RelationBuildPartitionKey(relation);
-                       Assert(relation->rd_partkey != NULL);
-
-                       restart = true;
-               }
-
-               if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-                       relation->rd_partdesc == NULL)
-               {
                        RelationBuildPartitionDesc(relation);
+                       Assert(relation->rd_partkey != NULL);
                        Assert(relation->rd_partdesc != NULL);
 
                        restart = true;
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 1f49e5d3a9..2cda9c9cad 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -37,8 +37,6 @@ extern List *map_partition_varattnos(List *expr, int 
fromrel_varno,
                                                bool *found_whole_row);
 extern bool has_partition_attrs(Relation rel, Bitmapset *attnums,
                                        bool *used_in_expr);
-
-extern Oid     get_default_oid_from_partdesc(PartitionDesc partdesc);
 extern Oid     get_default_partition_oid(Oid parentId);
 extern void update_default_partition_oid(Oid parentId, Oid defaultPartId);
 extern List *get_proposed_default_constraint(List *new_part_constaints);
diff --git a/src/include/executor/execPartition.h 
b/src/include/executor/execPartition.h
index e81bdc4a0a..b5dc53bfcb 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -25,14 +25,15 @@
  *     reldesc         Relation descriptor of the table
  *     key                     Partition key information of the table
  *     keystate        Execution state required for expressions in the 
partition key
- *     partdesc        Partition descriptor of the table
+ *     nparts          Number of partitions of the table
+ *     boundinfo       PartitionBoundInfo of the table
  *     tupslot         A standalone TupleTableSlot initialized with this 
table's tuple
  *                             descriptor
  *     tupmap          TupleConversionMap to convert from the parent's rowtype 
to
  *                             this table's rowtype (when extracting the 
partition key of a
  *                             tuple just before routing it through this table)
- *     indexes         Array with partdesc->nparts members (for details on what
- *                             individual members represent, see how they are 
set in
+ *     indexes         Array with nparts members (for details on what 
individual
+ *                             members represent, see how they are set in
  *                             get_partition_dispatch_recurse())
  *-----------------------
  */
@@ -41,7 +42,8 @@ typedef struct PartitionDispatchData
        Relation        reldesc;
        PartitionKey key;
        List       *keystate;           /* list of ExprState */
-       PartitionDesc partdesc;
+       int                     nparts;
+       PartitionBoundInfo boundinfo;
        TupleTableSlot *tupslot;
        TupleConversionMap *tupmap;
        int                *indexes;
diff --git a/src/include/partitioning/partbounds.h 
b/src/include/partitioning/partbounds.h
index 71c04aa446..9cdfc04018 100644
--- a/src/include/partitioning/partbounds.h
+++ b/src/include/partitioning/partbounds.h
@@ -16,7 +16,7 @@
 #include "nodes/pg_list.h"
 #include "partitioning/partdefs.h"
 #include "utils/relcache.h"
-
+#include "utils/partcache.h"
 
 /*
  * PartitionBoundInfoData encapsulates a set of partition bounds. It is
diff --git a/src/include/partitioning/partprune.h 
b/src/include/partitioning/partprune.h
index a5568abce6..114a9594be 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -14,7 +14,7 @@
 #ifndef PARTPRUNE_H
 #define PARTPRUNE_H
 
-#include "nodes/execnodes.h"
+#include "partitioning/partbounds.h"
 #include "nodes/relation.h"
 
 
diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h
index c1d029fdb3..b037bb00d5 100644
--- a/src/include/utils/partcache.h
+++ b/src/include/utils/partcache.h
@@ -48,6 +48,11 @@ typedef struct PartitionKeyData
 
 extern void RelationBuildPartitionKey(Relation relation);
 extern void RelationBuildPartitionDesc(Relation rel);
+extern PartitionKey RelationGetPartitionKey(Relation relation);
+extern int RelationGetPartitionCount(Relation relation);
+extern Oid *RelationGetPartitionOids(Relation relation);
+extern PartitionBoundInfo RelationGetPartitionBounds(Relation relation);
+extern Oid     RelationGetDefaultPartitionOid(Relation rel);
 extern List *RelationGetPartitionQual(Relation rel);
 extern Expr *get_partition_qual_relid(Oid relid);
 
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 1d0461d295..f5b84ed60a 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -582,18 +582,6 @@ typedef struct ViewOptions
         RelationNeedsWAL(relation) && \
         !IsCatalogRelation(relation))
 
-/*
- * RelationGetPartitionKey
- *             Returns the PartitionKey of a relation
- */
-#define RelationGetPartitionKey(relation) ((relation)->rd_partkey)
-
-/*
- * RelationGetPartitionDesc
- *             Returns partition descriptor for a relation.
- */
-#define RelationGetPartitionDesc(relation) ((relation)->rd_partdesc)
-
 /* routines in utils/cache/relcache.c */
 extern void RelationIncrementReferenceCount(Relation rel);
 extern void RelationDecrementReferenceCount(Relation rel);
-- 
2.11.0

From cc5103479506aba20ed1c115755fe329343fbcf2 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 16 Apr 2018 16:10:16 +0900
Subject: [PATCH v1 2/3] Cache all partitioning info under one memory context

Instead of having one for PartitionKey and another for PartitionDesc,
use just one.  Also, instead of allocating partition constraint
expression tree directly under CacheMemoryContext, do it under the
aforementioned context.
---
 src/backend/utils/cache/partcache.c | 33 +++++++-----------------------
 src/backend/utils/cache/relcache.c  | 40 +++++++++++++++++++++++++------------
 src/include/utils/rel.h             |  4 ++--
 3 files changed, 36 insertions(+), 41 deletions(-)

diff --git a/src/backend/utils/cache/partcache.c 
b/src/backend/utils/cache/partcache.c
index 0c8bbec12d..e234320e30 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -72,8 +72,7 @@ RelationBuildPartitionKey(Relation relation)
        oidvector  *collation;
        ListCell   *partexprs_item;
        Datum           datum;
-       MemoryContext partkeycxt,
-                               oldcxt;
+       MemoryContext oldcxt;
        int16           procnum;
 
        tuple = SearchSysCache1(PARTRELID,
@@ -86,13 +85,7 @@ RelationBuildPartitionKey(Relation relation)
        if (!HeapTupleIsValid(tuple))
                return;
 
-       partkeycxt = AllocSetContextCreate(CurTransactionContext,
-                                                                          
"partition key",
-                                                                          
ALLOCSET_SMALL_SIZES);
-       MemoryContextCopyAndSetIdentifier(partkeycxt,
-                                                                         
RelationGetRelationName(relation));
-
-       key = (PartitionKey) MemoryContextAllocZero(partkeycxt,
+       key = (PartitionKey) MemoryContextAllocZero(relation->rd_partcxt,
                                                                                
                sizeof(PartitionKeyData));
 
        /* Fixed-length attributes */
@@ -144,12 +137,12 @@ RelationBuildPartitionKey(Relation relation)
                expr = eval_const_expressions(NULL, expr);
                fix_opfuncids(expr);
 
-               oldcxt = MemoryContextSwitchTo(partkeycxt);
+               oldcxt = MemoryContextSwitchTo(relation->rd_partcxt);
                key->partexprs = (List *) copyObject(expr);
                MemoryContextSwitchTo(oldcxt);
        }
 
-       oldcxt = MemoryContextSwitchTo(partkeycxt);
+       oldcxt = MemoryContextSwitchTo(relation->rd_partcxt);
        key->partattrs = (AttrNumber *) palloc0(key->partnatts * 
sizeof(AttrNumber));
        key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
        key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid));
@@ -211,7 +204,7 @@ RelationBuildPartitionKey(Relation relation)
                 * first to the caller's memory context, so setting the memory 
context
                 * here may seem pointless.
                 */
-               fmgr_info_cxt(funcid, &key->partsupfunc[i], partkeycxt);
+               fmgr_info_cxt(funcid, &key->partsupfunc[i], 
relation->rd_partcxt);
 
                /* Collation */
                key->partcollation[i] = collation->values[i];
@@ -245,13 +238,6 @@ RelationBuildPartitionKey(Relation relation)
        }
 
        ReleaseSysCache(tuple);
-
-       /*
-        * Success --- reparent our context and make the relcache point to the
-        * newly constructed key
-        */
-       MemoryContextSetParent(partkeycxt, CacheMemoryContext);
-       relation->rd_partkeycxt = partkeycxt;
        relation->rd_partkey = key;
 }
 
@@ -583,12 +569,7 @@ RelationBuildPartitionDesc(Relation rel)
        }
 
        /* Now build the actual relcache partition descriptor */
-       rel->rd_pdcxt = AllocSetContextCreate(CacheMemoryContext,
-                                                                               
  "partition descriptor",
-                                                                               
  ALLOCSET_DEFAULT_SIZES);
-       MemoryContextCopyAndSetIdentifier(rel->rd_pdcxt, 
RelationGetRelationName(rel));
-
-       oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
+       oldcxt = MemoryContextSwitchTo(rel->rd_partcxt);
 
        result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
        result->nparts = nparts;
@@ -1043,7 +1024,7 @@ generate_partition_qual(Relation rel)
                elog(ERROR, "unexpected whole-row reference found in partition 
key");
 
        /* Save a copy in the relcache */
-       oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+       oldcxt = MemoryContextSwitchTo(rel->rd_partcxt);
        rel->rd_partcheck = copyObject(result);
        MemoryContextSwitchTo(oldcxt);
 
diff --git a/src/backend/utils/cache/relcache.c 
b/src/backend/utils/cache/relcache.c
index 86bff9c53b..16081bc932 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1129,17 +1129,36 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
         * If we need to initialize partitioning info, do that in a dedicated
         * context that's attached to the cache context.
         */
-       if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+       if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
+               relation->rd_rel->relispartition)
        {
-               RelationBuildPartitionKey(relation);
-               RelationBuildPartitionDesc(relation);
+               relation->rd_partcxt = AllocSetContextCreate(CacheMemoryContext,
+                                                                               
                         "partition info",
+                                                                               
                         ALLOCSET_SMALL_SIZES);
+               MemoryContextCopyAndSetIdentifier(relation->rd_partcxt,
+                                                                               
  RelationGetRelationName(relation));
+
+               /*
+                * For a partitioned table, initialize partition key and 
partition
+                * descriptor.
+                */
+               if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+               {
+                       RelationBuildPartitionKey(relation);
+                       RelationBuildPartitionDesc(relation);
+               }
+
+               /*
+                * Partition constraint of a partition itself is built only when
+                * needed.  See RelationGetPartitionQual().
+                */
        }
        else
        {
-               relation->rd_partkeycxt = NULL;
+               relation->rd_partcxt = NULL;
                relation->rd_partkey = NULL;
-               relation->rd_pdcxt = NULL;
                relation->rd_partdesc = NULL;
+               relation->rd_partcheck = NIL;
        }
 
        /*
@@ -2142,12 +2161,8 @@ RelationDestroyRelation(Relation relation, bool 
remember_tupdesc)
                MemoryContextDelete(relation->rd_rulescxt);
        if (relation->rd_rsdesc)
                MemoryContextDelete(relation->rd_rsdesc->rscxt);
-       if (relation->rd_partkeycxt)
-               MemoryContextDelete(relation->rd_partkeycxt);
-       if (relation->rd_pdcxt)
-               MemoryContextDelete(relation->rd_pdcxt);
-       if (relation->rd_partcheck)
-               pfree(relation->rd_partcheck);
+       if (relation->rd_partcxt)
+               MemoryContextDelete(relation->rd_partcxt);
        if (relation->rd_fdwroutine)
                pfree(relation->rd_fdwroutine);
        pfree(relation);
@@ -5492,9 +5507,8 @@ load_relcache_init_file(bool shared)
                rel->rd_rulescxt = NULL;
                rel->trigdesc = NULL;
                rel->rd_rsdesc = NULL;
-               rel->rd_partkeycxt = NULL;
+               rel->rd_partcxt = NULL;
                rel->rd_partkey = NULL;
-               rel->rd_pdcxt = NULL;
                rel->rd_partdesc = NULL;
                rel->rd_partcheck = NIL;
                rel->rd_indexprs = NIL;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index f5b84ed60a..378401abca 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -95,9 +95,9 @@ typedef struct RelationData
        List       *rd_fkeylist;        /* list of ForeignKeyCacheInfo (see 
below) */
        bool            rd_fkeyvalid;   /* true if list has been computed */
 
-       MemoryContext rd_partkeycxt;    /* private memory cxt for the below */
+       MemoryContext rd_partcxt;       /* private memory cxt for the values 
contained
+                                                                * in the 
fields related to partitioning */
        struct PartitionKeyData *rd_partkey;    /* partition key, or NULL */
-       MemoryContext rd_pdcxt;         /* private context for partdesc */
        struct PartitionDescData *rd_partdesc;  /* partitions, or NULL */
        List       *rd_partcheck;       /* partition CHECK quals */
 
-- 
2.11.0

From f8fc3f6b76c48c4834117c91a13223a663210e87 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 16 Apr 2018 11:54:44 +0900
Subject: [PATCH v1 3/3] Cache partsupfunc separately from PartitionKey

---
 src/backend/executor/execPartition.c  | 24 +++++++--
 src/backend/optimizer/util/plancat.c  |  9 +++-
 src/backend/partitioning/partbounds.c | 40 ++++++++++++---
 src/backend/partitioning/partprune.c  |  8 ++-
 src/backend/utils/cache/partcache.c   | 97 +++++++++++++++++++++++++++--------
 src/backend/utils/cache/relcache.c    |  2 +
 src/include/executor/execPartition.h  |  2 +
 src/include/partitioning/partprune.h  |  2 +-
 src/include/utils/partcache.h         |  4 +-
 src/include/utils/rel.h               |  2 +
 10 files changed, 150 insertions(+), 40 deletions(-)

diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index f04bd276ee..87ec10f6f2 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -894,6 +894,13 @@ get_partition_dispatch_recurse(Relation rel, Relation 
parent,
        pd->reldesc = rel;
        pd->key = partkey;
        pd->keystate = NIL;
+       /* Get partsupfunc FmgrInfo's. */
+       for (i = 0; i < partkey->partnatts; i++)
+       {
+               fmgr_info_copy(&pd->partsupfunc[i],
+                                          partition_getprocinfo(rel, partkey, 
i),
+                                          CurrentMemoryContext);
+       }
        pd->nparts = nparts;
        pd->boundinfo = boundinfo;
        if (parent != NULL)
@@ -1044,6 +1051,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum 
*values, bool *isnull)
        int                     bound_offset;
        int                     part_index = -1;
        PartitionKey key = pd->key;
+       FmgrInfo   *partsupfunc = pd->partsupfunc;
        PartitionBoundInfo boundinfo = pd->boundinfo;
 
        /* Route as appropriate based on partitioning strategy. */
@@ -1053,7 +1061,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum 
*values, bool *isnull)
                        {
                                int                     greatest_modulus = 
get_hash_partition_greatest_modulus(boundinfo);
                                uint64          rowHash = 
compute_hash_value(key->partnatts,
-                                                                               
                                 key->partsupfunc,
+                                                                               
                                 partsupfunc,
                                                                                
                                 values, isnull);
 
                                part_index = boundinfo->indexes[rowHash % 
greatest_modulus];
@@ -1070,7 +1078,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum 
*values, bool *isnull)
                        {
                                bool            equal = false;
 
-                               bound_offset = 
partition_list_bsearch(key->partsupfunc,
+                               bound_offset = 
partition_list_bsearch(partsupfunc,
                                                                                
                          key->partcollation,
                                                                                
                          boundinfo,
                                                                                
                          values[0], &equal);
@@ -1100,7 +1108,7 @@ get_partition_for_tuple(PartitionDispatch pd, Datum 
*values, bool *isnull)
 
                                if (!range_partkey_has_null)
                                {
-                                       bound_offset = 
partition_range_datum_bsearch(key->partsupfunc,
+                                       bound_offset = 
partition_range_datum_bsearch(partsupfunc,
                                                                                
                                                 key->partcollation,
                                                                                
                                                 boundinfo,
                                                                                
                                                 key->partnatts,
@@ -1400,6 +1408,7 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                int                     nparts;
                PartitionBoundInfo boundinfo;
                int                     partnatts;
+               int                     j;
 
                pprune->present_parts = bms_copy(pinfo->present_parts);
                pprune->subnode_map = palloc(sizeof(int) * pinfo->nparts);
@@ -1420,7 +1429,6 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                 */
                rel = relation_open(pinfo->reloid, NoLock);
 
-               /* Copy data from relcache into current memory context. */
                partkey = RelationGetPartitionKey(rel);
                nparts = RelationGetPartitionCount(rel);
                boundinfo = RelationGetPartitionBounds(rel);
@@ -1430,7 +1438,13 @@ ExecSetupPartitionPruneState(PlanState *planstate, List 
*partitionpruneinfo)
                context->partopfamily = partkey->partopfamily;
                context->partopcintype = partkey->partopcintype;
                context->partcollation = partkey->partcollation;
-               context->partsupfunc = partkey->partsupfunc;
+               /* Get partsupfunc FmgrInfo's. */
+               for (j = 0; j < partkey->partnatts; j++)
+               {
+                       fmgr_info_copy(&context->partsupfunc[j],
+                                                  partition_getprocinfo(rel, 
partkey, j),
+                                                  CurrentMemoryContext);
+               }
                context->nparts = nparts;
                context->boundinfo = boundinfo;
                context->planstate = planstate;
diff --git a/src/backend/optimizer/util/plancat.c 
b/src/backend/optimizer/util/plancat.c
index cfda6f2a34..e189d07efe 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1940,7 +1940,7 @@ find_partition_scheme(PlannerInfo *root, Relation rel,
                 */
 #ifdef USE_ASSERT_CHECKING
                for (i = 0; i < partkey->partnatts; i++)
-                       Assert(partkey->partsupfunc[i].fn_oid ==
+                       Assert(partkey->partsupfuncid[i] ==
                                   part_scheme->partsupfunc[i].fn_oid);
 #endif
 
@@ -1960,7 +1960,12 @@ find_partition_scheme(PlannerInfo *root, Relation rel,
        part_scheme->partcollation = partkey->partcollation;
        part_scheme->parttyplen = partkey->parttyplen;
        part_scheme->parttypbyval = partkey->parttypbyval;
-       part_scheme->partsupfunc = partkey->partsupfunc;
+       part_scheme->partsupfunc = (FmgrInfo *)
+               palloc(sizeof(FmgrInfo) * partnatts);
+       for (i = 0; i < partnatts; i++)
+               fmgr_info_copy(&part_scheme->partsupfunc[i],
+                                          partition_getprocinfo(rel, partkey, 
i),
+                                          CurrentMemoryContext);
 
        /* Add the partitioning scheme to PlannerInfo. */
        root->part_schemes = lappend(root->part_schemes, part_scheme);
diff --git a/src/backend/partitioning/partbounds.c 
b/src/backend/partitioning/partbounds.c
index 0d2064d617..321b7cf427 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -420,8 +420,15 @@ check_new_partition_bound(char *relname, Relation parent,
 
                case PARTITION_STRATEGY_LIST:
                        {
+                               FmgrInfo partsupfunc;
+
                                Assert(spec->strategy == 
PARTITION_STRATEGY_LIST);
 
+                               /* Get partsupfunc FmgrInfo for the only key. */
+                               fmgr_info_copy(&partsupfunc,
+                                                          
partition_getprocinfo(parent, key, 0),
+                                                          
CurrentMemoryContext);
+
                                if (nparts > 0)
                                {
                                        ListCell   *cell;
@@ -441,8 +448,8 @@ check_new_partition_bound(char *relname, Relation parent,
                                                        int                     
offset;
                                                        bool            equal;
 
-                                                       offset = 
partition_list_bsearch(&key->partsupfunc[0],
-                                                                               
                                        key->partcollation,
+                                                       offset = 
partition_list_bsearch(&partsupfunc,
+                                                                               
                                key->partcollation,
                                                                                
                                        boundinfo,
                                                                                
                                        val->constvalue,
                                                                                
                                        &equal);
@@ -469,6 +476,16 @@ check_new_partition_bound(char *relname, Relation parent,
                        {
                                PartitionRangeBound *lower,
                                                   *upper;
+                               FmgrInfo partsupfunc[PARTITION_MAX_KEYS];
+                               int             i;
+
+                               /* Get partsupfunc FmgrInfo's. */
+                               for (i = 0; i < key->partnatts; i++)
+                               {
+                                       fmgr_info_copy(&partsupfunc[i],
+                                                                  
partition_getprocinfo(parent, key, i),
+                                                                  
CurrentMemoryContext);
+                               }
 
                                Assert(spec->strategy == 
PARTITION_STRATEGY_RANGE);
                                lower = make_one_range_bound(key, -1, 
spec->lowerdatums, true);
@@ -478,7 +495,7 @@ check_new_partition_bound(char *relname, Relation parent,
                                 * First check if the resulting range would be 
empty with
                                 * specified lower and upper bounds
                                 */
-                               if (partition_rbound_cmp(key->partnatts, 
key->partsupfunc,
+                               if (partition_rbound_cmp(key->partnatts, 
partsupfunc,
                                                                                
 key->partcollation, lower->datums,
                                                                                
 lower->kind, true, upper) >= 0)
                                {
@@ -518,7 +535,7 @@ check_new_partition_bound(char *relname, Relation parent,
                                         * at the end.
                                         */
                                        offset = 
partition_range_bsearch(key->partnatts,
-                                                                               
                         key->partsupfunc,
+                                                                               
                         partsupfunc,
                                                                                
                         key->partcollation,
                                                                                
                         boundinfo, lower,
                                                                                
                         &equal);
@@ -543,7 +560,7 @@ check_new_partition_bound(char *relname, Relation parent,
                                                        is_lower = 
(boundinfo->indexes[offset + 1] == -1);
 
                                                        cmpval = 
partition_rbound_cmp(key->partnatts,
-                                                                               
                                  key->partsupfunc,
+                                                                               
                                  partsupfunc,
                                                                                
                                  key->partcollation,
                                                                                
                                  datums, kind,
                                                                                
                                  is_lower, upper);
@@ -2150,6 +2167,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
        {
                Relation        parent;
                PartitionKey key;
+               FmgrInfo        partsupfunc[PARTITION_MAX_KEYS];
                int                     j;
 
                /* Open parent relation and fetch partition keyinfo */
@@ -2172,6 +2190,14 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
                                         errmsg("\"%s\" is not a hash 
partitioned table",
                                                        
get_rel_name(parentId))));
 
+               /* Get partsupfunc FmgrInfo's. */
+               for (j = 0; j < key->partnatts; j++)
+               {
+                       fmgr_info_copy(&partsupfunc[j],
+                                                  
partition_getprocinfo(parent, key, j),
+                                                  CurrentMemoryContext);
+               }
+
                if (!get_fn_expr_variadic(fcinfo->flinfo))
                {
                        int                     nargs = PG_NARGS() - 3;
@@ -2204,7 +2230,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
                                                                        j + 1, 
format_type_be(key->parttypid[j]), format_type_be(argtype))));
 
                                fmgr_info_copy(&my_extra->partsupfunc[j],
-                                                          &key->partsupfunc[j],
+                                                          &partsupfunc[j],
                                                           
fcinfo->flinfo->fn_mcxt);
                        }
 
@@ -2238,7 +2264,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
                                                                        
format_type_be(my_extra->variadic_type))));
 
                        fmgr_info_copy(&my_extra->partsupfunc[0],
-                                                  &key->partsupfunc[0],
+                                                  &partsupfunc[0],
                                                   fcinfo->flinfo->fn_mcxt);
                }
 
diff --git a/src/backend/partitioning/partprune.c 
b/src/backend/partitioning/partprune.c
index f047e6e827..d506bc0264 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -436,7 +436,10 @@ prune_append_rel_partitions(RelOptInfo *rel)
        context.partopfamily = rel->part_scheme->partopfamily;
        context.partopcintype = rel->part_scheme->partopcintype;
        context.partcollation = rel->part_scheme->partcollation;
-       context.partsupfunc = rel->part_scheme->partsupfunc;
+       for (i = 0; i < context.partnatts; i++)
+               fmgr_info_copy(&context.partsupfunc[i],
+                                          &rel->part_scheme->partsupfunc[i],
+                                          CurrentMemoryContext);
        context.nparts = rel->nparts;
        context.boundinfo = rel->boundinfo;
 
@@ -1412,7 +1415,8 @@ match_clause_to_partition_key(RelOptInfo *rel,
                partclause->op_is_ne = false;
                partclause->expr = expr;
                /* We know that expr is of Boolean type. */
-               partclause->cmpfn = 
rel->part_scheme->partsupfunc[partkeyidx].fn_oid;
+               partclause->cmpfn =
+                                               
rel->part_scheme->partsupfunc[partkeyidx].fn_oid;
                partclause->op_strategy = InvalidStrategy;
 
                *pc = partclause;
diff --git a/src/backend/utils/cache/partcache.c 
b/src/backend/utils/cache/partcache.c
index e234320e30..f73582a2a1 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -36,6 +36,12 @@
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
+typedef struct PartitionBoundSortInfo
+{
+       FmgrInfo           *partsupfunc;
+       PartitionKey    key;
+} PartitionBoundSortInfo;
+
 static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
                                                           void *arg);
@@ -146,10 +152,16 @@ RelationBuildPartitionKey(Relation relation)
        key->partattrs = (AttrNumber *) palloc0(key->partnatts * 
sizeof(AttrNumber));
        key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
        key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid));
-       key->partsupfunc = (FmgrInfo *) palloc0(key->partnatts * 
sizeof(FmgrInfo));
-
+       key->partsupfuncid = (Oid *) palloc0(key->partnatts * sizeof(Oid));
        key->partcollation = (Oid *) palloc0(key->partnatts * sizeof(Oid));
 
+       /*
+        * Also allocate space for partition support procedure FmgrInfo's, but
+        * they won't be filled until someone calls partition_getprocinfo.
+        */
+       relation->rd_partsupfunc = (FmgrInfo *)
+                                               palloc0(key->partnatts * 
sizeof(FmgrInfo));
+
        /* Gather type and collation info as well */
        key->parttypid = (Oid *) palloc0(key->partnatts * sizeof(Oid));
        key->parttypmod = (int32 *) palloc0(key->partnatts * sizeof(int32));
@@ -199,12 +211,7 @@ RelationBuildPartitionKey(Relation relation)
                                                        procnum,
                                                        
format_type_be(opclassform->opcintype))));
 
-               /*
-                * Actually, we never use one of these FmgrInfo's without 
copying
-                * first to the caller's memory context, so setting the memory 
context
-                * here may seem pointless.
-                */
-               fmgr_info_cxt(funcid, &key->partsupfunc[i], 
relation->rd_partcxt);
+               key->partsupfuncid[i] = funcid;
 
                /* Collation */
                key->partcollation[i] = collation->values[i];
@@ -336,6 +343,20 @@ RelationBuildPartitionDesc(Relation rel)
 
        if (nparts > 0)
        {
+               FmgrInfo        partsupfunc[PARTITION_MAX_KEYS];
+               PartitionBoundSortInfo sortinfo;
+
+               /* Get partsupfunc FmgrInfo's. */
+               for (i = 0; i < key->partnatts; i++)
+               {
+                       fmgr_info_copy(&partsupfunc[i],
+                                                  partition_getprocinfo(rel, 
key, i),
+                                                  CurrentMemoryContext);
+               }
+
+               sortinfo.partsupfunc = partsupfunc;
+               sortinfo.key = key;
+
                oids = (Oid *) palloc(nparts * sizeof(Oid));
                i = 0;
                foreach(cell, partoids)
@@ -453,7 +474,7 @@ RelationBuildPartitionDesc(Relation rel)
                        }
 
                        qsort_arg(all_values, ndatums, 
sizeof(PartitionListValue *),
-                                         qsort_partition_list_value_cmp, (void 
*) key);
+                                         qsort_partition_list_value_cmp, (void 
*) &sortinfo);
                }
                else if (key->strategy == PARTITION_STRATEGY_RANGE)
                {
@@ -506,7 +527,7 @@ RelationBuildPartitionDesc(Relation rel)
                        qsort_arg(all_bounds, ndatums,
                                          sizeof(PartitionRangeBound *),
                                          qsort_partition_rbound_cmp,
-                                         (void *) key);
+                                         (void *) &sortinfo);
 
                        /* Save distinct bounds from all_bounds into rbounds. */
                        rbounds = (PartitionRangeBound **)
@@ -538,7 +559,7 @@ RelationBuildPartitionDesc(Relation rel)
                                        if (cur->kind[j] != 
PARTITION_RANGE_DATUM_VALUE)
                                                break;
 
-                                       cmpval = 
FunctionCall2Coll(&key->partsupfunc[j],
+                                       cmpval = 
FunctionCall2Coll(&partsupfunc[j],
                                                                                
           key->partcollation[j],
                                                                                
           cur->datums[j],
                                                                                
           prev->datums[j]);
@@ -844,6 +865,40 @@ RelationGetDefaultPartitionOid(Relation rel)
 }
 
 /*
+ * partition_getprocinfo
+ *             Return fmgr lookup info of partition support procs from relcache
+ *
+ * If it's not been built yet by calling fmgr.c, do that and add it to
+ * relcache.
+ */
+FmgrInfo *
+partition_getprocinfo(Relation rel, PartitionKey key, int partattoff)
+{
+       FmgrInfo   *info;
+
+       info = rel->rd_partsupfunc;
+
+       Assert(info != NULL);
+
+       info += partattoff;
+
+       /* Initialize the lookup info if first time through */
+       if (info->fn_oid == InvalidOid)
+       {
+               RegProcedure *func = key->partsupfuncid;
+               RegProcedure procId;
+
+               Assert(func != NULL);
+
+               procId = func[partattoff];
+               Assert(RegProcedureIsValid(procId));
+               fmgr_info_cxt(procId, info, rel->rd_partcxt);
+       }
+
+       return info;
+}
+
+/*
  * RelationGetPartitionQual
  *
  * Returns a list of partition quals
@@ -900,8 +955,7 @@ static PartitionKey
 partition_key_copy(PartitionKey fromkey)
 {
        PartitionKey newkey;
-       int                     n,
-                               i;
+       int                     n;
 
        Assert(fromkey != NULL);
 
@@ -921,11 +975,8 @@ partition_key_copy(PartitionKey fromkey)
        newkey->partopcintype = (Oid *) palloc(n * sizeof(Oid));
        memcpy(newkey->partopcintype, fromkey->partopcintype, n * sizeof(Oid));
 
-       newkey->partsupfunc = (FmgrInfo *) palloc(n * sizeof(FmgrInfo));
-       for (i = 0; i < fromkey->partnatts; i++)
-               fmgr_info_copy(&newkey->partsupfunc[i],
-                                          &fromkey->partsupfunc[i],
-                                          CurrentMemoryContext);
+       newkey->partsupfuncid = (Oid *) palloc(n * sizeof(Oid));
+       memcpy(newkey->partsupfuncid, fromkey->partsupfuncid, n * sizeof(Oid));
 
        newkey->partcollation = (Oid *) palloc(n * sizeof(Oid));
        memcpy(newkey->partcollation, fromkey->partcollation, n * sizeof(Oid));
@@ -1059,9 +1110,10 @@ qsort_partition_list_value_cmp(const void *a, const void 
*b, void *arg)
 {
        Datum           val1 = (*(const PartitionListValue **) a)->value,
                                val2 = (*(const PartitionListValue **) 
b)->value;
-       PartitionKey key = (PartitionKey) arg;
+       PartitionBoundSortInfo *sortinfo = (PartitionBoundSortInfo *) arg;
+       PartitionKey key = sortinfo->key;
 
-       return DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
+       return DatumGetInt32(FunctionCall2Coll(&sortinfo->partsupfunc[0],
                                                                                
   key->partcollation[0],
                                                                                
   val1, val2));
 }
@@ -1072,9 +1124,10 @@ qsort_partition_rbound_cmp(const void *a, const void *b, 
void *arg)
 {
        PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
        PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
-       PartitionKey key = (PartitionKey) arg;
+       PartitionBoundSortInfo *sortinfo = (PartitionBoundSortInfo *) arg;
+       PartitionKey key = sortinfo->key;
 
-       return partition_rbound_cmp(key->partnatts, key->partsupfunc,
+       return partition_rbound_cmp(key->partnatts, sortinfo->partsupfunc,
                                                                
key->partcollation, b1->datums, b1->kind,
                                                                b1->lower, b2);
 }
diff --git a/src/backend/utils/cache/relcache.c 
b/src/backend/utils/cache/relcache.c
index 16081bc932..dbd41d365e 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1157,6 +1157,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
        {
                relation->rd_partcxt = NULL;
                relation->rd_partkey = NULL;
+               relation->rd_partsupfunc = NULL;
                relation->rd_partdesc = NULL;
                relation->rd_partcheck = NIL;
        }
@@ -5509,6 +5510,7 @@ load_relcache_init_file(bool shared)
                rel->rd_rsdesc = NULL;
                rel->rd_partcxt = NULL;
                rel->rd_partkey = NULL;
+               rel->rd_partsupfunc = NULL;
                rel->rd_partdesc = NULL;
                rel->rd_partcheck = NIL;
                rel->rd_indexprs = NIL;
diff --git a/src/include/executor/execPartition.h 
b/src/include/executor/execPartition.h
index b5dc53bfcb..47eedb91bb 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -25,6 +25,7 @@
  *     reldesc         Relation descriptor of the table
  *     key                     Partition key information of the table
  *     keystate        Execution state required for expressions in the 
partition key
+ *     partsupfunc             fmgr lookup info of partition support functions
  *     nparts          Number of partitions of the table
  *     boundinfo       PartitionBoundInfo of the table
  *     tupslot         A standalone TupleTableSlot initialized with this 
table's tuple
@@ -42,6 +43,7 @@ typedef struct PartitionDispatchData
        Relation        reldesc;
        PartitionKey key;
        List       *keystate;           /* list of ExprState */
+       FmgrInfo        partsupfunc[PARTITION_MAX_KEYS];
        int                     nparts;
        PartitionBoundInfo boundinfo;
        TupleTableSlot *tupslot;
diff --git a/src/include/partitioning/partprune.h 
b/src/include/partitioning/partprune.h
index 114a9594be..44f0ad3706 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -31,7 +31,7 @@ typedef struct PartitionPruneContext
        Oid                *partopfamily;
        Oid                *partopcintype;
        Oid                *partcollation;
-       FmgrInfo   *partsupfunc;
+       FmgrInfo        partsupfunc[PARTITION_MAX_KEYS];
 
        /* Number of partitions */
        int                     nparts;
diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h
index b037bb00d5..e9a133ec76 100644
--- a/src/include/utils/partcache.h
+++ b/src/include/utils/partcache.h
@@ -32,7 +32,7 @@ typedef struct PartitionKeyData
 
        Oid                *partopfamily;       /* OIDs of operator families */
        Oid                *partopcintype;      /* OIDs of opclass declared 
input data types */
-       FmgrInfo   *partsupfunc;        /* lookup info for support funcs */
+       Oid                *partsupfuncid;      /* partition support func OIDs 
*/
 
        /* Partitioning collation per attribute */
        Oid                *partcollation;
@@ -49,6 +49,8 @@ typedef struct PartitionKeyData
 extern void RelationBuildPartitionKey(Relation relation);
 extern void RelationBuildPartitionDesc(Relation rel);
 extern PartitionKey RelationGetPartitionKey(Relation relation);
+extern FmgrInfo *partition_getprocinfo(Relation rel, PartitionKey key,
+                                                                          int 
partattoff);
 extern int RelationGetPartitionCount(Relation relation);
 extern Oid *RelationGetPartitionOids(Relation relation);
 extern PartitionBoundInfo RelationGetPartitionBounds(Relation relation);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 378401abca..930e4363c1 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -98,6 +98,8 @@ typedef struct RelationData
        MemoryContext rd_partcxt;       /* private memory cxt for the values 
contained
                                                                 * in the 
fields related to partitioning */
        struct PartitionKeyData *rd_partkey;    /* partition key, or NULL */
+       FmgrInfo   *rd_partsupfunc;     /* fmgr lookup info of partition support
+                                                                * functions */
        struct PartitionDescData *rd_partdesc;  /* partitions, or NULL */
        List       *rd_partcheck;       /* partition CHECK quals */
 
-- 
2.11.0

Reply via email to