diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 974febb..10124d3 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;
@@ -195,49 +195,64 @@ typedef enum PartOpStrategy
 } PartOpStrategy;
 
 /*
+ */
+typedef struct PartScanClauseInfo
+{
+	/* Lists of clauses indexed by partition key */
+	List   *clauses[PARTITION_MAX_KEYS];
+
+	List   *or_clauses; /* List of clauses found in an OR branch */
+	List   *ne_clauses; /* Clauses in the form partkey <> Expr */
+
+	Bitmapset   *keyisnull;
+	Bitmapset   *keyisnotnull;
+
+	/* Stored data is known to contain impossible contradictions */
+	bool	constfalse;
+} PartScanClauseInfo;
+
+/*
  * PartScanKeyInfo
  *		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 cached 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,17 +308,15 @@ 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,
-								 int rt_index,
-								 PartScanKeyInfo *keys, bool *constfalse,
-								 List **or_clauses, List **ne_clauses);
-static void remove_redundant_clauses(PartitionKey partkey,
-						 int partkeyidx, List *all_clauses,
-						 List **result, bool *constfalse);
+static bool extract_partition_key_clauses(PartitionKey partkey, List *clauses,
+							  int rt_index, PartScanClauseInfo *partclauses);
+static bool extract_bounding_datums(PartitionKey partkey,
+						PartScanClauseInfo *partclauses,
+						PartScanKeyInfo *keys);
 static bool partition_cmp_args(PartitionKey key, int partkeyidx,
 				   PartClause *op, PartClause *leftarg, PartClause *rightarg,
 				   bool *result);
@@ -311,6 +324,8 @@ static PartOpStrategy partition_op_strategy(PartitionKey key, PartClause *op,
 					bool *incl);
 static bool partkey_datum_from_expr(PartitionKey key, int partkeyidx,
 						Expr *expr, Datum *value);
+static void remove_redundant_clauses(PartitionKey partkey,
+						 PartScanClauseInfo *partclauses);
 static Bitmapset *get_partitions_for_keys(Relation rel,
 						PartScanKeyInfo *keys);
 static Bitmapset *get_partitions_for_keys_hash(Relation rel,
@@ -1692,25 +1707,30 @@ 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;
-	PartitionDesc	partdesc = RelationGetPartitionDesc(relation);
-	PartitionBoundInfo	boundinfo = partdesc->boundinfo;
+	PartitionDesc		partdesc = RelationGetPartitionDesc(relation);
+	PartitionBoundInfo	boundinfo;
+	List			   *clauses;
 
-	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);
+	boundinfo = partdesc->boundinfo;
 
 	/*
-	 * If relation is a partition itself, add its partition constraint
+	 * If relation is a sub-partitioned table, add its partition constraint
 	 * clauses to the list of clauses to use for partition pruning.  This
 	 * is done to facilitate correct decision regarding the default
 	 * partition.  Adding the partition constraint clauses to the list helps
@@ -1719,19 +1739,20 @@ 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);
+		/* Fix Vars to have the desired varno */
+		if (rt_index != 1)
+			ChangeVarNodes((Node *) partqual, 1, rt_index, 0);
 
-	return result;
+		clauses = list_concat(clauses, partqual);
+	}
+
+	return get_partitions_from_clauses_recurse(relation, rt_index, clauses);
 }
 
 /* Module-local functions */
@@ -1747,59 +1768,75 @@ static Bitmapset *
 get_partitions_from_clauses_recurse(Relation relation, int rt_index,
 									List *clauses)
 {
-	Bitmapset *result;
-	PartScanKeyInfo keys;
-	bool	constfalse;
-	List *or_clauses,
-		 *ne_clauses;
+	PartitionDesc		partdesc = RelationGetPartitionDesc(relation);
+	PartitionKey		partkey	= RelationGetPartitionKey(relation);
+	PartScanClauseInfo	partclauses;
+	Bitmapset 		   *result;
+	PartScanKeyInfo		keys;
 	ListCell *lc;
 
-	/*
-	 * Try to reduce the set of clauses into a form that
-	 * get_partitions_for_keys() can work with.
-	 */
-	if (classify_partition_bounding_keys(relation, clauses, rt_index,
-										 &keys, &constfalse,
-										 &or_clauses, &ne_clauses))
+	/* Populate partclauses from the clause list */
+	if (extract_partition_key_clauses(partkey, clauses, rt_index, &partclauses))
 	{
 		/*
-		 * classify_partition_bounding_keys() may have found clauses marked
-		 * pseudo-constant that are false that the planner didn't or it may
-		 * have itself found contradictions among clauses.
+		 * No partitions to scan if extract_partition_key_clauses found some
+		 * clause contradiction.
 		 */
-		if (constfalse)
+		if (partclauses.constfalse)
+			return NULL;
+
+		/* collapse clauses down to the most restrictive set */
+		remove_redundant_clauses(partkey, &partclauses);
+
+		/* Did remove_redundant_clauses find any contradicting clauses? */
+		if (partclauses.constfalse)
 			return NULL;
 
-		result = get_partitions_for_keys(relation, &keys);
+		if (extract_bounding_datums(partkey, &partclauses, &keys))
+		{
+			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.
+			 */
+			result = bms_add_range(NULL, 0, partdesc->nparts - 1);
+		}
 	}
 	else
 	{
-		PartitionDesc partdesc = RelationGetPartitionDesc(relation);
-
+		/*
+		 * no useful key clauses found, but we might still be able to
+		 * eliminate some partitions with ne_clauses or or_clauses.
+		*/
 		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)
+	if (partclauses.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,
+													partclauses.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);
 	}
 
 	/* Select partitions by applying OR clauses. */
-	foreach(lc, or_clauses)
+	foreach(lc, partclauses.or_clauses)
 	{
 		BoolExpr *or = (BoolExpr *) lfirst(lc);
 		Bitmapset *or_parts;
@@ -1820,14 +1857,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;
@@ -1903,10 +1940,9 @@ get_partitions_excluded_by(Relation relation, List *ne_clauses)
 
 	/*
 	 * Now compare the counts and eliminate any partition for which we found
-	 * clauses for all its permitted values. We must be careful here not to
-	 * eliminate the default partition, but the condition below that we must
-	 * have found at least 1 datum will ensure that, because in the default
-	 * partition's case, both arrays will contain zero.
+	 * clauses for all its permitted values.  We must be careful here not to
+	 * eliminate the default partition.  We can recognize that by it having a
+	 * zero value in both arrays.
 	 */
 	for (i = 0; i < partdesc->nparts; i++)
 	{
@@ -1949,15 +1985,15 @@ get_partitions_from_or_clause_args(Relation relation, int rt_index,
 		Bitmapset *arg_partset;
 
 		/*
-		 * It's possible that this clause is never true for this relation
-		 * due to the latter's partition constraint, which means we must
-		 * not add its partitions to or_partset.  But the clause may not
-		 * contain this relation's partition key expressions (instead the
-		 * parent's), so we could not depend on just calling
-		 * get_partitions_from_clauses_recurse(relation, ...) to determine
-		 * that the clause indeed prunes all of the relation's partition.
-		 *
-		 * Use predicate refutation proof instead.
+		 * It's possible that this clause is never true for this relation due
+		 * to it contradicting the partition's constraint.  In this case we
+		 * must not include any partitions for this OR clause.  However, this
+		 * OR clause may not contain any quals matching this partition table's
+		 * partition key, it may contain some belonging to a parent partition
+		 * though, so we may not have all the quals here required to make use
+		 * of get_partitions_from_clauses_recurse to determine the correct set
+		 * of partitions, so we'll just make use of predicate_refuted_by
+		 * instead.
 		 */
 		if (partconstr)
 		{
@@ -1979,108 +2015,65 @@ 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.
- *
- * 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
- * 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
- * bound (which also happens to be inclusive), so it is kept while discarding
- * both a > 1 and a > 2.
+ * extract_partition_key_clauses
+ *		Process 'clauses' to extract clause matching the partition key.
+ *		This populates 'partclauses' with the set of clauses matching each
+ *		key also also collects other useful clauses to assist in partition
+ *		elimination, such as or clauses and not equal clauses. We also record
+ *		which partitions keys we can prove are NULL or NOT NULL.
  *
- * 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.
+ * We may also discover some contradition in the clauses which means that no
+ * partition can possibly match.  In this case the function sets partclauses's
+ * 'constfalse' to true and returns true.  In this case the caller should not
+ * assume the clauses have been fully processed as we abort as soon as we find
+ * a contradicting condition.
  *
- * Certain kinds of clauses are not immediately handled within this function
- * and are instead returned to the caller for further processing.  That
- * includes OR clauses (both those encountered in the input list and those
- * 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.
- *
- * True is returned if *keys contains valid information upon return or if
- * *constfalse is set to true.
+ * The function returns false if no useful key clauses were found.
  */
 static bool
-classify_partition_bounding_keys(Relation relation, List *clauses,
-								 int rt_index,
-								 PartScanKeyInfo *keys, bool *constfalse,
-								 List **or_clauses,
-								 List **ne_clauses)
+extract_partition_key_clauses(PartitionKey partkey, List *clauses,
+							  int rt_index,
+							  PartScanClauseInfo *partclauses)
 {
-	PartitionKey partkey = RelationGetPartitionKey(relation);
-	int		i;
-	ListCell *lc;
-	List   *keyclauses_all[PARTITION_MAX_KEYS],
-		   *keyclauses[PARTITION_MAX_KEYS];
-	bool	will_compute_keys = false;
-	Bitmapset *keyisnull = NULL,
-			  *keyisnotnull = NULL;
-	bool	need_next_eq,
-			need_next_min,
-			need_next_max;
-	int		n_keynullness = 0;
-
-	*or_clauses = NIL;
-	*ne_clauses = NIL;
-	*constfalse = false;
-	memset(keyclauses_all, 0, sizeof(keyclauses_all));
+	int			i;
+	ListCell   *lc;
+	bool		got_useful_keys = false;
+
+	memset(partclauses, 0, sizeof(PartScanClauseInfo));
 
 	foreach(lc, clauses)
 	{
-		Expr	   *clause;
+		Expr	   *clause = (Expr *) lfirst(lc);
 		ListCell   *partexprs_item;
 
-		if (IsA(lfirst(lc), RestrictInfo))
+		if (IsA(clause, RestrictInfo))
 		{
-			RestrictInfo *rinfo = lfirst(lc);
+			RestrictInfo *rinfo = (RestrictInfo *) clause;
 
 			clause = rinfo->clause;
 			if (rinfo->pseudoconstant &&
 				!DatumGetBool(((Const *) clause)->constvalue))
 			{
-				*constfalse = true;
+				partclauses->constfalse = true;
 				return true;
 			}
 		}
-		else
-			clause = (Expr *) lfirst(lc);
 
 		/* Get the BoolExpr's out of the way.*/
 		if (IsA(clause, BoolExpr))
 		{
 			if (or_clause((Node *) clause))
 			{
-				*or_clauses = lappend(*or_clauses, clause);
+				partclauses->or_clauses = lappend(partclauses->or_clauses, clause);
 				continue;
 			}
 			else if (and_clause((Node *) clause))
@@ -2097,31 +2090,33 @@ 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
-				 * contain a dummy varno (that is, 1), but we must switch to
-				 * the RT index of the table in this query so that it can be
-				 * correctly matched to the expressions coming from the query.
+				 * Expressions stored for the PartitionKey in the relcache are
+				 * all stored with the dummy varno of 1. Change that to what
+				 * we need.
 				 */
 				if (rt_index != 1)
+				{
+					/* make a copy so as not to overwrite the relcache */
+					partexpr = (Expr *) copyObject(partexpr);
 					ChangeVarNodes((Node *) partexpr, 1, rt_index, 0);
+				}
 
 				partexprs_item = lnext(partexprs_item);
 			}
@@ -2140,15 +2135,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 +2213,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,25 +2237,27 @@ 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);
+					partclauses->ne_clauses = lappend(partclauses->ne_clauses,
+													  pc);
 				else
 				{
-					keyclauses_all[i] = lappend(keyclauses_all[i], pc);
-					will_compute_keys = true;
+					partclauses->clauses[i] = lappend(partclauses->clauses[i], pc);
+					got_useful_keys = true;
 
 					/*
 					 * Since we only allow strict operators, require keys to
 					 * be not null.
 					 */
-					if (bms_is_member(i, keyisnull))
+					if (bms_is_member(i, partclauses->keyisnull))
 					{
-						*constfalse = true;
+						partclauses->constfalse = true;
 						return true;
 					}
-					keyisnotnull = bms_add_member(keyisnotnull, i);
+					partclauses->keyisnotnull =
+								bms_add_member(partclauses->keyisnotnull, i);
 				}
 			}
 			else if (IsA(clause, ScalarArrayOpExpr))
@@ -2248,20 +2266,39 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				Oid		saop_op = saop->opno;
 				Oid		saop_opfuncid = saop->opfuncid;
 				Oid		saop_coll = saop->inputcollid;
-				Expr   *leftop = linitial(saop->args),
-					   *rightop = lsecond(saop->args);
+				Expr   *leftop = (Expr *) linitial(saop->args),
+					   *rightop = (Expr *) lsecond(saop->args);
 				List   *elem_exprs,
 					   *elem_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 +2380,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);
 
@@ -2380,7 +2417,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				 * of the list that's being processed currently.
 				 */
 				if (saop->useOr)
-					*or_clauses = lappend(*or_clauses,
+					partclauses->or_clauses = lappend(partclauses->or_clauses,
 										  makeBoolExpr(OR_EXPR, elem_clauses,
 													   -1));
 				else
@@ -2399,17 +2436,28 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				{
 					if (nulltest->nulltesttype == IS_NULL)
 					{
-						if (bms_is_member(i, keyisnotnull))
+						/* check for conflicting IS NOT NULLs */
+						if (bms_is_member(i, partclauses->keyisnotnull))
 						{
-							*constfalse = true;
+							partclauses->constfalse = true;
 							return true;
 						}
-						keyisnull = bms_add_member(keyisnull, i);
+						partclauses->keyisnull =
+									bms_add_member(partclauses->keyisnull, i);
 					}
 					else
-						keyisnotnull = bms_add_member(keyisnotnull, i);
-					n_keynullness++;
-					will_compute_keys = true;
+					{
+						/* check for conflicting IS NULLs */
+						if (bms_is_member(i, partclauses->keyisnull))
+						{
+							partclauses->constfalse = true;
+							return true;
+						}
+
+						partclauses->keyisnotnull =
+								bms_add_member(partclauses->keyisnotnull, i);
+					}
+					got_useful_keys = true;
 				}
 			}
 			/*
@@ -2425,15 +2473,21 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 				Expr   *leftop,
 					   *rightop;
 
-				pc = palloc0(sizeof(PartClause));
+				pc = (PartClause *) palloc0(sizeof(PartClause));
 
 				if (IsA(clause, BooleanTest))
 				{
 					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 +2504,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;
@@ -2463,40 +2518,40 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 										   leftop, rightop,
 										   InvalidOid, InvalidOid);
 				pc->constarg = rightop;
-				keyclauses_all[i] = lappend(keyclauses_all[i], pc);
-				will_compute_keys = true;
+				partclauses->clauses[i] = lappend(partclauses->clauses[i],
+												  pc);
+				got_useful_keys = true;
 			}
 		}
 	}
 
-	/* Return if no work to do below. */
-	if (!will_compute_keys)
-		return false;
+	return got_useful_keys;
+}
 
-	/*
-	 * Try to eliminate redundant keys.  In the process, we might find out
-	 * that clauses are mutually contradictory and hence can never be true
-	 * for any rows.
-	 */
-	memset(keyclauses, 0, PARTITION_MAX_KEYS * sizeof(List *));
-	for (i = 0; i < partkey->partnatts; i++)
-	{
-		remove_redundant_clauses(partkey, i,
-								 keyclauses_all[i], &keyclauses[i],
-								 constfalse);
-		if (*constfalse)
-			return true;
-	}
+/*
+ * extract_bounding_datums
+ *		Process 'partclauses' and populate 'keys' with all min/max/equal values
+ *		that we're able to determine.
+ *
+ * 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.
+ *
+ * Returns true if any keys were found during partition pruning.
+ */
+static bool
+extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
+						PartScanKeyInfo *keys)
+{
+	bool		need_next_eq,
+				need_next_min,
+				need_next_max;
+	int i;
+	ListCell *lc;
 
 	/*
-	 * Generate bounding tuple(s).
-	 *
-	 * Eventually, callers will use a function like partition_bound_bsearch()
-	 * to look up partitions from the clauses we matched against individual
-	 * partition key columns.  Those function expect the lookup key to be in a
-	 * Datum array form, not a list-of-clauses form.  So, we must construct the
-	 * lookup key(s) by extracting constant values out the clauses.
-	 *
 	 * Based on the strategies of the clause operators (=, </<=, >/>=), try to
 	 * construct tuples of those datums that serve as the exact look up tuple
 	 * or tuples that serve as minimum and maximum bound.  If we find datums
@@ -2516,6 +2571,8 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 	memset(keys, 0, sizeof(PartScanKeyInfo));
 	for (i = 0; i < partkey->partnatts; i++)
 	{
+		List *clauselist = partclauses->clauses[i];
+
 		/*
 		 * Min and max keys must constitute a prefix of the partition key and
 		 * must appear in the same order as partition keys.  Equal keys have
@@ -2531,9 +2588,9 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 		if (i > keys->n_maxkeys)
 			need_next_max = false;
 
-		foreach(lc, keyclauses[i])
+		foreach(lc, clauselist)
 		{
-			PartClause *clause = lfirst(lc);
+			PartClause *clause = (PartClause *) lfirst(lc);
 			Expr *constarg = clause->constarg;
 			bool incl;
 			PartOpStrategy	op_strategy;
@@ -2612,11 +2669,12 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
 		keys->n_eqkeys = 0;
 
 	/* Finally, also set the keyisnull and keyisnotnull values. */
-	keys->keyisnull = keyisnull;
-	keys->keyisnotnull = keyisnotnull;
+	keys->keyisnull = partclauses->keyisnull;
+	keys->keyisnotnull = partclauses->keyisnotnull;
 
-	return (keys->n_eqkeys > 0	|| keys->n_minkeys > 0 ||
-			keys->n_maxkeys > 0	|| n_keynullness > 0);
+	return (keys->n_eqkeys > 0 || keys->n_minkeys > 0 ||
+			keys->n_maxkeys > 0 || !bms_is_empty(keys->keyisnull) ||
+			!bms_is_empty(keys->keyisnotnull));
 }
 
 /*
@@ -2732,235 +2790,264 @@ partkey_datum_from_expr(PartitionKey key, int partkeyidx,
 }
 
 /*
- * For a given partition key column, find the most restrictive of the clauses
- * contained in all_clauses that are known to match the column and add it to
- * *result.
+ * remove_redundant_clauses
+ *		Collapse the 'partclauses' clauses lists to remove clause which are
+ *		superseeded by a clause which is more restrictive.
+ *
+ * Here we perform further processing on 'partclauses' to remove any redundant
+ * clauses. We also look for clauses which contradict one another in a way
+ * that proves the 'partclauses' cannot possibly match any partition.
+ * Impossible clauses include things like: x = 1 AND x = 2, x > 0 and x < 10
  *
- * If it is found that two clauses are mutually contradictory, *constfalse
- * is set to true before returning.
+ * We also transform 'partclauses' into the minimum set of clauses by removing
+ * any clauses which are made redundant by a more restrictive clause. For
+ * example, x > 1 AND x > 2 and x >= 5, the latter is the most restrictive so
+ * 5 is the best minimum bound. The operator here also happens to be
+ * inclusive.
+ *
+ * If we find that two clauses contradict each other then 'partclauses'
+ * constfalse is set to true to alert the caller that nothing can match.
  */
 static void
-remove_redundant_clauses(PartitionKey partkey, int partkeyidx,
-						 List *all_clauses, List **result,
-						 bool *constfalse)
+remove_redundant_clauses(PartitionKey partkey,
+						 PartScanClauseInfo *partclauses)
 {
 	PartClause *hash_clause,
 			   *btree_clauses[BTMaxStrategyNumber];
 	ListCell *lc;
 	int		s;
+	int		i;
 	bool	test_result;
+	List   *newlist;
 
-	*result = NIL;
-
-	hash_clause = NULL;
-	memset(btree_clauses, 0, sizeof(btree_clauses));
-	foreach(lc, all_clauses)
+	for (i = 0; i < partkey->partnatts; i++)
 	{
-		PartClause *cur = lfirst(lc);
+		List *all_clauses = partclauses->clauses[i];
 
-		if (!cur->valid_cache)
-		{
-			Oid		lefttype;
-
-			get_op_opfamily_properties(cur->op->opno,
-									   partkey->partopfamily[partkeyidx],
-									   false,
-									   &cur->op_strategy,
-									   &lefttype,
-									   &cur->op_subtype);
-			fmgr_info(get_opcode(cur->op->opno), &cur->op_func);
-			cur->valid_cache = true;
-		}
+		hash_clause = NULL;
+		newlist = NIL;
 
-		/*
-		 * Hash-partitioning knows only about equality.  So, if we've matched
-		 * a clause and found another clause whose constant operand doesn't
-		 * match the constant operand of the former, then we have found
-		 * mutually contradictory clauses.
-		 */
-		if (partkey->strategy == PARTITION_STRATEGY_HASH)
+		memset(btree_clauses, 0, sizeof(btree_clauses));
+
+		foreach(lc, all_clauses)
 		{
-			if (hash_clause == NULL)
-				hash_clause = cur;
-			/* check if another clause would contradict the one we have */
-			else if (partition_cmp_args(partkey, partkeyidx,
-										cur, cur, hash_clause,
-										&test_result))
+			PartClause *cur = (PartClause *) lfirst(lc);
+
+			if (!cur->valid_cache)
 			{
-				if (!test_result)
-				{
-					*constfalse = true;
-					return;
-				}
+				Oid		lefttype;
+
+				get_op_opfamily_properties(cur->op->opno,
+										   partkey->partopfamily[i],
+										   false,
+										   &cur->op_strategy,
+										   &lefttype,
+										   &cur->op_subtype);
+				fmgr_info(get_opcode(cur->op->opno), &cur->op_func);
+				cur->valid_cache = true;
 			}
-			/*
-			 * Couldn't compare; keep hash_clause set to the previous value,
-			 * and add this one directly to the result.  Caller would
-			 * arbitrarily choose one of the many and perform
-			 * partition-pruning with it.
-			 */
-			else
-				*result = lappend(*result, cur);
 
 			/*
-			 * The code below handles btree operators, so not relevant for
-			 * hash partitioning.
+			 * Hash-partitioning knows only about equality.  So, if we've
+			 * matched a clause and found another clause whose constant
+			 * operand doesn't match the constant operand of the former, then
+			 * we have found mutually contradictory clauses.
 			 */
-			continue;
-		}
+			if (partkey->strategy == PARTITION_STRATEGY_HASH)
+			{
+				if (hash_clause == NULL)
+					hash_clause = cur;
+				/* check if another clause would contradict the one we have */
+				else if (partition_cmp_args(partkey, i,
+											cur, cur, hash_clause,
+											&test_result))
+				{
+					if (!test_result)
+					{
+						partclauses->constfalse = true;
+						return;
+					}
+				}
+				/*
+				 * Couldn't compare; keep hash_clause set to the previous value,
+				 * and add this one directly to the result.  Caller would
+				 * arbitrarily choose one of the many and perform
+				 * partition-pruning with it.
+				 */
+				else
+					newlist = lappend(newlist, cur);
+
+				/*
+				 * The code below handles btree operators, so not relevant for
+				 * hash partitioning.
+				 */
+				continue;
+			}
 
-		/*
-		 * The code that follows closely mimics similar processing done by
-		 * nbtutils.c: _bt_preprocess_keys().
-		 *
-		 * btree_clauses[s] points currently best clause containing the
-		 * operator strategy type s+1; it is NULL if we haven't yet found
-		 * such a clause.
-		 */
-		s = cur->op_strategy - 1;
-		if (btree_clauses[s] == NULL)
-		{
-			btree_clauses[s] = cur;
-		}
-		else
-		{
 			/*
-			 * Is this one more restrictive than what we already have?
+			 * The code that follows closely mimics similar processing done by
+			 * nbtutils.c: _bt_preprocess_keys().
 			 *
-			 * Consider some examples: 1. If btree_clauses[BTLT] now contains
-			 * a < 5, and cur is a < 3, then because 3 < 5 is true, a < 5
-			 * currently at btree_clauses[BTLT] will be replaced by a < 3.
-			 *
-			 * 2. If btree_clauses[BTEQ] now contains a = 5 and cur is a = 7,
-			 * then because 5 = 7 is false, we found a mutual contradiction,
-			 * so we set *constfalse to true and return.
-			 *
-			 * 3. If btree_clauses[BTLT] now contains a < 5 and cur is a < 7,
-			 * then because 7 < 5 is false, we leave a < 5 where it is and
-			 * effectively discard a < 7 as being redundant.
+			 * btree_clauses[s] points currently best clause containing the
+			 * operator strategy type s+1; it is NULL if we haven't yet found
+			 * such a clause.
 			 */
-			if (partition_cmp_args(partkey, partkeyidx,
-								   cur, cur, btree_clauses[s],
-								   &test_result))
+			s = cur->op_strategy - 1;
+			if (btree_clauses[s] == NULL)
 			{
-				/* cur is more restrictive, so replace the existing. */
-				if (test_result)
-					btree_clauses[s] = cur;
-				else if (s == BTEqualStrategyNumber - 1)
-				{
-					*constfalse = true;
-					return;
-				}
-
-				/* Old one is more restrictive, so keep around. */
+				btree_clauses[s] = cur;
 			}
 			else
 			{
 				/*
-				 * we couldn't determine which one is more restrictive.  Keep
-				 * the previous one in btree_clauses[s] and push this one directly
-				 * to the output list.
+				 * Is this one more restrictive than what we already have?
+				 *
+				 * Consider some examples: 1. If btree_clauses[BTLT] now contains
+				 * a < 5, and cur is a < 3, then because 3 < 5 is true, a < 5
+				 * currently at btree_clauses[BTLT] will be replaced by a < 3.
+				 *
+				 * 2. If btree_clauses[BTEQ] now contains a = 5 and cur is a = 7,
+				 * then because 5 = 7 is false, we found a mutual contradiction,
+				 * so we set *constfalse to true and return.
+				 *
+				 * 3. If btree_clauses[BTLT] now contains a < 5 and cur is a < 7,
+				 * then because 7 < 5 is false, we leave a < 5 where it is and
+				 * effectively discard a < 7 as being redundant.
 				 */
-				*result = lappend(*result, cur);
+				if (partition_cmp_args(partkey, i,
+									   cur, cur, btree_clauses[s],
+									   &test_result))
+				{
+					/* cur is more restrictive, so replace the existing. */
+					if (test_result)
+						btree_clauses[s] = cur;
+					else if (s == BTEqualStrategyNumber - 1)
+					{
+						partclauses->constfalse = true;
+						return;
+					}
+
+					/* Old one is more restrictive, so keep around. */
+				}
+				else
+				{
+					/*
+					 * We couldn't determine which one is more restrictive.  Keep
+					 * the previous one in btree_clauses[s] and push this one directly
+					 * to the output list.
+					 */
+					newlist = lappend(newlist, cur);
+				}
 			}
 		}
-	}
-
-	if (partkey->strategy == PARTITION_STRATEGY_HASH)
-	{
-		/* Note we didn't add this one to the result yet. */
-		if (hash_clause)
-			*result = lappend(*result, hash_clause);
-		return;
-	}
 
-	/* Compare btree operator clauses across strategies. */
+		if (partkey->strategy == PARTITION_STRATEGY_HASH)
+		{
+			/* Note we didn't add this one to the result yet. */
+			if (hash_clause)
+				newlist = lappend(newlist, hash_clause);
+			list_free(partclauses->clauses[i]);
+			partclauses->clauses[i] = newlist;
+			continue;
+		}
 
-	/* Compare the equality clause with clauses of other strategies. */
-	if (btree_clauses[BTEqualStrategyNumber - 1])
-	{
-		PartClause *eq = btree_clauses[BTEqualStrategyNumber - 1];
+		/* Compare btree operator clauses across strategies. */
 
-		for (s = 0; s < BTMaxStrategyNumber; s++)
+		/* Compare the equality clause with clauses of other strategies. */
+		if (btree_clauses[BTEqualStrategyNumber - 1])
 		{
-			PartClause *chk = btree_clauses[s];
-
-			if (!chk || s == (BTEqualStrategyNumber - 1))
-				continue;
+			PartClause *eq = btree_clauses[BTEqualStrategyNumber - 1];
 
-			/*
-			 * Suppose btree_clauses[BTLT] contained a < 5 and the eq clause
-			 * is a = 5, then because 5 < 5 is false, we found contradiction.
-			 * That is, a < 5 and a = 5 are mutually contradictory.  OTOH, if
-			 * eq clause is a = 3, then because 3 < 5, we no longer need
-			 * a < 5, because a = 3 is more restrictive.
-			 */
-			if (partition_cmp_args(partkey, partkeyidx,
-								   chk, eq, chk,
-								   &test_result))
+			for (s = 0; s < BTMaxStrategyNumber; s++)
 			{
-				if (!test_result)
+				PartClause *chk = btree_clauses[s];
+
+				if (!chk || s == (BTEqualStrategyNumber - 1))
+					continue;
+
+				/*
+				 * Suppose btree_clauses[BTLT] contained a < 5 and the eq clause
+				 * is a = 5, then because 5 < 5 is false, we found contradiction.
+				 * That is, a < 5 and a = 5 are mutually contradictory.  OTOH, if
+				 * eq clause is a = 3, then because 3 < 5, we no longer need
+				 * a < 5, because a = 3 is more restrictive.
+				 */
+				if (partition_cmp_args(partkey, i,
+									   chk, eq, chk,
+									   &test_result))
 				{
-					*constfalse = true;
-					return;
+					if (!test_result)
+					{
+						partclauses->constfalse = true;
+						return;
+					}
+					/* Discard the no longer needed clause. */
+					btree_clauses[s] = NULL;
 				}
-				/* Discard the no longer needed clause. */
-				btree_clauses[s] = NULL;
 			}
 		}
-	}
-
-	/*
-	 * Try to keep only one of <, <=.
-	 *
-	 * Suppose btree_clauses[BTLT] contains a < 3 and btree_clauses[BTLE]
-	 * contains a <= 3 (or a <= 4), then because 3 <= 3 (or 3 <= 4) is true,
-	 * we discard the a <= 3 (or a <= 4) as redundant.  If the latter contains
-	 * contains a <= 2, then because 3 <= 2 is false, we dicard a < 3 as
-	 * redundant.
-	 */
-	if (btree_clauses[BTLessStrategyNumber - 1] &&
-		btree_clauses[BTLessEqualStrategyNumber - 1])
-	{
-		PartClause *lt = btree_clauses[BTLessStrategyNumber - 1],
-				   *le = btree_clauses[BTLessEqualStrategyNumber - 1];
 
-		if (partition_cmp_args(partkey, partkeyidx,
-							   le, lt, le,
-							   &test_result))
+		/*
+		 * Try to keep only one of <, <=.
+		 *
+		 * Suppose btree_clauses[BTLT] contains a < 3 and btree_clauses[BTLE]
+		 * contains a <= 3 (or a <= 4), then because 3 <= 3 (or 3 <= 4) is true,
+		 * we discard the a <= 3 (or a <= 4) as redundant.  If the latter contains
+		 * contains a <= 2, then because 3 <= 2 is false, we dicard a < 3 as
+		 * redundant.
+		 */
+		if (btree_clauses[BTLessStrategyNumber - 1] &&
+			btree_clauses[BTLessEqualStrategyNumber - 1])
 		{
-			if (test_result)
-				btree_clauses[BTLessEqualStrategyNumber - 1] = NULL;
-			else
-				btree_clauses[BTLessStrategyNumber - 1] = NULL;
+			PartClause *lt = btree_clauses[BTLessStrategyNumber - 1],
+					   *le = btree_clauses[BTLessEqualStrategyNumber - 1];
+
+			if (partition_cmp_args(partkey, i,
+								   le, lt, le,
+								   &test_result))
+			{
+				if (test_result)
+					btree_clauses[BTLessEqualStrategyNumber - 1] = NULL;
+				else
+					btree_clauses[BTLessStrategyNumber - 1] = NULL;
+			}
 		}
-	}
 
-	/* Try to keep only one of >, >=.  See the example above. */
-	if (btree_clauses[BTGreaterStrategyNumber - 1] &&
-		btree_clauses[BTGreaterEqualStrategyNumber - 1])
-	{
-		PartClause *gt = btree_clauses[BTGreaterStrategyNumber - 1],
-				   *ge = btree_clauses[BTGreaterEqualStrategyNumber - 1];
+		/* Try to keep only one of >, >=.  See the example above. */
+		if (btree_clauses[BTGreaterStrategyNumber - 1] &&
+			btree_clauses[BTGreaterEqualStrategyNumber - 1])
+		{
+			PartClause *gt = btree_clauses[BTGreaterStrategyNumber - 1],
+					   *ge = btree_clauses[BTGreaterEqualStrategyNumber - 1];
+
+			if (partition_cmp_args(partkey, i,
+								   ge, gt, ge,
+								   &test_result))
+			{
+				if (test_result)
+					btree_clauses[BTGreaterEqualStrategyNumber - 1] = NULL;
+				else
+					btree_clauses[BTGreaterStrategyNumber - 1] = NULL;
+			}
+		}
 
-		if (partition_cmp_args(partkey, partkeyidx,
-							   ge, gt, ge,
-							   &test_result))
+		/*
+		 * btree_clauses now contains the "best" clause or NULL for each btree
+		 * strategy number.  Add to the newlist.
+		 */
+		for (s = 0; s < BTMaxStrategyNumber; s++)
 		{
-			if (test_result)
-				btree_clauses[BTGreaterEqualStrategyNumber - 1] = NULL;
-			else
-				btree_clauses[BTGreaterStrategyNumber - 1] = NULL;
+			if (btree_clauses[s])
+				newlist = lappend(newlist, btree_clauses[s]);
 		}
-	}
 
-	/*
-	 * btree_clauses now contains the "best" clause or NULL for each btree
-	 * strategy number.  Add to the result.
-	 */
-	for (s = 0; s < BTMaxStrategyNumber; s++)
-		if (btree_clauses[s])
-			*result = lappend(*result, btree_clauses[s]);
+		/*
+		 * Replace the old List with the new one with the redundant clauses
+		 * removed.
+		 */
+		list_free(partclauses->clauses[i]);
+		partclauses->clauses[i] = newlist;
+	}
 }
 
 /*
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;
 }
