diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index b35e35c..ad789f6 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -173,8 +173,9 @@ typedef struct PartitionBoundCmpArg
  */
 typedef struct PartClause
 {
-	OpExpr *op;
-	Expr   *constarg;
+	Oid		opno;		/* opno to compare partkey to 'value' */
+	Oid		inputcollid; /* collation to compare partkey to 'value' */
+	Expr   *value;	/* The value the partition key is being compared to */
 
 	/* cached info. */
 	bool	valid_cache;	/* Are the following fields populated? */
@@ -195,24 +196,6 @@ typedef enum PartOpStrategy
 } PartOpStrategy;
 
 /*
- * Clauses matched to partition keys
- */
-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()
@@ -307,26 +290,25 @@ static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull);
 /* SQL-callable function for use in hash partition CHECK constraints */
 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_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 extract_partition_key_clauses(PartitionKey partkey, List *clauses,
-							  int rt_index, PartScanClauseInfo *partclauses);
+static Bitmapset *get_partitions_from_or_clause_args(
+								   PartitionPruneContext *context,
+								   List *or_clause_args);
+static void extract_partition_key_clauses(PartitionKey partkey, List *clauses,
+							  int rt_index, PartitionClauseInfo *partclauses);
 static bool extract_bounding_datums(PartitionKey partkey,
-						PartScanClauseInfo *partclauses,
+						PartitionPruneContext *context,
 						PartScanKeyInfo *keys);
 static bool partition_cmp_args(PartitionKey key, int partkeyidx,
-				   PartClause *op, PartClause *leftarg, PartClause *rightarg,
+				   PartClause *pc, PartClause *leftarg, PartClause *rightarg,
 				   bool *result);
-static PartOpStrategy partition_op_strategy(PartitionKey key, PartClause *op,
+static PartOpStrategy partition_op_strategy(PartitionKey key, PartClause *pc,
 					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);
+						 PartitionPruneContext *context);
 static Bitmapset *get_partitions_for_keys(Relation rel,
 						PartScanKeyInfo *keys);
 static Bitmapset *get_partitions_for_keys_hash(Relation rel,
@@ -1707,38 +1689,46 @@ get_partition_qual_relid(Oid relid)
 }
 
 /*
- * get_partitions_from_clauses
- *		Determine all partitions of 'relation' that could possibly contain a
- *		record that matches 'partclauses'
+ * populate_partition_clause_info
+ *		Processes 'clauses' to try to match them to relation's partition
+ *		keys.  If any clauses are found which match a partition key, then
+ *		these clauses are stored in 'partclauseinfo'.
  *
- * Returns a Bitmapset of the matching partition indexes, or NULL if none can
- * match.
+ * The caller must ensure that 'clauses' is not an empty List. Upon return,
+ * callers must also check if the 'partclauseinfo' constfalse has been set, if
+ * so, then they must be aware that the 'partclauseinfo' may only be partially
+ * populated.
  */
-Bitmapset *
-get_partitions_from_clauses(Relation relation, int rt_index,
-							List *partclauses)
+void
+populate_partition_clause_info(Relation relation,
+							   int rt_index, List *clauses,
+							   PartitionClauseInfo *partclauseinfo)
 {
-	PartitionDesc		partdesc = RelationGetPartitionDesc(relation);
+	PartitionDesc		partdesc;
+	PartitionKey		partkey;
 	PartitionBoundInfo	boundinfo;
-	List			   *clauses;
 
-	/* All partitions match if there are no clauses */
-	if (!partclauses)
-		return bms_add_range(NULL, 0, partdesc->nparts - 1);
+	Assert(clauses != NIL);
+
+	partkey = RelationGetPartitionKey(relation);
+	partdesc = RelationGetPartitionDesc(relation);
 
 	/* Some functions called below modify this list */
-	clauses = list_copy(partclauses);
+	clauses = list_copy(clauses);
 	boundinfo = partdesc->boundinfo;
 
 	/*
-	 * 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
-	 * restrict the possible key space to only that allowed by the partition
-	 * and thus avoids the default partition being inadvertently added to the
-	 * set of selected partitions for a query whose clauses select a key space
-	 * bigger than the partition's.
+	 * For sub-partitioned tables there's a corner case where if the
+	 * sub-partitioned table shares any partition keys with its parent, then
+	 * it's possible that the partitioning hierarchy allows the parent
+	 * partition to only contain a narrower range of values than the
+	 * sub-partitioned table does.  In this case it is possible that we'd
+	 * include partitions that could not possibly have any tuples matching
+	 * 'clauses'.  The possibility of such a partition arrangement
+	 * is perhaps unlikely for non-default partitions, but it may be more
+	 * likely in the case of default partitions, so we'll add the parent
+	 * partition table's partition qual to the clause list in this case only.
+	 * This may result in the default partition being eliminated.
 	 */
 	if (partition_bound_has_default(boundinfo))
 	{
@@ -1753,47 +1743,56 @@ get_partitions_from_clauses(Relation relation, int rt_index,
 		clauses = list_concat(clauses, partqual);
 	}
 
-	return get_partitions_from_clauses_recurse(relation, rt_index, clauses);
+	extract_partition_key_clauses(partkey, clauses, rt_index, partclauseinfo);
 }
 
-/* Module-local functions */
-
 /*
- * get_partitions_from_clauses_recurse
- *		Determine relation's partitions that satisfy *all* of the clauses
- *		in the list
+ * get_partitions_from_clauses
+ *		Determine all partitions of the context 'relation' that could possibly
+ *		contain a record that matches the context 'clauseinfo'
  *
- * Return value is a Bitmapset containing the indexes of selected partitions.
+ * Returns a Bitmapset of the matching partition indexes, or NULL if none can
+ * match.
  */
-static Bitmapset *
-get_partitions_from_clauses_recurse(Relation relation, int rt_index,
-									List *clauses)
+Bitmapset *
+get_partitions_from_clauseinfo(PartitionPruneContext *context)
 {
-	PartitionDesc		partdesc = RelationGetPartitionDesc(relation);
-	PartitionKey		partkey	= RelationGetPartitionKey(relation);
-	PartScanClauseInfo	partclauses;
-	Bitmapset 		   *result;
+	PartitionClauseInfo	*partclauseinfo = context->clauseinfo;
+	PartitionDesc		partdesc;
+	PartitionBoundInfo	boundinfo;
+	PartitionKey		partkey;
 	PartScanKeyInfo		keys;
+	Bitmapset 		   *result;
+	Relation			relation;
+	int					rt_index;
 	ListCell *lc;
 
-	/* Populate partclauses from the clause list */
-	if (extract_partition_key_clauses(partkey, clauses, rt_index, &partclauses))
-	{
-		/*
-		 * No partitions to scan if extract_partition_key_clauses found some
-		 * clause contradiction.
-		 */
-		if (partclauses.constfalse)
-			return NULL;
+	Assert(partclauseinfo != NULL);
 
+	/*
+	 * Check if there were proofs that no partitions can match due to some
+	 * clause items contradicting each other.
+	 */
+	if (partclauseinfo->constfalse)
+		return NULL;
+
+	relation = context->relation;
+	rt_index = context->rt_index;
+
+	partdesc = RelationGetPartitionDesc(relation);
+	boundinfo = partdesc->boundinfo;
+	partkey = RelationGetPartitionKey(relation);
+
+	if (partclauseinfo->foundkeyclauses)
+	{
 		/* collapse clauses down to the most restrictive set */
-		remove_redundant_clauses(partkey, &partclauses);
+		remove_redundant_clauses(partkey, context);
 
 		/* Did remove_redundant_clauses find any contradicting clauses? */
-		if (partclauses.constfalse)
+		if (partclauseinfo->constfalse)
 			return NULL;
 
-		if (extract_bounding_datums(partkey, &partclauses, &keys))
+		if (extract_bounding_datums(partkey, context, &keys))
 		{
 			result = get_partitions_for_keys(relation, &keys);
 
@@ -1816,34 +1815,35 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
 	}
 	else
 	{
-		/*
-		 * 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);
 	}
 
 	/* Select partitions by applying the clauses containing <> operators. */
-	if (partclauses.ne_clauses)
+	if (partclauseinfo->ne_clauses)
 	{
-		Bitmapset *ne_clause_parts;
+		Bitmapset *ne_parts;
 
-		ne_clause_parts = get_partitions_excluded_by_ne_clauses(relation,
-													partclauses.ne_clauses);
+		ne_parts = get_partitions_excluded_by_ne_clauses(relation,
+												partclauseinfo->ne_clauses);
 
 		/* Remove any partitions we found to not be needed */
-		result = bms_del_members(result, ne_clause_parts);
-		bms_free(ne_clause_parts);
+		result = bms_del_members(result, ne_parts);
+		bms_free(ne_parts);
 	}
 
 	/* Select partitions by applying OR clauses. */
-	foreach(lc, partclauses.or_clauses)
+	foreach(lc, partclauseinfo->or_clauses)
 	{
-		BoolExpr *or = (BoolExpr *) lfirst(lc);
+		List *or_args = (List *) lfirst(lc);
+		PartitionPruneContext orcontext;
 		Bitmapset *or_parts;
 
-		or_parts = get_partitions_from_or_clause_args(relation, rt_index,
-													  or->args);
+		orcontext.rt_index = context->rt_index;
+		orcontext.relation = context->relation;
+		orcontext.clauseinfo = NULL;
+
+		or_parts = get_partitions_from_or_clause_args(&orcontext, or_args);
+
 		/*
 		 * Clauses in or_clauses are mutually conjunctive and also in
 		 * in conjunction with the rest of the clauses above, so combine the
@@ -1857,6 +1857,8 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
 	return result;
 }
 
+/* Module-local functions */
+
 /*
  * get_partitions_excluded_by_ne_clauses
  *
@@ -1892,7 +1894,7 @@ get_partitions_excluded_by_ne_clauses(Relation relation, List *ne_clauses)
 		PartClause *pc = (PartClause *) lfirst(lc);
 		Datum	datum;
 
-		if (partkey_datum_from_expr(partkey, 0, pc->constarg, &datum))
+		if (partkey_datum_from_expr(partkey, 0, pc->value, &datum))
 		{
 			int		offset;
 			bool	is_equal;
@@ -1973,17 +1975,25 @@ get_partitions_excluded_by_ne_clauses(Relation relation, List *ne_clauses)
  * clause in or_clause_args.
  */
 static Bitmapset *
-get_partitions_from_or_clause_args(Relation relation, int rt_index,
+get_partitions_from_or_clause_args(PartitionPruneContext *context,
 								   List *or_clause_args)
 {
-	ListCell   *lc;
-	Bitmapset  *result = NULL;
+	List		   *partconstr;
+	PartitionKey	partkey;
+	Bitmapset	   *result = NULL;
+	ListCell	   *lc;
+
+	partconstr = RelationGetPartitionQual(context->relation);
+	partkey = RelationGetPartitionKey(context->relation);
+
+	partconstr = (List *) expression_planner((Expr *) partconstr);
+	if (context->rt_index != 1)
+		ChangeVarNodes((Node *) partconstr, 1, context->rt_index, 0);
 
 	foreach(lc, or_clause_args)
 	{
-		List *arg_clauses = list_make1(lfirst(lc));
-		List *partconstr = RelationGetPartitionQual(relation);
-		Bitmapset *arg_partset;
+		List *clauses = list_make1(lfirst(lc));
+		PartitionClauseInfo partclauseinfo;
 
 		/*
 		 * It's possible that this clause is never true for this relation due
@@ -1992,23 +2002,29 @@ get_partitions_from_or_clause_args(Relation relation, int rt_index,
 		 * 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.
+		 * of get_partitions_from_clauseinfo to determine the correct set of
+		 * partitions, so we'll just make use of predicate_refuted_by instead.
 		 */
-		if (partconstr)
+		if (partconstr && predicate_refuted_by(partconstr, clauses, false))
+			continue;
+
+		extract_partition_key_clauses(partkey, clauses, context->rt_index,
+									  &partclauseinfo);
+
+		if (!partclauseinfo.constfalse)
 		{
-			partconstr = (List *) expression_planner((Expr *) partconstr);
-			if (rt_index != 1)
-				ChangeVarNodes((Node *) partconstr, 1, rt_index, 0);
-			if (predicate_refuted_by(partconstr, arg_clauses, false))
-				continue;
-		}
+			PartitionPruneContext subcontext;
+			Bitmapset *arg_partset;
+
+			subcontext.rt_index = context->rt_index;
+			subcontext.relation = context->relation;
+			subcontext.clauseinfo = &partclauseinfo;
+
+			arg_partset = get_partitions_from_clauseinfo(&subcontext);
 
-		arg_partset = get_partitions_from_clauses_recurse(relation, rt_index,
-														  arg_clauses);
-		result = bms_add_members(result, arg_partset);
-		bms_free(arg_partset);
+			result = bms_add_members(result, arg_partset);
+			bms_free(arg_partset);
+		}
 	}
 
 	return result;
@@ -2028,28 +2044,25 @@ get_partitions_from_or_clause_args(Relation relation, int rt_index,
  * 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
+ *		key and 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.
  *
- * 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.
- *
- * The function returns false if no useful key clauses were found.
+ * We may also discover some contradiction in the clauses which means that no
+ * partition can possibly match.  In this case, the function sets
+ * partclauseinfo's 'constfalse' to true and exits immediately without
+ * processing any further clauses.  In this case, the caller must be careful
+ * not to assume the PartitionClauseInfo is fully populated with all clauses.
  */
-static bool
+static void
 extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 							  int rt_index,
-							  PartScanClauseInfo *partclauses)
+							  PartitionClauseInfo *partclauseinfo)
 {
 	int			i;
 	ListCell   *lc;
-	bool		got_useful_keys = false;
 
-	memset(partclauses, 0, sizeof(PartScanClauseInfo));
+	memset(partclauseinfo, 0, sizeof(PartitionClauseInfo));
 
 	foreach(lc, clauses)
 	{
@@ -2064,8 +2077,8 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 			if (rinfo->pseudoconstant &&
 				!DatumGetBool(((Const *) clause)->constvalue))
 			{
-				partclauses->constfalse = true;
-				return true;
+				partclauseinfo->constfalse = true;
+				return;
 			}
 		}
 
@@ -2074,7 +2087,9 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 		{
 			if (or_clause((Node *) clause))
 			{
-				partclauses->or_clauses = lappend(partclauses->or_clauses, clause);
+				partclauseinfo->or_clauses =
+										lappend(partclauseinfo->or_clauses,
+												((BoolExpr *) clause)->args);
 				continue;
 			}
 			else if (and_clause((Node *) clause))
@@ -2127,7 +2142,7 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 				OpExpr	   *opclause = (OpExpr *) clause;
 				Expr	   *leftop,
 						   *rightop,
-						   *constexpr;
+						   *valueexpr;
 				bool		is_ne_listp = false;
 
 				leftop = (Expr *) get_leftop(clause);
@@ -2139,10 +2154,10 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 
 				/* check if the clause matches the partition key */
 				if (EXPR_MATCHES_PARTKEY(leftop, partattno, partexpr))
-					constexpr = rightop;
+					valueexpr = rightop;
 				else if (EXPR_MATCHES_PARTKEY(rightop, partattno, partexpr))
 				{
-					constexpr = leftop;
+					valueexpr = leftop;
 
 					commutator = get_commutator(opclause->opno);
 
@@ -2169,7 +2184,7 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 					continue;
 
 				/* Useless if the "constant" can change its value. */
-				if (contain_volatile_functions((Node *) constexpr))
+				if (contain_volatile_functions((Node *) valueexpr))
 					continue;
 
 				/*
@@ -2215,25 +2230,9 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 				}
 
 				pc = (PartClause *) palloc0(sizeof(PartClause));
-				pc->constarg = constexpr;
-
-				/*
-				 * 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 (!OidIsValid(commutator))
-					pc->op = opclause;
-				else
-				{
-					OpExpr   *commuted;
-
-					commuted = (OpExpr *) copyObject(opclause);
-					commuted->opno = commutator;
-					commuted->opfuncid = get_opcode(commutator);
-					commuted->args = list_make2(rightop, leftop);
-					pc->op = commuted;
-				}
+				pc->opno = OidIsValid(commutator) ? commutator : opclause->opno;
+				pc->inputcollid = opclause->inputcollid;
+				pc->value = valueexpr;
 
 				/*
 				 * We don't turn a <> operator clause into a key right away.
@@ -2241,24 +2240,28 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 				 * get_partitions_excluded_by_ne_clauses().
 				 */
 				if (is_ne_listp)
-					partclauses->ne_clauses = lappend(partclauses->ne_clauses,
-													  pc);
+					partclauseinfo->ne_clauses =
+										lappend(partclauseinfo->ne_clauses,
+												pc);
 				else
 				{
-					partclauses->clauses[i] = lappend(partclauses->clauses[i], pc);
-					got_useful_keys = true;
+					partclauseinfo->keyclauses[i] =
+										lappend(partclauseinfo->keyclauses[i],
+												pc);
+					partclauseinfo->foundkeyclauses = true;
 
 					/*
 					 * Since we only allow strict operators, require keys to
 					 * be not null.
 					 */
-					if (bms_is_member(i, partclauses->keyisnull))
+					if (bms_is_member(i, partclauseinfo->keyisnull))
 					{
-						partclauses->constfalse = true;
-						return true;
+						partclauseinfo->constfalse = true;
+						return;
 					}
-					partclauses->keyisnotnull =
-								bms_add_member(partclauses->keyisnotnull, i);
+					partclauseinfo->keyisnotnull =
+								bms_add_member(partclauseinfo->keyisnotnull,
+											   i);
 				}
 			}
 			else if (IsA(clause, ScalarArrayOpExpr))
@@ -2418,9 +2421,9 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 				 * of the list that's being processed currently.
 				 */
 				if (saop->useOr)
-					partclauses->or_clauses = lappend(partclauses->or_clauses,
-										  makeBoolExpr(OR_EXPR, elem_clauses,
-													   -1));
+					partclauseinfo->or_clauses =
+										lappend(partclauseinfo->or_clauses,
+												elem_clauses);
 				else
 					clauses = list_concat(clauses, elem_clauses);
 			}
@@ -2438,27 +2441,29 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 					if (nulltest->nulltesttype == IS_NULL)
 					{
 						/* check for conflicting IS NOT NULLs */
-						if (bms_is_member(i, partclauses->keyisnotnull))
+						if (bms_is_member(i, partclauseinfo->keyisnotnull))
 						{
-							partclauses->constfalse = true;
-							return true;
+							partclauseinfo->constfalse = true;
+							return;
 						}
-						partclauses->keyisnull =
-									bms_add_member(partclauses->keyisnull, i);
+						partclauseinfo->keyisnull =
+									bms_add_member(partclauseinfo->keyisnull,
+												   i);
 					}
 					else
 					{
 						/* check for conflicting IS NULLs */
-						if (bms_is_member(i, partclauses->keyisnull))
+						if (bms_is_member(i, partclauseinfo->keyisnull))
 						{
-							partclauses->constfalse = true;
-							return true;
+							partclauseinfo->constfalse = true;
+							return;
 						}
 
-						partclauses->keyisnotnull =
-								bms_add_member(partclauses->keyisnotnull, i);
+						partclauseinfo->keyisnotnull =
+								bms_add_member(partclauseinfo->keyisnotnull,
+											   i);
 					}
-					got_useful_keys = true;
+					partclauseinfo->foundkeyclauses = true;
 				}
 			}
 			/*
@@ -2474,8 +2479,6 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 				Expr   *leftop,
 					   *rightop;
 
-				pc = (PartClause *) palloc0(sizeof(PartClause));
-
 				if (IsA(clause, BooleanTest))
 				{
 					BooleanTest *btest = (BooleanTest *) clause;
@@ -2514,19 +2517,19 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
 									? (Expr *) makeBoolConst(true, false)
 									: (Expr *) makeBoolConst(false, false);
 				}
-				pc->op = (OpExpr *) make_opclause(BooleanEqualOperator,
-										   BOOLOID, false,
-										   leftop, rightop,
-										   InvalidOid, InvalidOid);
-				pc->constarg = rightop;
-				partclauses->clauses[i] = lappend(partclauses->clauses[i],
-												  pc);
-				got_useful_keys = true;
+
+				pc = (PartClause *) palloc0(sizeof(PartClause));
+				pc->opno = BooleanEqualOperator;
+				pc->inputcollid = InvalidOid;
+				pc->value = rightop;
+
+				partclauseinfo->keyclauses[i] =
+										lappend(partclauseinfo->keyclauses[i],
+												pc);
+				partclauseinfo->foundkeyclauses = true;
 			}
 		}
 	}
-
-	return got_useful_keys;
 }
 
 /*
@@ -2543,21 +2546,24 @@ extract_partition_key_clauses(PartitionKey partkey, List *clauses,
  * Returns true if any keys were found during partition pruning.
  */
 static bool
-extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
+extract_bounding_datums(PartitionKey partkey, PartitionPruneContext *context,
 						PartScanKeyInfo *keys)
 {
+	PartitionClauseInfo *clauseinfo;
 	bool		need_next_eq,
 				need_next_min,
 				need_next_max;
 	int i;
 	ListCell *lc;
 
+	clauseinfo = context->clauseinfo;
+
 	/*
 	 * Based on the strategies of the clause operators (=, </<=, >/>=), try to
-	 * construct tuples of those datums that serve as the exact look up tuple
+	 * construct tuples of those datums that serve as the exact lookup tuple
 	 * or tuples that serve as minimum and maximum bound.  If we find datums
 	 * for all partition key columns that appear in = operator clauses, then
-	 * we have the exact match look up tuple, which will be used to match just
+	 * we have the exact match lookup tuple, which will be used to match just
 	 * one partition.  If the last datum in a tuple comes from a clause
 	 * containing </<= or >/>= operator, then that constitutes the minimum
 	 * or maximum bound tuple, respectively.  There is one exception -- if
@@ -2572,7 +2578,7 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 	memset(keys, 0, sizeof(PartScanKeyInfo));
 	for (i = 0; i < partkey->partnatts; i++)
 	{
-		List *clauselist = partclauses->clauses[i];
+		List *clauselist = clauseinfo->keyclauses[i];
 
 		/*
 		 * Min and max keys must constitute a prefix of the partition key and
@@ -2592,7 +2598,7 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 		foreach(lc, clauselist)
 		{
 			PartClause *clause = (PartClause *) lfirst(lc);
-			Expr *constarg = clause->constarg;
+			Expr *value = clause->value;
 			bool incl;
 			PartOpStrategy	op_strategy;
 
@@ -2602,12 +2608,12 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 				case PART_OP_EQUAL:
 					Assert(incl);
 					if (need_next_eq &&
-						partkey_datum_from_expr(partkey, i, constarg,
+						partkey_datum_from_expr(partkey, i, value,
 												&keys->eqkeys[i]))
 						keys->n_eqkeys++;
 
 					if (need_next_max &&
-						partkey_datum_from_expr(partkey, i, constarg,
+						partkey_datum_from_expr(partkey, i, value,
 												&keys->maxkeys[i]))
 					{
 						keys->n_maxkeys++;
@@ -2615,7 +2621,7 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 					}
 
 					if (need_next_min &&
-						partkey_datum_from_expr(partkey, i, constarg,
+						partkey_datum_from_expr(partkey, i, value,
 												&keys->minkeys[i]))
 					{
 						keys->n_minkeys++;
@@ -2625,7 +2631,7 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 
 				case PART_OP_LESS:
 					if (need_next_max &&
-						partkey_datum_from_expr(partkey, i, constarg,
+						partkey_datum_from_expr(partkey, i, value,
 												&keys->maxkeys[i]))
 					{
 						keys->n_maxkeys++;
@@ -2637,7 +2643,7 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 
 				case PART_OP_GREATER:
 					if (need_next_min &&
-						partkey_datum_from_expr(partkey, i, constarg,
+						partkey_datum_from_expr(partkey, i, value,
 												&keys->minkeys[i]))
 					{
 						keys->n_minkeys++;
@@ -2670,8 +2676,8 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 		keys->n_eqkeys = 0;
 
 	/* Finally, also set the keyisnull and keyisnotnull values. */
-	keys->keyisnull = partclauses->keyisnull;
-	keys->keyisnotnull = partclauses->keyisnotnull;
+	keys->keyisnull = clauseinfo->keyisnull;
+	keys->keyisnotnull = clauseinfo->keyisnotnull;
 
 	return (keys->n_eqkeys > 0 || keys->n_minkeys > 0 ||
 			keys->n_maxkeys > 0 || !bms_is_empty(keys->keyisnull) ||
@@ -2680,57 +2686,54 @@ extract_bounding_datums(PartitionKey partkey, PartScanClauseInfo *partclauses,
 
 /*
  * partition_op_strategy
- *		Returns whether the clause in 'op' contains an =, </<=, or >/>=
+ *		Returns whether the clause in 'pc' contains an =, </<=, or >/>=
  *		operator and set *incl to true if the operator's strategy is
  *		inclusive.
  */
 static PartOpStrategy
-partition_op_strategy(PartitionKey key, PartClause *op, bool *incl)
+partition_op_strategy(PartitionKey key, PartClause *pc, bool *incl)
 {
-	PartOpStrategy	result;
+	*incl = false;	/* overwritten below */
 
-	*incl = false;	/* overwritten as appropriate below */
 	switch (key->strategy)
 	{
 		/* Hash partitioning allows only hash equality. */
 		case PARTITION_STRATEGY_HASH:
-			if (op->op_strategy == HTEqualStrategyNumber)
+			if (pc->op_strategy == HTEqualStrategyNumber)
 			{
 				*incl = true;
-				result = PART_OP_EQUAL;
+				return PART_OP_EQUAL;
 			}
-			break;
+			elog(ERROR, "unexpected strategy number: %d",
+				 pc->op_strategy);
 
 		/* List and range partitioning support all btree operators. */
 		case PARTITION_STRATEGY_LIST:
 		case PARTITION_STRATEGY_RANGE:
-			switch (op->op_strategy)
+			switch (pc->op_strategy)
 			{
 				case BTLessEqualStrategyNumber:
 					*incl = true;
 					/* fall through */
 				case BTLessStrategyNumber:
-					result = PART_OP_LESS;
-					break;
+					return PART_OP_LESS;
+
 				case BTEqualStrategyNumber:
 					*incl = true;
-					result = PART_OP_EQUAL;
-					break;
+					return PART_OP_EQUAL;
 				case BTGreaterEqualStrategyNumber:
 					*incl = true;
 					/* fall through */
 				case BTGreaterStrategyNumber:
-					result = PART_OP_GREATER;
-					break;
+					return PART_OP_GREATER;
 			}
-			break;
 
 		default:
 			elog(ERROR, "unexpected partition strategy: %d",
 				 (int) key->strategy);
 	}
 
-	return result;
+	return PART_OP_EQUAL;		/* keep compiler quiet */
 }
 
 /*
@@ -2811,10 +2814,11 @@ partkey_datum_from_expr(PartitionKey key, int partkeyidx,
  */
 static void
 remove_redundant_clauses(PartitionKey partkey,
-						 PartScanClauseInfo *partclauses)
+						 PartitionPruneContext *context)
 {
 	PartClause *hash_clause,
 			   *btree_clauses[BTMaxStrategyNumber];
+	PartitionClauseInfo *partclauseinfo = context->clauseinfo;
 	ListCell *lc;
 	int		s;
 	int		i;
@@ -2823,29 +2827,29 @@ remove_redundant_clauses(PartitionKey partkey,
 
 	for (i = 0; i < partkey->partnatts; i++)
 	{
-		List *all_clauses = partclauses->clauses[i];
+		List *keyclauses = partclauseinfo->keyclauses[i];
 
 		hash_clause = NULL;
 		newlist = NIL;
 
 		memset(btree_clauses, 0, sizeof(btree_clauses));
 
-		foreach(lc, all_clauses)
+		foreach(lc, keyclauses)
 		{
-			PartClause *cur = (PartClause *) lfirst(lc);
+			PartClause *pc = (PartClause *) lfirst(lc);
 
-			if (!cur->valid_cache)
+			if (!pc->valid_cache)
 			{
 				Oid		lefttype;
 
-				get_op_opfamily_properties(cur->op->opno,
+				get_op_opfamily_properties(pc->opno,
 										   partkey->partopfamily[i],
 										   false,
-										   &cur->op_strategy,
+										   &pc->op_strategy,
 										   &lefttype,
-										   &cur->op_subtype);
-				fmgr_info(get_opcode(cur->op->opno), &cur->op_func);
-				cur->valid_cache = true;
+										   &pc->op_subtype);
+				fmgr_info(get_opcode(pc->opno), &pc->op_func);
+				pc->valid_cache = true;
 			}
 
 			/*
@@ -2857,15 +2861,15 @@ remove_redundant_clauses(PartitionKey partkey,
 			if (partkey->strategy == PARTITION_STRATEGY_HASH)
 			{
 				if (hash_clause == NULL)
-					hash_clause = cur;
+					hash_clause = pc;
 				/* check if another clause would contradict the one we have */
 				else if (partition_cmp_args(partkey, i,
-											cur, cur, hash_clause,
+											pc, pc, hash_clause,
 											&test_result))
 				{
 					if (!test_result)
 					{
-						partclauses->constfalse = true;
+						partclauseinfo->constfalse = true;
 						return;
 					}
 				}
@@ -2876,7 +2880,7 @@ remove_redundant_clauses(PartitionKey partkey,
 				 * partition-pruning with it.
 				 */
 				else
-					newlist = lappend(newlist, cur);
+					newlist = lappend(newlist, pc);
 
 				/*
 				 * The code below handles btree operators, so not relevant for
@@ -2893,10 +2897,10 @@ remove_redundant_clauses(PartitionKey partkey,
 			 * operator strategy type s+1; it is NULL if we haven't yet found
 			 * such a clause.
 			 */
-			s = cur->op_strategy - 1;
+			s = pc->op_strategy - 1;
 			if (btree_clauses[s] == NULL)
 			{
-				btree_clauses[s] = cur;
+				btree_clauses[s] = pc;
 			}
 			else
 			{
@@ -2916,15 +2920,15 @@ remove_redundant_clauses(PartitionKey partkey,
 				 * effectively discard a < 7 as being redundant.
 				 */
 				if (partition_cmp_args(partkey, i,
-									   cur, cur, btree_clauses[s],
+									   pc, pc, btree_clauses[s],
 									   &test_result))
 				{
 					/* cur is more restrictive, so replace the existing. */
 					if (test_result)
-						btree_clauses[s] = cur;
+						btree_clauses[s] = pc;
 					else if (s == BTEqualStrategyNumber - 1)
 					{
-						partclauses->constfalse = true;
+						partclauseinfo->constfalse = true;
 						return;
 					}
 
@@ -2937,7 +2941,7 @@ remove_redundant_clauses(PartitionKey partkey,
 					 * the previous one in btree_clauses[s] and push this one directly
 					 * to the output list.
 					 */
-					newlist = lappend(newlist, cur);
+					newlist = lappend(newlist, pc);
 				}
 			}
 		}
@@ -2947,8 +2951,8 @@ remove_redundant_clauses(PartitionKey partkey,
 			/* 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;
+			list_free(partclauseinfo->keyclauses[i]);
+			partclauseinfo->keyclauses[i] = newlist;
 			continue;
 		}
 
@@ -2979,7 +2983,7 @@ remove_redundant_clauses(PartitionKey partkey,
 				{
 					if (!test_result)
 					{
-						partclauses->constfalse = true;
+						partclauseinfo->constfalse = true;
 						return;
 					}
 					/* Discard the no longer needed clause. */
@@ -3046,8 +3050,8 @@ remove_redundant_clauses(PartitionKey partkey,
 		 * Replace the old List with the new one with the redundant clauses
 		 * removed.
 		 */
-		list_free(partclauses->clauses[i]);
-		partclauses->clauses[i] = newlist;
+		list_free(partclauseinfo->keyclauses[i]);
+		partclauseinfo->keyclauses[i] = newlist;
 	}
 }
 
@@ -3058,53 +3062,62 @@ remove_redundant_clauses(PartitionKey partkey,
  *		of this comparison.
  *
  * Returns true if we could actually perform the comparison; otherwise false.
- * We may not be able to perform the comparison if operand values are
- * unavailable and/or types of operands are incompatible with the operator.
+ *
+ * Note: We may not be able to perform the comparison if operand values are
+ * unknown in this context or if the type of any of the operands are
+ * incompatible with the operator.
  */
 static bool
 partition_cmp_args(PartitionKey key, int partkeyidx,
-				   PartClause *op, PartClause *leftarg, PartClause *rightarg,
+				   PartClause *pc, PartClause *leftarg, PartClause *rightarg,
 				   bool *result)
 {
-	Oid		partopfamily = key->partopfamily[partkeyidx];
-	Datum	leftarg_const,
-			rightarg_const;
+	Datum	left_value;
+	Datum	right_value;
 
-	Assert(op->valid_cache && leftarg->valid_cache && rightarg->valid_cache);
-	/* Get the constant values from the operands */
+	Assert(pc->valid_cache && leftarg->valid_cache && rightarg->valid_cache);
+
+	/*
+	 * Try to extract an actual value from each arg.  This may fail if the
+	 * value is unknown in this context, in which case we cannot compare.
+	 */
 	if (!partkey_datum_from_expr(key, partkeyidx,
-								 leftarg->constarg, &leftarg_const))
+								 leftarg->value, &left_value))
 		return false;
+
 	if (!partkey_datum_from_expr(key, partkeyidx,
-								 rightarg->constarg, &rightarg_const))
+								 rightarg->value, &right_value))
 		return false;
 
 	/*
-	 * We can compare leftarg_const and rightarg_const using op's operator
-	 * only if both are of the type expected by it.
+	 * We can compare left_value and right_value using op's operator
+	 * only if both are of the expected type.
 	 */
-	if (leftarg->op_subtype == op->op_subtype &&
-		rightarg->op_subtype == op->op_subtype)
+	if (leftarg->op_subtype == pc->op_subtype &&
+		rightarg->op_subtype == pc->op_subtype)
 	{
-		*result = DatumGetBool(FunctionCall2Coll(&op->op_func,
-												 op->op->inputcollid,
-												 leftarg_const,
-												 rightarg_const));
+		*result = DatumGetBool(FunctionCall2Coll(&pc->op_func,
+												 pc->inputcollid,
+												 left_value,
+												 right_value));
 		return true;
 	}
 	else
 	{
+		Oid		partopfamily = key->partopfamily[partkeyidx];
+		Oid		cmp_op;
+
 		/* Otherwise, look one up in the partitioning operator family. */
-		Oid		cmp_op = get_opfamily_member(partopfamily,
-											 leftarg->op_subtype,
-											 rightarg->op_subtype,
-											 op->op_strategy);
+		cmp_op = get_opfamily_member(partopfamily,
+									 leftarg->op_subtype,
+									 rightarg->op_subtype,
+									 pc->op_strategy);
 		if (OidIsValid(cmp_op))
 		{
 			*result = DatumGetBool(OidFunctionCall2Coll(get_opcode(cmp_op),
-														op->op->inputcollid,
-														leftarg_const,
-														rightarg_const));
+														pc->inputcollid,
+														left_value,
+														right_value));
 			return true;
 		}
 	}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index ddbbc79..2393d26 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2126,6 +2126,25 @@ _copyOnConflictExpr(const OnConflictExpr *from)
 	return newnode;
 }
 
+static PartitionClauseInfo *
+_copyPartitionClauseInfo(const PartitionClauseInfo *from)
+{
+	PartitionClauseInfo *newnode = makeNode(PartitionClauseInfo);
+
+	int i;
+	for (i = 0; i < PARTITION_MAX_KEYS; i++)
+		COPY_NODE_FIELD(keyclauses[i]);
+
+	COPY_NODE_FIELD(or_clauses);
+	COPY_NODE_FIELD(ne_clauses);
+	COPY_BITMAPSET_FIELD(keyisnull);
+	COPY_BITMAPSET_FIELD(keyisnotnull);
+	COPY_SCALAR_FIELD(constfalse);
+	COPY_SCALAR_FIELD(foundkeyclauses);
+
+	return newnode;
+}
+
 /* ****************************************************************
  *						relation.h copy functions
  *
@@ -5007,6 +5026,9 @@ copyObjectImpl(const void *from)
 		case T_OnConflictExpr:
 			retval = _copyOnConflictExpr(from);
 			break;
+		case T_PartitionClauseInfo:
+			retval = _copyPartitionClauseInfo(from);
+			break;
 
 			/*
 			 * RELATION NODES
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 51648c8..3821977 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -867,41 +867,65 @@ get_append_rel_partitions(PlannerInfo *root,
 						  RelOptInfo *rel,
 						  RangeTblEntry *rte)
 {
-	Relation		partrel;
-	Bitmapset	   *partindexes;
-	List		   *result = NIL;
-	int				i;
+	List	   *result = NIL;
+	List	   *clauses = rel->baserestrictinfo;
+	int			i;
 
-	partrel = heap_open(rte->relid, NoLock);
+	if (!clauses)
+	{
+		/* If there are no clauses then include every partition */
+		for (i = 0; i < rel->nparts; i++)
+			result = lappend(result, rel->part_appinfos[i]);
+		return result;
+	}
+	else
+	{
+		Relation		partrel;
+		Bitmapset	   *partindexes;
+		PartitionClauseInfo partclauseinfo;
 
-	partindexes = get_partitions_from_clauses(partrel, rel->relid,
-											  rel->baserestrictinfo);
+		partrel = heap_open(rte->relid, NoLock);
 
-	/* Fetch the partition appinfos. */
-	i = -1;
-	while ((i = bms_next_member(partindexes, i)) >= 0)
-	{
-		AppendRelInfo *appinfo = rel->part_appinfos[i];
+		/* Process clauses and populate partclauseinfo */
+		populate_partition_clause_info(partrel, rel->relid,
+									   clauses, &partclauseinfo);
+
+		if (!partclauseinfo.constfalse)
+		{
+			PartitionPruneContext context;
+
+			context.rt_index = rel->relid;
+			context.relation = partrel;
+			context.clauseinfo = &partclauseinfo;
+
+			partindexes = get_partitions_from_clauseinfo(&context);
+
+			/* Fetch the partition appinfos. */
+			i = -1;
+			while ((i = bms_next_member(partindexes, i)) >= 0)
+			{
+				AppendRelInfo *appinfo = rel->part_appinfos[i];
 
 #ifdef USE_ASSERT_CHECKING
-		PartitionDesc	partdesc = RelationGetPartitionDesc(partrel);
-		RangeTblEntry   *childrte;
+				PartitionDesc	partdesc = RelationGetPartitionDesc(partrel);
+				RangeTblEntry   *childrte;
 
-		childrte = planner_rt_fetch(appinfo->child_relid, root);
+				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] == childrte->relid);
+				/*
+				 * 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] == childrte->relid);
 #endif
+				result = lappend(result, appinfo);
+			}
+		}
 
-		result = lappend(result, appinfo);
-	}
-
-	heap_close(partrel, NoLock);
+		heap_close(partrel, NoLock);
 
-	return result;
+		return result;
+	}
 }
 
 /*
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 8423c6e..01f5f0c 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -40,6 +40,13 @@ typedef struct PartitionDescData
 	PartitionBoundInfo boundinfo;	/* collection of partition bounds */
 } PartitionDescData;
 
+typedef struct PartitionPruneContext
+{
+	int			rt_index;
+	Relation	relation;
+	PartitionClauseInfo *clauseinfo;
+} PartitionPruneContext;
+
 typedef struct PartitionDescData *PartitionDesc;
 
 extern void RelationBuildPartitionDesc(Relation relation);
@@ -74,6 +81,10 @@ extern int get_partition_for_tuple(Relation relation, Datum *values,
 						bool *isnull);
 
 /* For partition-pruning */
-extern Bitmapset *get_partitions_from_clauses(Relation relation, int rt_index,
-							List *partclauses);
+extern void populate_partition_clause_info(Relation relation,
+							   int rt_index, List *clauses,
+							   PartitionClauseInfo *partclauseinfo);
+extern Bitmapset *get_partitions_from_clauseinfo(
+							   PartitionPruneContext *context);
+
 #endif							/* PARTITION_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2eb3d6d..7630f25 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -190,6 +190,7 @@ typedef enum NodeTag
 	T_JoinExpr,
 	T_FromExpr,
 	T_OnConflictExpr,
+	T_PartitionClauseInfo,
 	T_IntoClause,
 
 	/*
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 1b4b0d7..2a8cc40 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1506,4 +1506,29 @@ typedef struct OnConflictExpr
 	List	   *exclRelTlist;	/* tlist of the EXCLUDED pseudo relation */
 } OnConflictExpr;
 
+/*----------
+ * PartitionClauseInfo
+ *
+ * Stores clauses which were matched to a partition key. Each matching clause
+ * is stored in the 'clauses' list for the partition key index that it was
+ * matched to.  Other details are also stored, such as OR clauses and
+ * not-equal (<>) clauses.  Nullness properties are also stored.
+ *----------
+ */
+typedef struct PartitionClauseInfo
+{
+	/* Lists of clauses indexed by the partition key */
+	List   *keyclauses[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;
+	bool	foundkeyclauses; /* true if clauses contains any items */
+} PartitionClauseInfo;
+
 #endif							/* PRIMNODES_H */
