From 490d89a55bb0a680885704a8b6ddb96b85e160de Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 10 Feb 2016 19:28:22 +0900
Subject: [PATCH 08/10] Rework code manipulating the PartitionKey data structure.

Previously, type information about partition key columns was handled
separately. So, there were public interface functions to get partition
key type information wherever required. But that needed access to the
root parent relation at all times (to get to partition expressions) and
resulted in needing to pass around that rel and type information which
became unbearable by this point.

Instead, integrate type information into PartitionKey structure and build
it when building partition key itself. That means, partition expressions
are also built which wasn't the case previously. So, no more need for
RelationGetPartitionExpr() which had a weird interface anyway.
---
 src/backend/catalog/partition.c    |  298 +++++++++++++++++++-----------------
 src/backend/commands/tablecmds.c   |   60 +++----
 src/backend/parser/parse_utilcmd.c |   17 +--
 src/backend/utils/cache/relcache.c |   88 -----------
 src/include/catalog/partition.h    |   41 +++---
 src/include/utils/relcache.h       |    2 -
 6 files changed, 204 insertions(+), 302 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 33a16eb..cf48bf4 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -30,6 +30,8 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
+#include "optimizer/planmain.h"
 #include "storage/lmgr.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
@@ -61,11 +63,9 @@ typedef struct PartitionInfo
 
 static int32 range_partition_cmp_max(const void *a, const void *b,
 					void *arg);
-static PartitionDesc CopyPartitionDesc(PartitionDesc src, int partnatts,
-					char strategy, PartitionKeyTypeInfo *typinfo);
+static PartitionDesc CopyPartitionDesc(PartitionDesc src, PartitionKey key);
 static PartitionInfo **GetRelPartitions(Relation rel, PartitionKey key,
-					PartitionKeyTypeInfo *typinfo, bool only_valid,
-					int *numparts);
+					bool only_valid, int *numparts);
 static void free_partitions(PartitionInfo **p, int num);
 static int	oid_cmp(const void *p1, const void *p2);
 static List *get_leaf_partitions_recurse(Oid relid, int lockmode,
@@ -248,11 +248,9 @@ relid_is_partitioned(Oid relid)
 void
 RelationBuildPartitionKeys(Relation relation)
 {
-	List	   *keys = NIL;
-	HeapTuple	tuple;
-	bool		isnull;
-	int			level, i;
-	MemoryContext oldcxt = CurrentMemoryContext;
+	List		   *keys = NIL;
+	int				level;
+	MemoryContext	oldcxt = CurrentMemoryContext;
 
 	/*
 	 * Loop through the partition keys for this relation, if any.
@@ -261,10 +259,15 @@ RelationBuildPartitionKeys(Relation relation)
 	{
 		Relation		catalog;
 		Form_pg_partitioned_rel	form;
-		PartitionKey	key;
+		HeapTuple		tuple;
+		Datum			datum;
+		bool			isnull;
 		int2vector	   *partattrs;
+		ListCell	   *partexprs_item;
 		oidvector	   *opclass;
-		Datum			datum;
+		int				i;
+		PartitionKey	key;
+		KeyTypeInfo	   *typinfo;
 
 		tuple = SearchSysCache2(PARTEDRELIDLEVEL,
 							ObjectIdGetDatum(RelationGetRelid(relation)),
@@ -295,33 +298,83 @@ RelationBuildPartitionKeys(Relation relation)
 		Assert(!isnull);
 		opclass = (oidvector *) DatumGetPointer(datum);
 
-		key->partattrs = (AttrNumber *)
-							palloc0(key->partnatts * sizeof(AttrNumber));
+		datum = heap_getattr(tuple,
+								Anum_pg_partitioned_rel_partexprs,
+								RelationGetDescr(catalog),
+								&isnull);
+		if (!isnull)
+		{
+			char   *exprsString;
+			Node   *exprs;
+
+			exprsString = TextDatumGetCString(datum);
+			exprs = stringToNode(exprsString);
+			pfree(exprsString);
+
+			/*
+			 * Run the expressions through eval_const_expressions. This is
+			 * not just an optimization, but is necessary, because the
+			 * planner will be comparing them to similarly-processed qual
+			 * clauses, and may fail to detect valid matches without this.
+			 * We don't bother with canonicalize_qual, however.
+			 */
+			exprs = eval_const_expressions(NULL, (Node *) exprs);
+
+			/* May as well fix opfuncids too */
+			fix_opfuncids((Node *) exprs);
+			key->partexprs = (List *) exprs;
+		}
+
+		key->partattrs = (AttrNumber *) palloc0(key->partnatts * sizeof(AttrNumber));
 		key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
-		key->partsupfunc = (FmgrInfo *)
-							palloc0(key->partnatts * sizeof(FmgrInfo));
+		key->partsupfunc = (FmgrInfo *) palloc0(key->partnatts * sizeof(FmgrInfo));
+
+		/* Gather type info as well */
+		key->typinfo = typinfo = (KeyTypeInfo *) palloc0(sizeof(KeyTypeInfo));
+		typinfo->typid = (Oid *) palloc0(key->partnatts * sizeof(Oid));
+		typinfo->typmod = (int32 *) palloc0(key->partnatts * sizeof(int32));
+		typinfo->typlen = (int16 *) palloc0(key->partnatts * sizeof(int16));
+		typinfo->typbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
+		typinfo->typalign = (char *) palloc0(key->partnatts * sizeof(bool));
 
 		/*
 		 * Copy partattrs. Further, determine and store the opfamily and
 		 * support function per attribute.
 		 */
+		partexprs_item = list_head(key->partexprs);
 		for (i = 0; i < key->partnatts; i++)
 		{
-			HeapTuple			tuple;
-			Form_pg_opclass 	form;
-			Oid					funcid;
+			HeapTuple		tuple;
+			AttrNumber		attno;
+			Form_pg_opclass form;
+			Oid				funcid;
 
-			key->partattrs[i] = partattrs->values[i];
+			key->partattrs[i] = attno = partattrs->values[i];
 
-			tuple = SearchSysCache(CLAOID,
-							ObjectIdGetDatum(opclass->values[i]),
-							0, 0, 0);
+			/* Collect type information */
+			if (attno != InvalidAttrNumber)
+			{
+				typinfo->typid[i] = relation->rd_att->attrs[attno - 1]->atttypid;
+				typinfo->typmod[i] = relation->rd_att->attrs[attno - 1]->atttypmod;
+			}
+			else
+			{
+				typinfo->typid[i] = exprType(lfirst(partexprs_item));
+				typinfo->typmod[i] = exprTypmod(lfirst(partexprs_item));
+				partexprs_item = lnext(partexprs_item);
+			}
+			get_typlenbyvalalign(typinfo->typid[i],
+								 &typinfo->typlen[i],
+								 &typinfo->typbyval[i],
+								 &typinfo->typalign[i]);
+
+			/* Determine operator family */
+			tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass->values[i]));
 			if (!HeapTupleIsValid(tuple))
 				elog(ERROR, "cache lookup failed for opclass %u",
 							opclass->values[i]);
 
 			form = (Form_pg_opclass) GETSTRUCT(tuple);
-
 			key->partopfamily[i] = form->opcfamily;
 
 			/*
@@ -336,9 +389,6 @@ RelationBuildPartitionKeys(Relation relation)
 			ReleaseSysCache(tuple);
 		}
 
-		/* partexprs are built and copied here as and when necessary */
-		key->partexprs = NIL;
-
 		keys = lappend(keys, key);
 
 		ReleaseSysCache(tuple);
@@ -353,6 +403,25 @@ RelationBuildPartitionKeys(Relation relation)
 	FreePartitionKeys(keys);
 }
 
+static KeyTypeInfo *
+copy_key_type_info(int n, KeyTypeInfo *typinfo)
+{
+	KeyTypeInfo   *result = (KeyTypeInfo *) palloc0(sizeof(KeyTypeInfo));
+
+	result->typid = (Oid *) palloc0(n * sizeof(Oid));
+	memcpy(result->typid, typinfo->typid, n * sizeof(Oid));
+	result->typmod = (int32 *) palloc0(n * sizeof(int32));
+	memcpy(result->typmod, typinfo->typmod, n * sizeof(int32));
+	result->typlen = (int16 *) palloc0(n * sizeof(int16));
+	memcpy(result->typlen, typinfo->typlen, n * sizeof(int16));
+	result->typbyval = (bool *) palloc0(n * sizeof(bool));
+	memcpy(result->typbyval, typinfo->typbyval, n * sizeof(bool));
+	result->typalign = (char *) palloc0(n * sizeof(bool));
+	memcpy(result->typalign, typinfo->typalign, n * sizeof(bool));
+
+	return result;
+}
+
 /*
  * CopyPartitionKeys
  *
@@ -389,6 +458,10 @@ CopyPartitionKeys(List *keys)
 		memcpy(newkey->partsupfunc, fromkey->partsupfunc,
 							newkey->partnatts * sizeof(FmgrInfo));
 
+		newkey->partexprs = copyObject(fromkey->partexprs);
+		newkey->typinfo = copy_key_type_info(fromkey->partnatts,
+											 fromkey->typinfo);
+
 		result = lappend(result, newkey);
 	}
 
@@ -396,6 +469,22 @@ CopyPartitionKeys(List *keys)
 }
 
 /*
+ * free_key_type_info
+ */
+static void
+free_key_type_info(KeyTypeInfo *typinfo)
+{
+	Assert(typinfo != NULL);
+
+	pfree(typinfo->typid);
+	pfree(typinfo->typmod);
+	pfree(typinfo->typlen);
+	pfree(typinfo->typbyval);
+	pfree(typinfo->typalign);
+	pfree(typinfo);
+}
+
+/*
  * FreePartitionKeys
  */
 void
@@ -413,83 +502,13 @@ FreePartitionKeys(List *keys)
 		pfree(key->partattrs);
 		pfree(key->partopfamily);
 		pfree(key->partsupfunc);
+		free_key_type_info(key->typinfo);
 		pfree(key);
 	}
 	pfree(keys);
 }
 
 /*
- * get_partition_key_type_info
- *		Returns a PartitionKeyTypeInfo object that includes type info
- *		for individual partition key attributes.
- *
- * Note to callers: make sure to call this on root parents (that is,
- * RELKIND_PARTITIONED_REL relations)
- */
-PartitionKeyTypeInfo *
-get_partition_key_type_info(Relation rel, PartitionKey key)
-{
-	int			i;
-	List	   *partexprs;
-	ListCell   *partexprs_item;
-	PartitionKeyTypeInfo *result;
-
-	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_REL);
-
-	partexprs = RelationGetPartitionExpr(rel, key->level);
-
-	result = (PartitionKeyTypeInfo *) palloc0(sizeof(PartitionKeyTypeInfo));
-	result->typid = (Oid *) palloc0(key->partnatts * sizeof(Oid));
-	result->typmod = (int32 *) palloc0(key->partnatts * sizeof(int32));
-	result->typlen = (int16 *) palloc0(key->partnatts * sizeof(int16));
-	result->typbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
-	result->typalign = (char *) palloc0(key->partnatts * sizeof(bool));
-
-	partexprs_item = list_head(partexprs);
-	for (i = 0; i < key->partnatts; i++)
-	{
-		AttrNumber attno = key->partattrs[i];
-
-		if (attno != InvalidAttrNumber)
-		{
-			result->typid[i] = rel->rd_att->attrs[attno - 1]->atttypid;
-			result->typmod[i] = rel->rd_att->attrs[attno - 1]->atttypmod;
-		}
-		else
-		{
-			result->typid[i] = exprType(lfirst(partexprs_item));
-			result->typmod[i] = exprTypmod(lfirst(partexprs_item));
-			partexprs_item = lnext(partexprs_item);
-		}
-		get_typlenbyvalalign(result->typid[i],
-								&result->typlen[i],
-								&result->typbyval[i],
-								&result->typalign[i]);
-	}
-
-	if (partexprs)
-		pfree(partexprs);
-
-	return result;
-}
-
-/*
- * free_key_type_info
- */
-void
-free_partition_key_type_info(PartitionKeyTypeInfo *typinfo)
-{
-	Assert(typinfo != NULL);
-
-	pfree(typinfo->typid);
-	pfree(typinfo->typmod);
-	pfree(typinfo->typlen);
-	pfree(typinfo->typbyval);
-	pfree(typinfo->typalign);
-	pfree(typinfo);
-}
-
-/*
  * StorePartition
  *		Store information of new partition of rel into pg_partition
  *
@@ -497,7 +516,7 @@ free_partition_key_type_info(PartitionKeyTypeInfo *typinfo)
  * 'parentOid' is OID of the actual parent of 'partition'.
  */
 void
-StorePartition(Relation rel, PartitionKey key, PartitionKeyTypeInfo *typinfo,
+StorePartition(Relation rel, PartitionKey key,
 				Oid partitionOid,
 				Oid parentOid,
 				bool valid,
@@ -522,10 +541,10 @@ StorePartition(Relation rel, PartitionKey key, PartitionKeyTypeInfo *typinfo,
 			Assert(listnvalues > 0);
 			arr_listvalues = construct_array(boundDatums,
 										 listnvalues,
-										 typinfo->typid[0],
-										 typinfo->typlen[0],
-										 typinfo->typbyval[0],
-										 typinfo->typalign[0]);
+										 key->typinfo->typid[0],
+										 key->typinfo->typlen[0],
+										 key->typinfo->typbyval[0],
+										 key->typinfo->typalign[0]);
 			/* No range bounds */
 			nulls[Anum_pg_partition_partrangemaxs - 1] = true;
 			break;
@@ -614,8 +633,7 @@ RelationDropPartitions(Oid relid)
  * though, since it could disappear due to relcache invalidation.)
  */
 PartitionDesc
-RelationGetPartitionDesc(Relation relation, PartitionKey key,
-						 PartitionKeyTypeInfo *typinfo, bool include_all)
+RelationGetPartitionDesc(Relation relation, PartitionKey key, bool include_all)
 {
 	int		i,
 			j;
@@ -626,15 +644,11 @@ RelationGetPartitionDesc(Relation relation, PartitionKey key,
 
 	/* Quick copy and exit if already computed the descriptor */
 	if (relation->rd_partdesc != NULL)
-		return CopyPartitionDesc(relation->rd_partdesc,
-								 key->partnatts,
-								 key->strategy,
-								 typinfo);
+		return CopyPartitionDesc(relation->rd_partdesc, key);
 
 	result = (PartitionDesc) palloc0(sizeof(PartitionDescData));
 
-	partitions = GetRelPartitions(relation, key, typinfo, !include_all,
-								  &numparts);
+	partitions = GetRelPartitions(relation, key, !include_all, &numparts);
 	result->numparts = numparts;
 
 	if (partitions)
@@ -671,12 +685,12 @@ RelationGetPartitionDesc(Relation relation, PartitionKey key,
 					Datum   *from = &partitions[i]->listvalues[j];
 					Datum   *into = &result->listvalues[i][j];
 
-					if (!typinfo->typbyval[0])
+					if (!key->typinfo->typbyval[0])
 					{
-						if (typinfo->typlen[0] == -1)
+						if (key->typinfo->typlen[0] == -1)
 							*into = PointerGetDatum(PG_DETOAST_DATUM_COPY(*from));
 						else
-							*into = datumCopy(*from, false, typinfo->typlen[0]);
+							*into = datumCopy(*from, false, key->typinfo->typlen[0]);
 					}
 					else
 						*into = *from;
@@ -694,12 +708,12 @@ RelationGetPartitionDesc(Relation relation, PartitionKey key,
 					Datum   *from = &partitions[i]->rangemaxs[j];
 					Datum   *into = &result->rangemaxs[j][i];
 
-					if (!typinfo->typbyval[j])
+					if (!key->typinfo->typbyval[j])
 					{
-						if (typinfo->typlen[j] == -1)
+						if (key->typinfo->typlen[j] == -1)
 							*into = PointerGetDatum(PG_DETOAST_DATUM_COPY(*from));
 						else
-							*into = datumCopy(*from, false, typinfo->typlen[j]);
+							*into = datumCopy(*from, false, key->typinfo->typlen[j]);
 					}
 					else
 						*into = *from;
@@ -722,10 +736,7 @@ RelationGetPartitionDesc(Relation relation, PartitionKey key,
 	relation->rd_partdesc = MemoryContextAllocZero(relation->rd_pdcxt,
 													sizeof(PartitionDescData));
 	oldcxt = MemoryContextSwitchTo(relation->rd_pdcxt);
-	relation->rd_partdesc = CopyPartitionDesc(result,
-											  key->partnatts,
-											  key->strategy,
-											  typinfo);
+	relation->rd_partdesc = CopyPartitionDesc(result, key);
 	MemoryContextSwitchTo(oldcxt);
 
 	return result;
@@ -769,8 +780,7 @@ range_partition_cmp_max(const void *a, const void *b, void *arg)
  *		Copy PartitionDesc of a partitioned relation into caller's context
  */
 static PartitionDesc
-CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
-				  PartitionKeyTypeInfo *typinfo)
+CopyPartitionDesc(PartitionDesc src, PartitionKey key)
 {
 	PartitionDesc	result;
 	int				i, j;
@@ -782,7 +792,7 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
 	if (result->numparts > 0)
 	{
 		result->oids = (Oid *) palloc0(result->numparts * sizeof(Oid));
-		switch (strategy)
+		switch (key->strategy)
 		{
 			case PARTITION_STRAT_LIST:
 				result->listnvalues = (int *)
@@ -791,7 +801,7 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
 								palloc0(result->numparts * sizeof(Datum *));
 				break;
 			case PARTITION_STRAT_RANGE:
-				for (i = 0; i < partnatts; i++)
+				for (i = 0; i < key->partnatts; i++)
 					result->rangemaxs[i] = (Datum *)
 								palloc0(result->numparts * sizeof(Datum));
 				break;
@@ -802,7 +812,7 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
 	{
 		result->oids[i] = src->oids[i];
 
-		switch (strategy)
+		switch (key->strategy)
 		{
 			case PARTITION_STRAT_LIST:
 				result->listnvalues[i] = src->listnvalues[i];
@@ -814,12 +824,12 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
 					Datum   *from = &src->listvalues[i][j];
 					Datum   *into = &result->listvalues[i][j];
 
-					if (!typinfo->typbyval[0])
+					if (!key->typinfo->typbyval[0])
 					{
-						if (typinfo->typlen[0] == -1)
+						if (key->typinfo->typlen[0] == -1)
 							*into = PointerGetDatum(PG_DETOAST_DATUM_COPY(*from));
 						else
-							*into = datumCopy(*from, false, typinfo->typlen[0]);
+							*into = datumCopy(*from, false, key->typinfo->typlen[0]);
 					}
 					else
 						*into = *from;
@@ -827,17 +837,17 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
 				break;
 
 			case PARTITION_STRAT_RANGE:
-				for (j = 0; j < partnatts; j++)
+				for (j = 0; j < key->partnatts; j++)
 				{
 					Datum   *from = &src->rangemaxs[j][i];
 					Datum   *into = &result->rangemaxs[j][i];
 
-					if (!typinfo->typbyval[j])
+					if (!key->typinfo->typbyval[j])
 					{
-						if (typinfo->typlen[j] == -1)
+						if (key->typinfo->typlen[j] == -1)
 							*into = PointerGetDatum(PG_DETOAST_DATUM_COPY(*from));
 						else
-							*into = datumCopy(*from, false, typinfo->typlen[j]);
+							*into = datumCopy(*from, false, key->typinfo->typlen[j]);
 					}
 					else
 						*into = *from;
@@ -859,8 +869,8 @@ CopyPartitionDesc(PartitionDesc src, int partnatts, char strategy,
  * Returns number of partitions in *numparts.
  */
 static PartitionInfo **
-GetRelPartitions(Relation rel, PartitionKey key, PartitionKeyTypeInfo *typinfo,
-				 bool only_valid, int *numparts)
+GetRelPartitions(Relation rel, PartitionKey key, bool only_valid,
+				 int *numparts)
 {
 	List	   *partoids;
 	int			i;
@@ -906,10 +916,10 @@ GetRelPartitions(Relation rel, PartitionKey key, PartitionKeyTypeInfo *typinfo,
 		if (!isnull)
 		{
 			deconstruct_array(DatumGetArrayTypeP(datum),
-							  typinfo->typid[0],
-							  typinfo->typlen[0],
-							  typinfo->typbyval[0],
-							  typinfo->typalign[0],
+							  key->typinfo->typid[0],
+							  key->typinfo->typlen[0],
+							  key->typinfo->typbyval[0],
+							  key->typinfo->typalign[0],
 							  &result->listvalues, NULL, &result->listnvalues);
 
 			ReleaseSysCache(tuple);
@@ -941,10 +951,10 @@ GetRelPartitions(Relation rel, PartitionKey key, PartitionKeyTypeInfo *typinfo,
 			int			dummy;
 
 			deconstruct_array(arr,
-							  typinfo->typid[j],
-							  typinfo->typlen[j],
-							  typinfo->typbyval[j],
-							  typinfo->typalign[j],
+							  key->typinfo->typid[j],
+							  key->typinfo->typlen[j],
+							  key->typinfo->typbyval[j],
+							  key->typinfo->typalign[j],
 							  &datum, &nulls, &dummy);
 			Assert(!nulls[0]);
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index adfaa2c..5e8726b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -458,12 +458,9 @@ static void ATExecChangePersistence(List **wqueue, AlteredTableInfo *tab,
 						Relation rel, char persistence, LOCKMODE lockmode);
 static void SetRelationPersistence(Oid relationId, char persistence);
 static Datum *EvalPartitionBound(Relation rootParent, Relation parent,
-						PartitionKey key, PartitionKeyTypeInfo *typinfo,
-						PartitionValues *values, int *listnvalues);
-static Datum *evalPartitionListBound(List *values, PartitionKeyTypeInfo *typinfo,
-						int nvalues);
-static Datum *evalPartitionRangeBound(List *values, PartitionKeyTypeInfo *typinfo,
-						int partnatts);
+						PartitionKey key, PartitionValues *values, int *listnvalues);
+static Datum *evalPartitionListBound(List *values, PartitionKey key);
+static Datum *evalPartitionRangeBound(List *values, PartitionKey key);
 static void ATExecAddPartition(Relation rootParent, RangeVar *name, RangeVar *parent,
 						PartitionValues *values);
 static void ATExecRemovePartition(Relation rootParent, RangeVar *name, bool is_detach,
@@ -6050,10 +6047,9 @@ is_partition_attr(Relation rel, AttrNumber attnum, bool *is_expr)
 	foreach(cell, keys)
 	{
 		PartitionKey	key = lfirst(cell);
-		int16		level = key->level;
 		int			partnatts = key->partnatts;
 		AttrNumber *partattrs = key->partattrs;
-		List	   *partexprs = RelationGetPartitionExpr(rel, level);
+		List	   *partexprs = key->partexprs;
 		ListCell   *partexpr_item;
 		int			i;
 
@@ -12918,7 +12914,6 @@ ATExecAddPartition(Relation rootParent, RangeVar *name, RangeVar *parent,
 	Datum		   *boundDatums;
 	int				listnvalues;
 	int				parent_level;
-	PartitionKeyTypeInfo *typinfo;
 
 	partRel = heap_openrv(name, NoLock);
 
@@ -12934,14 +12929,12 @@ ATExecAddPartition(Relation rootParent, RangeVar *name, RangeVar *parent,
 	partKey = is_subpart ? list_nth(rootParent->rd_partkeys, parent_level) :
 							linitial(rootParent->rd_partkeys);
 
-	typinfo = get_partition_key_type_info(rootParent, partKey);
-
 	/* Evaluate and validate new partition's bound */
-	boundDatums = EvalPartitionBound(rootParent, parentRel, partKey, typinfo,
-									 values, &listnvalues);
+	boundDatums = EvalPartitionBound(rootParent, parentRel, partKey, values,
+									 &listnvalues);
 
 	/* Update the catalog */
-	StorePartition(rootParent, partKey, typinfo,
+	StorePartition(rootParent, partKey,
 					RelationGetRelid(partRel),
 					RelationGetRelid(parentRel),
 					true,
@@ -12951,7 +12944,6 @@ ATExecAddPartition(Relation rootParent, RangeVar *name, RangeVar *parent,
 	/* Tell world about the new partition of parent. */
 	CacheInvalidateRelcache(parentRel);
 
-	free_partition_key_type_info(typinfo);
 	heap_close(partRel, NoLock);
 	if (parentRel != rootParent)
 		heap_close(parentRel, AccessExclusiveLock);
@@ -12967,8 +12959,7 @@ ATExecAddPartition(Relation rootParent, RangeVar *name, RangeVar *parent,
  */
 static Datum *
 EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
-				   PartitionKeyTypeInfo *typinfo, PartitionValues *values,
-				   int *listnvalues)
+				   PartitionValues *values, int *listnvalues)
 {
 	PartitionDesc	pdesc;
 	Datum	   *result;
@@ -12976,7 +12967,7 @@ EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
 	Oid			overlapsWith;
 	int			i;
 
-	pdesc = RelationGetPartitionDesc(parent, key, typinfo, true);
+	pdesc = RelationGetPartitionDesc(parent, key, true);
 
 	/* result->oid is set by the caller */
 
@@ -12988,8 +12979,7 @@ EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
 			Assert(list_length(values->listvalues) >= 1);
 
 			result = (Datum *) palloc0(*listnvalues * sizeof(Datum));
-			result = evalPartitionListBound(values->listvalues, typinfo,
-											*listnvalues);
+			result = evalPartitionListBound(values->listvalues, key);
 
 			/* TODO: uniqueify(result->listvalues) */
 
@@ -13005,7 +12995,7 @@ EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
 
 		case PARTITION_STRAT_RANGE:
 			Assert(list_length(values->rangemaxs) == key->partnatts);
-			rangemaxs = evalPartitionRangeBound(values->rangemaxs, typinfo, key->partnatts);
+			rangemaxs = evalPartitionRangeBound(values->rangemaxs, key);
 
 			if (range_partition_overlaps(pdesc, key, rangemaxs))
 				ereport(ERROR,
@@ -13037,8 +13027,10 @@ EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
 				lbs[0] = 1;
 
 				rangemax = construct_md_array(datums, nulls, 1, dims, lbs,
-												typinfo->typid[i], typinfo->typlen[i],
-												typinfo->typbyval[i], typinfo->typalign[i]);
+											  key->typinfo->typid[i],
+											  key->typinfo->typlen[i],
+											  key->typinfo->typbyval[i],
+											  key->typinfo->typalign[i]);
 
 				result[i] = PointerGetDatum(rangemax);
 			}
@@ -13053,19 +13045,19 @@ EvalPartitionBound(Relation rootParent, Relation parent, PartitionKey key,
  *		for a list partition
  */
 static Datum *
-evalPartitionListBound(List *values, PartitionKeyTypeInfo *typinfo, int nvalues)
+evalPartitionListBound(List *values, PartitionKey key)
 {
 	ListCell	*cell;
 	ParseState	*pstate;
 	EState		*estate;
 	ExprContext	*ecxt;
 	int			i;
-	Datum		*datum;
+	Datum	   *datum;
 
 	if (!values)
 		return NULL;
 
-	datum = (Datum *) palloc(nvalues * sizeof(Datum));
+	datum = (Datum *) palloc(list_length(values) * sizeof(Datum));
 	pstate = make_parsestate(NULL);
 	estate = CreateExecutorState();
 	ecxt = GetPerTupleExprContext(estate);
@@ -13089,12 +13081,12 @@ evalPartitionListBound(List *values, PartitionKeyTypeInfo *typinfo, int nvalues)
 
 		MemoryContextSwitchTo(oldcxt);
 
-		if (!typinfo->typbyval[0])
+		if (!key->typinfo->typbyval[0])
 		{
-			if (typinfo->typlen[0] == -1)
+			if (key->typinfo->typlen[0] == -1)
 				datum[i] = PointerGetDatum(PG_DETOAST_DATUM_COPY(datum[i]));
 			else
-				datum[i] = datumCopy(datum[i], false, typinfo->typlen[0]);
+				datum[i] = datumCopy(datum[i], false, key->typinfo->typlen[0]);
 		}
 
 		ResetPerTupleExprContext(estate);
@@ -13110,7 +13102,7 @@ evalPartitionListBound(List *values, PartitionKeyTypeInfo *typinfo, int nvalues)
  *		clause for a range partition
  */
 static Datum *
-evalPartitionRangeBound(List *values, PartitionKeyTypeInfo *typinfo, int partnatts)
+evalPartitionRangeBound(List *values, PartitionKey key)
 {
 	ListCell	*cell;
 	ParseState	*pstate;
@@ -13122,7 +13114,7 @@ evalPartitionRangeBound(List *values, PartitionKeyTypeInfo *typinfo, int partnat
 	if (!values)
 		return NULL;
 
-	datum = (Datum *) palloc(partnatts * sizeof(Datum));
+	datum = (Datum *) palloc(key->partnatts * sizeof(Datum));
 	pstate = make_parsestate(NULL);
 	estate = CreateExecutorState();
 	ecxt = GetPerTupleExprContext(estate);
@@ -13146,12 +13138,12 @@ evalPartitionRangeBound(List *values, PartitionKeyTypeInfo *typinfo, int partnat
 
 		MemoryContextSwitchTo(oldcxt);
 
-		if (!typinfo->typbyval[i])
+		if (!key->typinfo->typbyval[i])
 		{
-			if (typinfo->typlen[i] == -1)
+			if (key->typinfo->typlen[i] == -1)
 				datum[i] = PointerGetDatum(PG_DETOAST_DATUM_COPY(datum[i]));
 			else
-				datum[i] = datumCopy(datum[i], false, typinfo->typlen[i]);
+				datum[i] = datumCopy(datum[i], false, key->typinfo->typlen[i]);
 		}
 
 		ResetPerTupleExprContext(estate);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 94731ed..cdfea1c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3208,12 +3208,8 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 {
 	int			i;
 	ListCell   *cell;
-	PartitionKeyTypeInfo *typinfo;
 	PartitionValues		*result = (PartitionValues *)
 											makeNode(PartitionValues);
-
-	typinfo = get_partition_key_type_info(cxt->rel, key);
-
 	switch (key->strategy)
 	{
 		case PARTITION_STRAT_LIST:
@@ -3234,8 +3230,8 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 				valuetype = exprType(value);
 				value = coerce_to_target_type(cxt->pstate,
 											value, valuetype,
-											typinfo->typid[0],
-											typinfo->typmod[0],
+											key->typinfo->typid[0],
+											key->typinfo->typmod[0],
 											COERCION_ASSIGNMENT,
 											COERCE_IMPLICIT_CAST,
 											-1);
@@ -3244,7 +3240,7 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
 						 errmsg("partition key column is of type %s"
 								" but expression is of type %s",
-									format_type_be(typinfo->typid[0]),
+									format_type_be(key->typinfo->typid[0]),
 									format_type_be(valuetype)),
 						 errhint("You will need to rewrite or cast the expression."),
 						 parser_errposition(cxt->pstate, exprLocation(orig_value))));
@@ -3288,8 +3284,8 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 				valuetype = exprType(value);
 				value = coerce_to_target_type(NULL,
 											value, valuetype,
-											typinfo->typid[i],
-											typinfo->typmod[i],
+											key->typinfo->typid[i],
+											key->typinfo->typmod[i],
 											COERCION_ASSIGNMENT,
 											COERCE_IMPLICIT_CAST,
 											-1);
@@ -3298,7 +3294,7 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
 						 errmsg("partition key column is of type %s"
 								" but expression is of type %s",
-									format_type_be(typinfo->typid[0]),
+									format_type_be(key->typinfo->typid[0]),
 									format_type_be(valuetype)),
 						 errhint("You will need to rewrite or cast the expression."),
 						 parser_errposition(cxt->pstate, exprLocation(orig_value))));
@@ -3309,7 +3305,6 @@ transformPartitionValues(CreateStmtContext *cxt, PartitionKey key,
 			break;
 	}
 	result->location = values->location;
-	free_partition_key_type_info(typinfo);
 
 	return result;
 }
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ddb0da2..f6c656c 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -4514,94 +4514,6 @@ RelationGetExclusionInfo(Relation indexRelation,
 }
 
 /*
- * RelationGetPartitionExpr -- get the partition key expressions
- *
- * The returned node tree is copied into the caller's memory context. (We
- * don't want to return a pointer to the relcache copy,since it could
- * disappear due to relcache invalidation.)
- */
-List *
-RelationGetPartitionExpr(Relation relation, int16 level)
-{
-	ListCell   *cell;
-	Relation	catalog;
-	HeapTuple	tuple;
-	List	   *result = NIL;
-	Datum		exprsDatum;
-	bool		isnull;
-	char	   *exprsString;
-	MemoryContext oldcxt;
-
-	/* Shouldn't happen but play safe! */
-	if (relation->rd_partkeys == NIL)
-		return NIL;
-
-	/* Find the proper key in relcache */
-	foreach(cell, relation->rd_partkeys)
-	{
-		PartitionKey	key = lfirst(cell);
-
-		if (key->level != level)
-			continue;
-
-		/* Quick copy if we already computed the result */
-		if (key->partexprs)
-			return (List *) copyObject(key->partexprs);
-
-		/* Need to compute from the tuple in the syscache */
-		tuple = SearchSysCache2(PARTEDRELIDLEVEL,
-								RelationGetRelid(relation),
-								level);
-		Assert(HeapTupleIsValid(tuple));
-
-		/*
-		 * We build the tree we intend to return in the caller's context.
-		 * After successfully completing the work, we copy it into the
-		 * relcache entry. This avoids problems if we get some sort of
-		 * error partway through.
-		 */
-		catalog = heap_open(PartitionedRelRelationId, AccessShareLock);
-		exprsDatum = heap_getattr(tuple,
-								Anum_pg_partitioned_rel_partexprs,
-								RelationGetDescr(catalog),
-								&isnull);
-
-		/* No expressions in the key at this level */
-		if (isnull)
-		{
-			ReleaseSysCache(tuple);
-			heap_close(catalog, AccessShareLock);
-			return NIL;
-		}
-
-		exprsString = TextDatumGetCString(exprsDatum);
-		result = (List *) stringToNode(exprsString);
-		pfree(exprsString);
-
-		/*
-		 * Run the expressions through eval_const_expressions. This is not just an
-		 * optimization, but is necessary, because the planner will be comparing
-		 * them to similarly-processed qual clauses, and may fail to detect valid
-		 * matches without this.  We don't bother with canonicalize_qual, however.
-		 */
-		result = (List *) eval_const_expressions(NULL, (Node *) result);
-
-		/* May as well fix opfuncids too */
-		fix_opfuncids((Node *) result);
-
-		/* Now save a copy of the completed tree in the relcache entry. */
-		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-		key->partexprs = (List *) copyObject(result);
-		MemoryContextSwitchTo(oldcxt);
-
-		ReleaseSysCache(tuple);
-		heap_close(catalog, AccessShareLock);
-	}
-
-	return result;
-}
-
-/*
  * Routines to support ereport() reports of relation-related errors
  *
  * These could have been put into elog.c, but it seems like a module layering
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 7f1576a..c54fc1b 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -16,29 +16,30 @@
 #include "fmgr.h"
 #include "utils/relcache.h"
 
-/* Partition key information for one level */
-typedef struct PartitionKeyData
-{
-	char		strategy;		/* partition strategy */
-	int16		level;			/* partition level */
-	int16		partnatts;		/* number of partition attributes */
-	AttrNumber *partattrs;		/* partition attnums */
-	Oid		   *partopfamily;	/* OIDs of opfamily per col */
-	FmgrInfo   *partsupfunc;	/* lookup info for support funcs */
-	List	   *partexprs;		/* partition key expressions, if any */
-} PartitionKeyData;
-
-typedef struct PartitionKeyData *PartitionKey;
-
 /* Type information for partition key columns */
-typedef struct PartitionKeyTypeInfo
+typedef struct KeyTypeInfo
 {
 	Oid		*typid;
 	int32	*typmod;
 	int16	*typlen;
 	bool	*typbyval;
 	char	*typalign;
-} PartitionKeyTypeInfo;
+} KeyTypeInfo;
+
+/* Partition key information for one level */
+typedef struct PartitionKeyData
+{
+	char			strategy;		/* partition strategy */
+	int16			level;			/* partition level */
+	int16			partnatts;		/* number of partition attributes */
+	AttrNumber	   *partattrs;		/* partition attnums */
+	List		   *partexprs;		/* partition key expressions, if any */
+	KeyTypeInfo	   *typinfo;		/* key column type information */
+	Oid			   *partopfamily;	/* OIDs of opfamily per col */
+	FmgrInfo	   *partsupfunc;	/* lookup info for support funcs */
+} PartitionKeyData;
+
+typedef struct PartitionKeyData *PartitionKey;
 
 /*
  * Information about partitions of a partitioned table or sub-partitions
@@ -76,13 +77,9 @@ extern void RemovePartitionKeysByRelId(Oid relid);
 extern void RelationBuildPartitionKeys(Relation relation);
 extern List *CopyPartitionKeys(List *keys);
 extern void FreePartitionKeys(List *keys);
-extern PartitionKeyTypeInfo *get_partition_key_type_info(Relation rel,
-					PartitionKey key);
-extern void free_partition_key_type_info(PartitionKeyTypeInfo *typinfo);
 extern bool relid_is_partitioned(Oid relid);
 
 extern void StorePartition(Relation rel, PartitionKey key,
-					PartitionKeyTypeInfo *typinfo,
 					Oid partitionOid,
 					Oid parentOid,
 					bool valid,
@@ -91,9 +88,7 @@ extern void StorePartition(Relation rel, PartitionKey key,
 extern void RemovePartitionEntryByRelId(Oid relid);
 extern void RelationDropPartitions(Oid relid);
 extern PartitionDesc RelationGetPartitionDesc(Relation relation,
-					PartitionKey key,
-					PartitionKeyTypeInfo *typinfo,
-					bool include_all);
+					PartitionKey key, bool include_all);
 extern List *get_partitions(Oid relid, int lockmode);
 extern List *get_all_partitions(Oid relid, int lockmode);
 extern List *get_leaf_partitions(Oid relid, int lockmode);
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 0aa2104..1b48304 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -42,8 +42,6 @@ extern Oid	RelationGetOidIndex(Relation relation);
 extern Oid	RelationGetReplicaIndex(Relation relation);
 extern List *RelationGetIndexExpressions(Relation relation);
 extern List *RelationGetIndexPredicate(Relation relation);
-extern List *RelationGetPartitionExpr(Relation relation,
-									int16 level);
 
 typedef enum IndexAttrBitmapKind
 {
-- 
1.7.1

