diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 974febb..acd29eb 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -155,7 +155,6 @@ typedef struct PartitionRangeBound
  */
 typedef struct PartitionBoundCmpArg
 {
-	bool	is_bound;
 	union
 	{
 		PartitionListValue	   *lbound;
@@ -165,6 +164,7 @@ typedef struct PartitionBoundCmpArg
 
 	Datum  *datums;
 	int		ndatums;
+	bool	is_bound;
 } PartitionBoundCmpArg;
 
 /*
@@ -177,7 +177,7 @@ typedef struct PartClause
 	Expr   *constarg;
 
 	/* cached info. */
-	bool	valid_cache;	/* Is the following information initialized? */
+	bool	valid_cache;	/* Are the following fields populated? */
 	int		op_strategy;
 	Oid		op_subtype;
 	FmgrInfo op_func;
@@ -199,45 +199,43 @@ typedef enum PartOpStrategy
  *		Information about partition look up keys to be passed to
  *		get_partitions_for_keys()
  *
- * This information is extracted from the query's mutually conjunctive operator
- * clauses, each of whose variable argument is matched to a partition key and
- * operator is checked to be contained in the corresponding column's partition
- * operator family.
+ * Stores Datums and nullness properties found in clauses which match the
+ * partition key.  Properties found are cache and are indexed by the partition
+ * key index.
  */
 typedef struct PartScanKeyInfo
 {
 	/*
-	 * Equality look up key.  Values in the following array appear in no
-	 * particular order (unlike minkeys and maxkeys below which must appear in
-	 * the same order as the partition key columns).  n_eqkeys must be equal to
-	 * the number of partition keys to be valid (except in the case of hash
-	 * partitioning where that's not required).  When set, minkeys and maxkeys
-	 * are ignored.
+	 * Equality look up key.  Used to store known Datums values from clauses
+	 * compared by an equality operation to the partition key.
 	 */
 	Datum	eqkeys[PARTITION_MAX_KEYS];
-	int		n_eqkeys;
 
 	/*
-	 * Lower and upper bounds on a sequence of selected partitions.  Values in
-	 * the following arrays must appear in the same order as the partition key
-	 * columns and may contain values for only a prefix of the partition key
-	 * columns.  If *_incl is true then the corresponding bound is inclusive
-	 * and hence the partition into which the bound falls is to be included in
-	 * the set of selected partitions.
+	 * Lower and upper bounds on a sequence of selected partitions.  These may
+	 * contain values for only a prefix of the partition keys.
 	 */
 	Datum	minkeys[PARTITION_MAX_KEYS];
-	int		n_minkeys;
-	bool	min_incl;
-
 	Datum	maxkeys[PARTITION_MAX_KEYS];
+
+	/*
+	 * Number of values stored in the corresponding array above
+	 */
+	int		n_eqkeys;
+	int		n_minkeys;
 	int		n_maxkeys;
+
+	/*
+	 * Properties to mark if the clauses found for the corresponding partition
+	 * are inclusive of the stored value or not.
+	 */
+	bool	min_incl;
 	bool	max_incl;
 
 	/*
-	 * Information about nullness of partition keys, either specified
+	 * Information about nullness of the partition keys, either specified
 	 * explicitly in the query (in the form of a IS [NOT] NULL clause) or
-	 * implied due to the assumption of strictness of the partitioning
-	 * operators.
+	 * implied from strict clauses matching the partition key.
 	 */
 	Bitmapset   *keyisnull;
 	Bitmapset   *keyisnotnull;
@@ -293,8 +291,8 @@ PG_FUNCTION_INFO_V1(satisfies_hash_partition);
 
 static Bitmapset *get_partitions_from_clauses_recurse(Relation relation,
 								int rt_index, List *clauses);
-static Bitmapset *get_partitions_excluded_by(Relation relation,
-						   List *ne_clauses);
+static Bitmapset *get_partitions_excluded_by_ne_clauses(Relation relation,
+									  List *ne_clauses);
 static Bitmapset *get_partitions_from_or_clause_args(Relation relation,
 								int rt_index, List *or_clause_args);
 static bool classify_partition_bounding_keys(Relation relation, List *clauses,
@@ -1692,22 +1690,26 @@ get_partition_qual_relid(Oid relid)
 
 /*
  * get_partitions_from_clauses
- *		Determine the set of partitions of 'relation' that will satisfy all
- *		the clauses contained in 'partclauses'
+ *		Determine all partitions of 'relation' that could possibly contain a
+ *		record that matches 'partclauses'
  *
- * Outputs:
- *	A Bitmapset containing indexes of all selected partitions.
+ * Returns a Bitmapset of the matching partition indexes, or NULL if none can
+ * match.
  */
 Bitmapset *
 get_partitions_from_clauses(Relation relation, int rt_index,
 							List *partclauses)
 {
-	Bitmapset	   *result;
-	List		   *partconstr;
+	List		   *clauses;
 	PartitionDesc	partdesc = RelationGetPartitionDesc(relation);
 	PartitionBoundInfo	boundinfo = partdesc->boundinfo;
 
-	Assert(partclauses != NIL);
+	/* All partitions match if there are no clauses */
+	if (!partclauses)
+		return bms_add_range(NULL, 0, partdesc->nparts - 1);
+
+	/* Some functions called below modify this list */
+	clauses = list_copy(partclauses);
 
 	/*
 	 * If relation is a partition itself, add its partition constraint
@@ -1719,19 +1721,17 @@ get_partitions_from_clauses(Relation relation, int rt_index,
 	 * set of selected partitions for a query whose clauses select a key space
 	 * bigger than the partition's.
 	 */
-	if (partition_bound_has_default(boundinfo) &&
-		(partconstr = RelationGetPartitionQual(relation)) != NIL)
+	if (partition_bound_has_default(boundinfo))
 	{
-		partconstr = (List *) expression_planner((Expr *) partconstr);
+		List *partqual = RelationGetPartitionQual(relation);
 
-		/* Be careful not to modify the input list. */
-		partclauses = list_concat(list_copy(partclauses), partconstr);
-	}
+		partqual = (List *) expression_planner((Expr *) partqual);
 
-	result = get_partitions_from_clauses_recurse(relation, rt_index,
-												 partclauses);
+		clauses = list_concat(clauses, partqual);
+	}
 
-	return result;
+	return get_partitions_from_clauses_recurse(relation, rt_index,
+											   clauses);
 }
 
 /* Module-local functions */
@@ -1771,29 +1771,35 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
 			return NULL;
 
 		result = get_partitions_for_keys(relation, &keys);
+
+		/*
+		 * No point in trying to look at other conjunctive clauses, if we got
+		 * an empty set in the first place.
+		 */
+		if (bms_is_empty(result))
+			return NULL;
 	}
 	else
 	{
+		/*
+		 * We found nothing useful to indicate which partitions might need to
+		 * be scanned.  Perhaps we'll find something below that indicates
+		 * which ones won't need to be scanned.
+		 */
 		PartitionDesc partdesc = RelationGetPartitionDesc(relation);
 
 		result = bms_add_range(NULL, 0, partdesc->nparts - 1);
 	}
 
-	/*
-	 * No point in trying to look at other conjunctive clauses, if we got
-	 * an empty set in the first place.
-	 */
-	if (bms_is_empty(result))
-		return NULL;
-
 	/* Select partitions by applying the clauses containing <> operators. */
 	if (ne_clauses)
 	{
 		Bitmapset *ne_clause_parts;
 
-		ne_clause_parts = get_partitions_excluded_by(relation, ne_clauses);
+		ne_clause_parts = get_partitions_excluded_by_ne_clauses(relation,
+																ne_clauses);
 
-		/* Remove any matched partitions */
+		/* Remove any partitions we found to not be needed */
 		result = bms_del_members(result, ne_clause_parts);
 		bms_free(ne_clause_parts);
 	}
@@ -1820,14 +1826,14 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
 }
 
 /*
- * get_partitions_excluded_by
+ * get_partitions_excluded_by_ne_clauses
  *
  * Returns a Bitmapset of partition indexes of any partition that can safely
  * be removed due to 'ne_clauses' containing not-equal clauses for all
  * possible values that the partition can contain.
  */
 static Bitmapset *
-get_partitions_excluded_by(Relation relation, List *ne_clauses)
+get_partitions_excluded_by_ne_clauses(Relation relation, List *ne_clauses)
 {
 	ListCell	   *lc;
 	Bitmapset	   *excluded_parts = NULL;
@@ -1979,45 +1985,47 @@ get_partitions_from_or_clause_args(Relation relation, int rt_index,
 
 /* Match partition key (partattno/partexpr) to an expression (expr). */
 #define EXPR_MATCHES_PARTKEY(expr, partattno, partexpr) \
-		((partattno) != 0 ?\
-		 (IsA((expr), Var) &&\
-		 ((Var *) (expr))->varattno == (partattno)) :\
+		((partattno) != 0 ? \
+		 (IsA((expr), Var) && \
+		 ((Var *) (expr))->varattno == (partattno)) : \
 		 equal((expr), (partexpr)))
 
+#define COLLATION_MATCH(partcoll, exprcoll) \
+	(!OidIsValid(partcoll) || (partcoll) == (exprcoll))
+
 /*
  * classify_partition_bounding_keys
- *		Analyzes partition clauses to collect the equality key or minimum and
- *		maximum bounding keys using which to look up partitions of relation.
- *		Also collects information about the nullness of the individual
- *		partition key columns as the partitions may have certain properties
- *		with respect to null values.  Keys and nullness information are stored
- *		in the output argument *keys.
+ *		Analyzes 'clauses' clauses to collect the equality key, minimum,
+ *		maximum bounding keys.  We also collect nullability properties along
+ *		the way.  All these are then used to determine the minimum set of
+ *		partitions that need to be scanned to find all records matching
+ *		the clause list.
  *
- * Clauses in the provided list are assumed to be implicitly ANDed, each of
- * which is known to match some partition key column.  They're mapped to the
- * individual key columns and for each column, we find constant values that
- * are compared to the column using operators that are compatible with
- * partitioning.  For example, if there is a clause a = 4 where a is a
- * partition key column, then 4 is stored as the equality key if = is
- * partitioning equality operator.  If there are clauses a > 1 and a < 5, then
- * 1 and 5 are stored as the minimum and maximum bounding keys, if > and < are
- * partitioning less and greater operators, respectively.  If there are
- * multiple clauses addressing a given column, we first try to check if they
- * are mutually contradictory and set *constfalse if so.  For example, if there
- * are clauses a = 1 and a = 2 in the list, then clearly both will never be
- * true.  Similarly for a > 1 and a < 0.  For clauses containing ordering
+ * Clauses found to match a partition are are analyzed to determine if the
+ * clause is useful for partition elimination.  For this to work the value
+ * being compared to the partition key must be a known value, e.g. a Const.
+ * We attempt to determine the narrowest range of values that will match by
+ * collecting and storing values that further narrow the range of the possible
+ * partitions to scan.  For example, if x is a partition key and we see a
+ * clause such as x = 4, 4 is stored as the equality key if = is partitioning
+ * equality operator.  If there are clauses x > 1 and x < 5, then 1 and 5 are
+ * stored as the minimum and maximum bounding keys, respectively, providing
+ * that > and < are partitioning less and greater operators,  If there are
+ * multiple clauses matching a given column, we first try to check if they are
+ * mutually contradictory and, if so set *constfalse to true.  For example, if
+ * there are clauses x = 1 and x = 2 in the list, then clearly both will never
+ * be true.  Similarly for x > 1 and x < 0.  For clauses containing ordering
  * operators that are non-contradictory, we try to find the one that is the
- * most restrictive and discard others.  For example, of a > 1, a > 2, and
- * a >= 5, the last one is the most restrictive and so 5 is the best minimum
+ * most restrictive and discard others.  For example, of x > 1, x > 2, and
+ * x >= 5, the last one is the most restrictive and so 5 is the best minimum
  * bound (which also happens to be inclusive), so it is kept while discarding
- * both a > 1 and a > 2.
+ * both x > 1 and x > 2.
  *
- * For multi-column keys, an equality key needs to contain values corresponding
- * to *all* partition key columns in the range patitioning case, whereas it's
- * not necessary for hash partitioning.  Actually, the latter requires that
- * the remaining columns are covered by IS NULL clauses, but that's not checked
- * in this function.  Minimum and maximum bound keys are allowed to contain
- * values for only a prefix partition key columns.
+ * For RANGE partitioning we do not need to match all partition keys. We may
+ * be able to eliminate some partitions with just a prefix of the partition
+ * keys. HASH partitioning does require all keys are matched to with at least
+ * some combinations of equality clauses and IS NULL clauses. LIST partitions
+ * don't support multiple partition keys.
  *
  * Certain kinds of clauses are not immediately handled within this function
  * and are instead returned to the caller for further processing.  That
@@ -2025,10 +2033,10 @@ get_partitions_from_or_clause_args(Relation relation, int rt_index,
  * generated from ScalarArrayOpExpr clauses in the input list that have useOr
  * set to true), which are returned to the caller in *or_clauses and clauses
  * containing a <> operator (whose negator is a valid *list* partitioning
- * equality operator), which are returned to the caller to in *ne_clauses.
+ * equality operator), which are returned to the caller via *ne_clauses.
  *
- * True is returned if *keys contains valid information upon return or if
- * *constfalse is set to true.
+ * True is returned if *keys contains use information and also if *constfalse
+ * has been set to true.
  */
 static bool
 classify_partition_bounding_keys(Relation relation, List *clauses,
@@ -2048,7 +2056,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 	bool	need_next_eq,
 			need_next_min,
 			need_next_max;
-	int		n_keynullness = 0;
+	bool	got_nullcheck = false;
 
 	*or_clauses = NIL;
 	*ne_clauses = NIL;
@@ -2097,22 +2105,21 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 		{
 			Oid		partopfamily = partkey->partopfamily[i];
 			AttrNumber	partattno = partkey->partattrs[i];
+			Oid		partcoll = partkey->partcollation[i];
 			Expr *partexpr = NULL;
 			PartClause *pc;
+			Oid commutator = InvalidOid;
 
 			/*
-			 * A non-zero partattno refers to a simple column reference that
-			 * will be matched against varattno of a Var appearing the clause.
-			 * partattno == 0 refers to arbitrary expressions, which get the
-			 * current one from PartitionKey.
+			 * A zero attno means the partition key is an expression, so grab
+			 * the next expression from the list.
 			 */
 			if (partattno == 0)
 			{
 				if (partexprs_item == NULL)
 					elog(ERROR, "wrong number of partition key expressions");
 
-				/* Copy to avoid overwriting the relcache's content. */
-				partexpr = copyObject(lfirst(partexprs_item));
+				partexpr = (Expr *) lfirst(partexprs_item);
 
 				/*
 				 * Expressions stored in PartitionKey in the relcache all
@@ -2121,7 +2128,11 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				 * correctly matched to the expressions coming from the query.
 				 */
 				if (rt_index != 1)
+				{
+					/* make a copy so as now to overwrite the relcache */
+					partexpr = (Expr *) copyObject(partexpr);
 					ChangeVarNodes((Node *) partexpr, 1, rt_index, 0);
+				}
 
 				partexprs_item = lnext(partexprs_item);
 			}
@@ -2140,15 +2151,43 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				rightop = (Expr *) get_rightop(clause);
 				if (IsA(rightop, RelabelType))
 					rightop = ((RelabelType *) rightop)->arg;
+
+				/* check if the clause matches the partition key */
 				if (EXPR_MATCHES_PARTKEY(leftop, partattno, partexpr))
 					constexpr = rightop;
 				else if (EXPR_MATCHES_PARTKEY(rightop, partattno, partexpr))
+				{
 					constexpr = leftop;
+
+					commutator = get_commutator(opclause->opno);
+
+					/* nothing we can do unless we can swap the operands */
+					if (!OidIsValid(commutator))
+						continue;
+				}
 				else
 					/* Clause does not match this partition key. */
 					continue;
 
 				/*
+				 * Also, useless, if the clause's collation is different from
+				 * the partitioning collation.
+				 */
+				if (!COLLATION_MATCH(partcoll, opclause->inputcollid))
+					continue;
+
+				/*
+				 * Only allow strict operators.  This will guarantee nulls are
+				 * filtered.
+				 */
+				if (!op_strict(opclause->opno))
+					continue;
+
+				/* Useless if the "constant" can change its value. */
+				if (contain_volatile_functions((Node *) constexpr))
+					continue;
+
+				/*
 				 * Handle cases where the clause's operator does not belong to
 				 * the partitioning operator family.  We currently handle two
 				 * such cases: 1. Operators named '<>' are not listed in any
@@ -2190,30 +2229,23 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 						continue;
 				}
 
-				pc = palloc0(sizeof(PartClause));
+				pc = (PartClause *) palloc0(sizeof(PartClause));
 				pc->constarg = constexpr;
 
 				/*
-				 * Flip the left and right args if we have to, because the
-				 * code which extract the constant value to use for
-				 * partition-pruning expects to find it as the rightop of the
-				 * clause.  (See below in this function.)
+				 * If commutator is set to a valid Oid then we'll need to swap
+				 * the left and right operands.  Later code requires that the
+				 * partkey is on the left side.
 				 */
-				if (constexpr == rightop)
+				if (!OidIsValid(commutator))
 					pc->op = opclause;
 				else
 				{
 					OpExpr   *commuted;
-					Oid		  commutator = get_commutator(opclause->opno);
 
-					/*
-					 * Caller must have made sure to check that the commutator
-					 * indeed exists.
-					 */
-					Assert(OidIsValid(commutator));
 					commuted = (OpExpr *) copyObject(opclause);
 					commuted->opno = commutator;
-					commuted->opfuncid = get_opcode(commuted->opno);
+					commuted->opfuncid = get_opcode(commutator);
 					commuted->args = list_make2(rightop, leftop);
 					pc->op = commuted;
 				}
@@ -2221,7 +2253,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				/*
 				 * We don't turn a <> operator clause into a key right away.
 				 * Instead, the caller will hand over such clauses to
-				 * get_partitions_excluded_by().
+				 * get_partitions_excluded_by_ne_clauses().
 				 */
 				if (is_ne_listp)
 					*ne_clauses = lappend(*ne_clauses, pc);
@@ -2255,13 +2287,32 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				ListCell *lc1;
 				bool	negated = false;
 
-				/* Clause does not match this partition key. */
 				if (IsA(leftop, RelabelType))
 					leftop = ((RelabelType *) leftop)->arg;
+
+				/* Check it matches this partition key */
 				if (!EXPR_MATCHES_PARTKEY(leftop, partattno, partexpr))
 					continue;
 
 				/*
+				 * Also, useless, if the clause's collation is different from
+				 * the partitioning collation.
+				 */
+				if (!COLLATION_MATCH(partcoll, saop->inputcollid))
+					continue;
+
+				/*
+				 * Only allow strict operators.  This will guarantee null are
+				 * filtered.
+				 */
+				if (!op_strict(saop->opno))
+					continue;
+
+				/* Useless if the array has any volatile functions. */
+				if (contain_volatile_functions((Node *) rightop))
+					continue;
+
+				/*
 				 * In case of NOT IN (..), we get a '<>', which while not
 				 * listed as part of any operator family, we are able to
 				 * handle it if its negator is indeed a part of the
@@ -2343,10 +2394,10 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				elem_clauses = NIL;
 				foreach(lc1, elem_exprs)
 				{
-					Const  *rightop = castNode(Const, lfirst(lc1));
+					Expr *rightop = (Expr *) lfirst(lc1);
 					Expr   *elem_clause;
 
-					if (rightop->constisnull)
+					if (IsA(rightop, Const) && ((Const *) rightop)->constisnull)
 					{
 						NullTest *nulltest = makeNode(NullTest);
 
@@ -2399,6 +2450,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				{
 					if (nulltest->nulltesttype == IS_NULL)
 					{
+						/* check for conflicting IS NOT NULLs */
 						if (bms_is_member(i, keyisnotnull))
 						{
 							*constfalse = true;
@@ -2407,8 +2459,17 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 						keyisnull = bms_add_member(keyisnull, i);
 					}
 					else
+					{
+						/* check for conflicting IS NULLs */
+						if (bms_is_member(i, keyisnull))
+						{
+							*constfalse = true;
+							return true;
+						}
+
 						keyisnotnull = bms_add_member(keyisnotnull, i);
-					n_keynullness++;
+					}
+					got_nullcheck = true;
 					will_compute_keys = true;
 				}
 			}
@@ -2431,9 +2492,15 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				{
 					BooleanTest *btest = (BooleanTest *) clause;
 
+					/* Only IS [NOT] TRUE/FALSE are any good to us */
+					if (btest->booltesttype == IS_UNKNOWN ||
+						btest->booltesttype == IS_NOT_UNKNOWN)
+						continue;
+
 					leftop = btest->arg;
 					if (IsA(leftop, RelabelType))
 						leftop = ((RelabelType *) leftop)->arg;
+
 					/* Clause does not match this partition key. */
 					if (!EXPR_MATCHES_PARTKEY(leftop, partattno, partexpr))
 						continue;
@@ -2450,6 +2517,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 								: (Expr *) get_notclausearg((Expr *) clause);
 					if (IsA(leftop, RelabelType))
 						leftop = ((RelabelType *) leftop)->arg;
+
 					/* Clause does not match this partition key. */
 					if (!EXPR_MATCHES_PARTKEY(leftop, partattno, partexpr))
 						continue;
@@ -2616,7 +2684,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 	keys->keyisnotnull = keyisnotnull;
 
 	return (keys->n_eqkeys > 0	|| keys->n_minkeys > 0 ||
-			keys->n_maxkeys > 0	|| n_keynullness > 0);
+			keys->n_maxkeys > 0	|| got_nullcheck);
 }
 
 /*
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e7c7a6e..51648c8 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -858,54 +858,24 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 
 /*
  * get_append_rel_partitions
- *		Return the list of partitions of rel that pass the clauses mentioned
- *		in rel->baserestrictinfo.  An empty list is returned if no matching
- *		partitions were found.
- *
- * Returned list contains the AppendRelInfos of chosen partitions.
+ *		Returns a List of AppendRelInfo belonging to the minimum set of
+ *		partitions which must be scanned to satisfy rel's baserestrictinfo
+ *		quals.
  */
 static List *
 get_append_rel_partitions(PlannerInfo *root,
 						  RelOptInfo *rel,
 						  RangeTblEntry *rte)
 {
-	List   *partclauses;
-	bool	contains_const,
-			constfalse;
-	List   *result = NIL;
-	int		i;
-	Relation		parent;
-	PartitionDesc	partdesc;
+	Relation		partrel;
 	Bitmapset	   *partindexes;
+	List		   *result = NIL;
+	int				i;
 
-	/*
-	 * Get the clauses that match the partition key.  It's also a good idea
-	 * to check if the matched clauses contain constant values that can be
-	 * used for pruning and go to get_partitions_from_clauses() only if so.
-	 * If rel->baserestrictinfo might contain mutually contradictory clauses,
-	 * also find out about that.
-	 */
-	partclauses = match_clauses_to_partkey(root, rel, rel->baserestrictinfo,
-										   &contains_const, &constfalse);
+	partrel = heap_open(rte->relid, NoLock);
 
-	/* We're done here. */
-	if (constfalse)
-		return NIL;
-
-	parent = heap_open(rte->relid, NoLock);
-	partdesc = RelationGetPartitionDesc(parent);
-
-	if (partclauses != NIL && contains_const)
-		partindexes = get_partitions_from_clauses(parent, rel->relid,
-												  partclauses);
-	else
-	{
-		/*
-		 * There are no clauses that are useful to prune any partitions, so
-		 * scan all partitions.
-		 */
-		partindexes = bms_add_range(NULL, 0, partdesc->nparts - 1);
-	}
+	partindexes = get_partitions_from_clauses(partrel, rel->relid,
+											  rel->baserestrictinfo);
 
 	/* Fetch the partition appinfos. */
 	i = -1;
@@ -914,328 +884,22 @@ get_append_rel_partitions(PlannerInfo *root,
 		AppendRelInfo *appinfo = rel->part_appinfos[i];
 
 #ifdef USE_ASSERT_CHECKING
-		RangeTblEntry *rte = planner_rt_fetch(appinfo->child_relid, root);
+		PartitionDesc	partdesc = RelationGetPartitionDesc(partrel);
+		RangeTblEntry   *childrte;
+
+		childrte = planner_rt_fetch(appinfo->child_relid, root);
 
 		/*
 		 * Must be the intended child's RTE here, because appinfos are ordered
 		 * the same way as partitions in the partition descriptor.
 		 */
-		Assert(partdesc->oids[i] == rte->relid);
+		Assert(partdesc->oids[i] == childrte->relid);
 #endif
+
 		result = lappend(result, appinfo);
 	}
 
-	heap_close(parent, NoLock);
-
-	return result;
-}
-
-#define PartCollMatchesExprColl(partcoll, exprcoll) \
-	((partcoll) == InvalidOid || (partcoll) == (exprcoll))
-
-/*
- * match_clauses_to_partkey
- *		Match clauses with rel's partition key
- *
- * Returned list contains clauses matched to the partition key columns and
- * *contains_const and *constfalse are set as described below.
- *
- * For an individual clause to match with a partition key column, the clause
- * must be an operator clause of the form (partkey op const) or (const op
- * partkey); the latter only if a suitable commutator exists.  Furthermore,
- * the operator must be strict and its input collation must match the partition
- * collation.  The aforementioned "const" means any expression that doesn't
- * involve a volatile function or a Var of this relation.  We allow Vars
- * belonging to other relations (for example, if the clause is a join clause),
- * but they are treated as parameters whose values are not known now, so cannot
- * be used for partition pruning right within the planner.  It's the
- * responsibility of higher code levels to manage restriction and join clauses
- * appropriately.  If a NullTest against a partition key is encountered, it's
- * added to the result as well.
- *
- * *contains_const is set if at least one matched clauses contains the constant
- * operand or is a Nullness test.  *constfalse is set if the input list
- * contains a pseudo-constant RestrictInfo with false value.
- */
-static List *
-match_clauses_to_partkey(PlannerInfo *root,
-						 RelOptInfo *rel,
-						 List *clauses,
-						 bool *contains_const,
-						 bool *constfalse)
-{
-	PartitionScheme	partscheme = rel->part_scheme;
-	List	   *result = NIL;
-	ListCell   *lc;
-
-	*contains_const = false;
-	*constfalse = false;
-
-	Assert (partscheme != NULL);
-
-	/* Make a copy, because we may scribble on it below. */
-	clauses = list_copy(clauses);
-
-	foreach(lc, clauses)
-	{
-		Node   *member = lfirst(lc);
-		Expr   *clause;
-		int		i;
-
-		if (IsA(member, RestrictInfo))
-		{
-			RestrictInfo *rinfo = (RestrictInfo *) member;
-
-			clause = rinfo->clause;
-			if (rinfo->pseudoconstant &&
-				(IsA(clause, Const) &&
-				 ((((Const *) clause)->constisnull) ||
-				  !DatumGetBool(((Const *) clause)->constvalue))))
-			{
-				*constfalse = true;
-				return NIL;
-			}
-		}
-		else
-			clause = (Expr *) member;
-
-		/*
-		 * For a BoolExpr, we should try to match each of its args with the
-		 * partition key as described below for each type.
-		 */
-		if (IsA(clause, BoolExpr))
-		{
-			if (or_clause((Node *) clause))
-			{
-				/*
-				 * For each of OR clause's args, call this function
-				 * recursively with a given arg as the only member in the
-				 * input list and see if it's returned as matching the
-				 * partition key.  Add the OR clause to the result iff at
-				 * least one of its args contain a matching clause.
-				 */
-				BoolExpr *orclause = (BoolExpr *) clause;
-				ListCell *lc1;
-				bool	arg_matches_key = false,
-						matched_arg_contains_const = false,
-						all_args_constfalse = true;
-
-				foreach (lc1, orclause->args)
-				{
-					Node   *arg = lfirst(lc1);
-					bool	contains_const1,
-							constfalse1;
-
-					if (match_clauses_to_partkey(root, rel, list_make1(arg),
-												 &contains_const1,
-												 &constfalse1) != NIL)
-					{
-						arg_matches_key = true;
-						matched_arg_contains_const = contains_const1;
-					}
-
-					/* We got at least one arg that is not constant false. */
-					if (!constfalse1)
-						all_args_constfalse = false;
-				}
-
-				if (arg_matches_key)
-				{
-					result = lappend(result, clause);
-					*contains_const = matched_arg_contains_const;
-				}
-
-				/* OR clause is "constant false" if all of its args are. */
-				*constfalse = all_args_constfalse;
-				continue;
-			}
-			else if (and_clause((Node *) clause))
-			{
-				/*
-				 * Since the clause is itself implicitly ANDed with other
-				 * clauses in the input list, queue the args to be processed
-				 * later as if they were part of the original input list.
-				 */
-				clauses = list_concat(clauses,
-									  list_copy(((BoolExpr *) clause)->args));
-				continue;
-			}
-
-			/* Fall-through for a NOT clause, which is handled below. */
-		}
-
-		for (i = 0; i < partscheme->partnatts; i++)
-		{
-			Node   *partkey = linitial(rel->partexprs[i]);
-			Oid		partopfamily = partscheme->partopfamily[i],
-					partcoll = partscheme->partcollation[i];
-
-			/*
-			 * Check if the clauses matches the partition key and add it to
-			 * the result list if other things such as operator input
-			 * collation, strictness, etc. look fine.
-			 */
-			if (is_opclause(clause))
-			{
-				Expr   *constexpr,
-					   *leftop,
-					   *rightop;
-				Relids	constrelids;
-				Oid		expr_op,
-						expr_coll;
-
-				leftop = (Expr *) get_leftop(clause);
-				rightop = (Expr *) get_rightop(clause);
-				expr_op = ((OpExpr *) clause)->opno;
-				expr_coll = ((OpExpr *) clause)->inputcollid;
-
-				if (IsA(leftop, RelabelType))
-					leftop = ((RelabelType *) leftop)->arg;
-				if (IsA(rightop, RelabelType))
-					rightop = ((RelabelType *) rightop)->arg;
-
-				if (equal(leftop, partkey))
-				{
-					constexpr = rightop;
-					constrelids = pull_varnos((Node *) rightop);
-				}
-				else if (equal(rightop, partkey))
-				{
-					constexpr = leftop;
-					constrelids = pull_varnos((Node *) leftop);
-					expr_op = get_commutator(expr_op);
-
-					/*
-					 * If no commutator exists, cannot flip the qual's args,
-					 * so give up.
-					 */
-					if (!OidIsValid(expr_op))
-						continue;
-				}
-				else
-					/* Neither argument matches the partition key. */
-					continue;
-
-				/*
-				 * Useless if what we're thinking of as a constant is actually
-				 * a Var coming from this relation.
-				 */
-				if (bms_is_member(rel->relid, constrelids))
-					continue;
-
-				/*
-				 * Also, useless, if the clause's collation is different from
-				 * the partitioning collation.
-				 */
-				if (!PartCollMatchesExprColl(partcoll, expr_coll))
-					continue;
-
-				/*
-				 * Only allow strict operators to think sanely about the
-				 * behavior with null arguments.
-				 */
-				if (!op_strict(expr_op))
-					continue;
-
-				/* Useless if the "constant" can change its value. */
-				if (contain_volatile_functions((Node *) constexpr))
-					continue;
-
-				/*
-				 * Everything seems to be fine, so add it to the list of
-				 * clauses we will use for pruning.
-				 */
-				result = lappend(result, clause);
-
-				if (!*contains_const)
-					*contains_const = IsA(constexpr, Const);
-			}
-			else if (IsA(clause, ScalarArrayOpExpr))
-			{
-				ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
-				Oid		saop_op = saop->opno;
-				Oid		saop_coll = saop->inputcollid;
-				Node   *leftop = (Node *) linitial(saop->args),
-					   *rightop = (Node *) lsecond(saop->args);
-
-				if (IsA(leftop, RelabelType))
-					leftop = (Node *) ((RelabelType *) leftop)->arg;
-				if (!equal(leftop, partkey))
-					continue;
-
-				/* Check if saop_op is compatible with partitioning. */
-				if (!op_strict(saop_op))
-					continue;
-
-				/* Useless if the "constant" can change its value. */
-				if (contain_volatile_functions((Node *) rightop))
-					continue;
-
-				/*
-				 * Also, useless, if the clause's collation is different from
-				 * the partitioning collation.
-				 */
-				if (!PartCollMatchesExprColl(partcoll, saop_coll))
-					continue;
-
-				/* OK to add to the result. */
-				result = lappend(result, clause);
-				if (IsA(eval_const_expressions(root, rightop), Const))
-					*contains_const = true;
-				else
-					*contains_const = false;
-			}
-			else if (IsA(clause, NullTest))
-			{
-				NullTest   *nulltest = (NullTest *) clause;
-				Node	   *arg = (Node *) nulltest->arg;
-
-				if (equal(arg, partkey))
-				{
-					result = lappend(result, nulltest);
-					/* A Nullness test can be used right away. */
-					*contains_const = true;
-				}
-			}
-			/*
-			 * Certain Boolean conditions have a special shape, which we
-			 * accept if the partitioning opfamily accepts Boolean conditions.
-			 */
-			else if (IsBooleanOpfamily(partopfamily) &&
-					 (IsA(clause, BooleanTest) ||
-					  IsA(clause, Var) || not_clause((Node *) clause)))
-			{
-				/*
-				 * Only accept those for pruning that appear to be
-				 * IS [NOT] TRUE/FALSE.
-				 */
-				if (IsA(clause, BooleanTest))
-				{
-					BooleanTest *btest = (BooleanTest *) clause;
-					Expr   *arg = btest->arg;
-
-					if (btest->booltesttype != IS_UNKNOWN &&
-						btest->booltesttype != IS_NOT_UNKNOWN &&
-						equal((Node *) arg, partkey))
-						result = lappend(result, clause);
-				}
-				else if (IsA(clause, Var))
-				{
-					if (equal((Node *) clause, partkey))
-						result = lappend(result, clause);
-				}
-				else
-				{
-					Node   *arg = (Node *) get_notclausearg((Expr *) clause);
-
-					if (equal(arg, partkey))
-						result = lappend(result, clause);
-				}
-
-				*contains_const = true;
-			}
-		}
-	}
+	heap_close(partrel, NoLock);
 
 	return result;
 }
