diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index d42f0b748ab..48fa9dbf939 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -194,18 +194,22 @@ static uint64 compute_hash_value(int partnatts, FmgrInfo *partsupfunc,
 								 Datum *values, bool *isnull);
 
 static Bitmapset *perform_pruning_step(PartitionPruneContext *context,
-					 PartitionPruneStep *step,
-					 Bitmapset *srcparts);
+					 PartitionPruneStep *step);
 static Bitmapset *perform_pruning_base_step(PartitionPruneContext *context,
 						  PartitionPruneStepOp *opstep);
 static Bitmapset *perform_pruning_combine_step(PartitionPruneContext *context,
-							 PartitionPruneStepCombine *cstep,
-							 Bitmapset *srcparts);
+							 PartitionPruneStepCombine *cstep);
 static bool partkey_datum_from_expr(PartitionPruneContext *context,
 						int partkeyidx, Expr *expr, Datum *value);
-static Bitmapset *get_partitions_for_keys(PartitionPruneContext *context,
-						int opstrategy, Datum *values, int nvalues,
-						Bitmapset *nullkeys);
+static Bitmapset *get_partitions_for_keys_hash(PartitionPruneContext *context,
+							 int opstrategy, Datum *values, int nvalues,
+							 Bitmapset *nullkeys);
+static Bitmapset *get_partitions_for_keys_list(PartitionPruneContext *context,
+							 int opstrategy, Datum *values, int nvalues,
+							 Bitmapset *nullkeys);
+static Bitmapset *get_partitions_for_keys_range(
+							 PartitionPruneContext *context, int opstrategy,
+							 Datum *values, int nvalues, Bitmapset *nullkeys);
 static Bitmapset *get_partitions_excluded_by_ne_datums(PartitionPruneContext *context,
 						Datum *ne_datums, int n_ne_datums);
 
@@ -1573,32 +1577,46 @@ get_partition_qual_relid(Oid relid)
  * get_matching_partitions
  *		Determine partitions that survive partition pruning steps
  *
- * Returns a Bitmapset of indexes of surviving partitions, or NULL if none
- * survive.
+ * Returns a Bitmapset of indexes of surviving partitions.
  */
 Bitmapset *
 get_matching_partitions(PartitionPruneContext *context,
 						List *pruning_steps)
 {
-	/* First there are no unpruned partitions. */
-	Bitmapset  *result = bms_add_range(NULL, 0, context->nparts - 1);
-	ListCell   *lc;
-
-	/*
-	 * If there are multiple pruning steps, we perform them one after another,
-	 * passing the result of one step as input to another.  Based on the type
-	 * of pruning step, perform_pruning_step may add or remove partitions from
-	 * the set of partitions it receives as the input.
-	 */
-	foreach(lc, pruning_steps)
+	/* If there are no pruning steps then all partitions match. */
+	if (pruning_steps == NIL)
+		return bms_add_range(NULL, 0, context->nparts - 1);
+	else
 	{
-		PartitionPruneStep *step = lfirst(lc);
+		Bitmapset *result = NULL;
+		ListCell *lc;
+		bool firststep = true;
 
-		result = bms_int_members(result,
-								 perform_pruning_step(context, step, result));
-	}
+		/*
+		 * Below we process each partition pruning step one by one.  With each
+		 * step we the intersect the result with the previously taken steps so
+		 * that we end up with a minimal set of matching partition indexes.  When
+		 * performing the first step, we take the entire result, so we've
+		 * something to intersect on subsequent steps.
+		 */
 
-	return result;
+		foreach(lc, pruning_steps)
+		{
+			PartitionPruneStep *step = lfirst(lc);
+			Bitmapset		   *stepresult;
+
+			stepresult = perform_pruning_step(context, step);
+
+			if (firststep)
+			{
+				result = stepresult;
+				firststep = false;
+			}
+			else
+				result = bms_int_members(result, stepresult);
+		}
+		return result;
+	}
 }
 
 /* Module-local functions */
@@ -1609,36 +1627,27 @@ get_matching_partitions(PartitionPruneContext *context,
  */
 static Bitmapset *
 perform_pruning_step(PartitionPruneContext *context,
-					 PartitionPruneStep *step,
-					 Bitmapset *srcparts)
+					 PartitionPruneStep *step)
 {
 	switch (nodeTag(step))
 	{
-		case T_PartitionPruneStepNoop:
-			/* no-op */
-			break;
-
 		case T_PartitionPruneStepOp:
 			return perform_pruning_base_step(context,
 											(PartitionPruneStepOp *) step);
 
 		case T_PartitionPruneStepCombine:
 			return perform_pruning_combine_step(context,
-										(PartitionPruneStepCombine *) step,
-										srcparts);
+										(PartitionPruneStepCombine *) step);
 
 		default:
 			elog(ERROR, "invalid partition pruning step: %d", nodeTag(step));
-			break;
+			return NULL;		/* keep compiler quiet */
 	}
-
-	return srcparts;
 }
 
 /*
  * perform_pruning_base_step
- *		Returns indexes of partitions as given by get_partitions_for_keys
- *		for information contained in a given PartitionPruneStepOp
+ *		Returns indexes of partitions which match 'opstep'.
  */
 static Bitmapset *
 perform_pruning_base_step(PartitionPruneContext *context,
@@ -1652,9 +1661,7 @@ perform_pruning_base_step(PartitionPruneContext *context,
 	nvalues = 0;
 	lc = list_head(opstep->values);
 
-	/*
-	 * Generate the partition look-up key.
-	 */
+	/* Generate the partition look-up key. */
 	for (keyno = 0; keyno < context->partnatts; keyno++)
 	{
 		if (bms_is_member(keyno, opstep->nullkeys))
@@ -1679,73 +1686,104 @@ perform_pruning_base_step(PartitionPruneContext *context,
 		}
 	}
 
-	return get_partitions_for_keys(context,
-								   opstep->opstrategy,
-								   values, nvalues,
-								   opstep->nullkeys);
+	switch (context->strategy)
+	{
+		case PARTITION_STRATEGY_HASH:
+			return get_partitions_for_keys_hash(context,
+												opstep->opstrategy,
+												values, nvalues,
+												opstep->nullkeys);
+		case PARTITION_STRATEGY_LIST:
+			return get_partitions_for_keys_list(context,
+												opstep->opstrategy,
+												values, nvalues,
+												opstep->nullkeys);
+		case PARTITION_STRATEGY_RANGE:
+			return get_partitions_for_keys_range(context,
+												 opstep->opstrategy,
+												 values, nvalues,
+												 opstep->nullkeys);
+
+		default:
+			elog(ERROR, "unexpected partition strategy: %d",
+				 (int) context->strategy);
+			return NULL;
+	}
 }
 
 /*
  * perform_pruning_combine_step
- *		Returns the set of partitions in 'srcparts' that remain after
- *		performing the pruning "combine" step specified in 'cstep'
+ *		Returns the set of partitions which match this single combine step.
  */
 static Bitmapset *
 perform_pruning_combine_step(PartitionPruneContext *context,
-							 PartitionPruneStepCombine *cstep,
-							 Bitmapset *srcparts)
+							 PartitionPruneStepCombine *cstep)
 {
+	Bitmapset *result;
 	ListCell *lc;
 
-	srcparts = bms_copy(srcparts);
 	switch (cstep->combineOp)
 	{
 		case COMBINE_OR:
-		{
-			Bitmapset *step_parts = NULL;
-
-			foreach(lc, cstep->argsteps)
 			{
-				PartitionPruneStep *step = lfirst(lc);
-				Bitmapset *argparts;
+				if (cstep->argsteps == NIL)
+					return bms_add_range(NULL, 0, context->nparts - 1);
 
-				/* Recursively get partitions by performing this step. */
-				argparts = perform_pruning_step(context, step, srcparts);
-				step_parts = bms_add_members(step_parts, argparts);
-			}
+				result = NULL;
 
-			return step_parts;
-		}
+				foreach(lc, cstep->argsteps)
+				{
+					PartitionPruneStep *step = lfirst(lc);
+					Bitmapset *argresult;
 
-		case COMBINE_AND:
-		{
-			/* First there are no unpruned partitions. */
-			Bitmapset *step_parts = bms_add_range(NULL, 0,
-												  context->nparts - 1);
+					/* Recursively get partitions by performing this step. */
+					argresult = perform_pruning_step(context, step);
+					result = bms_add_members(result, argresult);
+				}
+
+				return result;
+			}
 
-			foreach(lc, cstep->argsteps)
+		case COMBINE_AND:
 			{
-				PartitionPruneStep *step = lfirst(lc);
-				Bitmapset *argparts;
+				bool firststep;
 
-				argparts = perform_pruning_step(context, step, srcparts);
-				step_parts = bms_int_members(step_parts, argparts);
-			}
+				if (cstep->argsteps == NIL)
+					return bms_add_range(NULL, 0, context->nparts - 1);
 
-			return step_parts;
-		}
+				firststep = true;
+				result = NULL;
+				foreach(lc, cstep->argsteps)
+				{
+					PartitionPruneStep *step = lfirst(lc);
+					Bitmapset *argresult;
+
+					argresult = perform_pruning_step(context, step);
+
+					if (firststep)
+					{
+						result = argresult;
+						firststep = false;
+					}
+					else
+						result = bms_int_members(result, argresult);
+				}
+
+				return result;
+			}
 
 		case COMBINE_NOT:
 		{
-			Bitmapset *step_parts = NULL;
-			Datum *ne_datums;
-			int		n_ne_datums = list_length(cstep->argvalues),
-					i;
+			Bitmapset	   *stepresult;
+			Datum		   *ne_datums;
+			int				n_ne_datums = list_length(cstep->argvalues),
+							i;
 
 			/*
-			 * XXX- The following ad-hoc method of pruning only works for list
-			 * partitioning.  It checks for each partition if all of its
-			 * accepted values appear in ne_datums[].
+			 * Apply not-equal clauses.  This only applies in the list
+			 * partitioning case as this is the only partition type where we
+			 * have knowledge of the entire set of values that can be stored
+			 * in a given partition.
 			 */
 			ne_datums = (Datum *) palloc0(n_ne_datums * sizeof(Datum));
 			i = 0;
@@ -1756,24 +1794,26 @@ perform_pruning_combine_step(PartitionPruneContext *context,
 
 				/*
 				 * Note that we're passing 0 for partkeyidx, because there can
-				 * be only one partition key column for list partitioning.
+				 * be only one partition key with list partitioning.
 				 */
 				if (partkey_datum_from_expr(context, 0, expr, &datum))
 					ne_datums[i++] = datum;
 			}
 
-			step_parts = get_partitions_excluded_by_ne_datums(context,
+			stepresult = get_partitions_excluded_by_ne_datums(context,
 															  ne_datums,
-															  n_ne_datums);
-			return bms_del_members(srcparts, step_parts);
+															  i);
+
+			/* All partitions apart from the stepresult partitions match */
+			result = bms_add_range(NULL, 0, context->nparts - 1);
+			return bms_del_members(result, stepresult);
 		}
 
 		default:
-			/* Return the source partitions as is; should never happen. */
-			break;
+			elog(ERROR, "Invalid PartitionPruneCombineOp: %d", (int)
+				 cstep->combineOp);
+			return NULL;			/* keep compiler quiet */
 	}
-
-	return srcparts;
 }
 
 /*
@@ -1819,549 +1859,527 @@ partkey_datum_from_expr(PartitionPruneContext *context, int partkeyidx,
 }
 
 /*
- * get_partitions_for_keys
- *		Returns the index of partitions that
- *		given look up keys
- *
- * Input:
- *	See the comments above the definition of PartScanKeyInfo to see what
- *	kind of information is contained in 'keys'.
- *
- * Outputs:
- *	Bitmapset containing indexes of the selected partitions
+ * get_partitions_for_keys_hash
+ *		Determine the minimum set of partitions matching the specified values
+ *		using hash partitioning.
  */
 static Bitmapset *
-get_partitions_for_keys(PartitionPruneContext *context,
-						int opstrategy, Datum *values, int nvalues,
-						Bitmapset *nullkeys)
+get_partitions_for_keys_hash(PartitionPruneContext *context,
+							 int opstrategy, Datum *values, int nvalues,
+							 Bitmapset *nullkeys)
 {
 	FmgrInfo *partsupfunc = context->partsupfunc;
 	PartitionBoundInfo boundinfo = context->boundinfo;
-	int	   *partindices = boundinfo->indexes,
-			default_index = boundinfo->default_index;
-	Oid	   *partcollation = context->partcollation;
+	int	   *partindices = boundinfo->indexes;
 	int		partnatts = context->partnatts;
-	Bitmapset *result = NULL;
+	bool	isnull[PARTITION_MAX_KEYS];
+	int 	i;
 
-	switch (context->strategy)
+	Assert(context->strategy == PARTITION_STRATEGY_HASH);
+
+	for (i = 0; i < partnatts; i++)
+		isnull[i] = bms_is_member(i, nullkeys);
+
+	/*
+	 * For hash partitioning we can only perform pruning based on equality
+	 * clauses to the partition key or IS NULL clauses.  We also can only
+	 * prune if we have such clauses for all keys.
+	 */
+	if (nvalues == partnatts)
 	{
-		case PARTITION_STRATEGY_HASH:
-		{
-			uint64	rowHash;
-			bool	isnull[PARTITION_MAX_KEYS];
-			int 	i,
-					greatest_modulus,
-					result_index;
-
-			memset(isnull, false, partnatts * sizeof(bool));
-			if (!bms_is_empty(nullkeys))
-			{
-				i = -1;
-				while ((i = bms_next_member(nullkeys, i)) >= 0)
-				{
-					Assert(i < partnatts);
-					isnull[i] = true;
-				}
-			}
+		uint64	rowHash;
+		int		greatest_modulus,
+				result_index;
 
-			/*
-			 * In this case, can only do pruning if we know values for all
-			 * the keys and they're all non-null.
-			 */
-			if (nvalues == context->partnatts)
+		greatest_modulus = get_greatest_modulus(boundinfo);
+		rowHash = compute_hash_value(partnatts, partsupfunc, values, isnull);
+		result_index = partindices[rowHash % greatest_modulus];
+
+		if (result_index >= 0)
+			return bms_make_singleton(result_index);
+	}
+	else
+	{
+		/* clauses missing for some keys, return all partitions. */
+		return bms_add_range(NULL, 0, context->nparts - 1);
+	}
+
+	return NULL;
+}
+
+/*
+ * get_partitions_for_keys_list
+ *		Determine the minimum set of partitions matching the specified values
+ *		using list partitioning.
+ */
+static Bitmapset *
+get_partitions_for_keys_list(PartitionPruneContext *context,
+							 int opstrategy, Datum *values, int nvalues,
+							 Bitmapset *nullkeys)
+{
+	FmgrInfo *partsupfunc = context->partsupfunc;
+	PartitionBoundInfo boundinfo = context->boundinfo;
+	int	   *partindices = boundinfo->indexes;
+	int		off,
+			minoff,
+			maxoff,
+			i;
+	bool	is_equal;
+	bool	inclusive = false;
+	Bitmapset *result;
+	int		partnatts = context->partnatts;
+	int		default_index = boundinfo->default_index;
+	Oid	   *partcollation = context->partcollation;
+
+	Assert(context->strategy == PARTITION_STRATEGY_LIST);
+	Assert(partnatts == 1);
+
+	if (!bms_is_empty(nullkeys))
+	{
+		/*
+		 * Nulls may exist in only one partition - the partition whose
+		 * accepted set of values includes null or the default partition if
+		 * the former doesn't exist.
+		 */
+		if (partition_bound_accepts_nulls(boundinfo))
+			return bms_make_singleton(boundinfo->null_index);
+		else if (partition_bound_has_default(boundinfo))
+			return bms_make_singleton(default_index);
+		else
+			return NULL;
+	}
+
+	/*
+	 * If there are no datums to compare keys with, but there are partitions,
+	 * just return the default partition if one exists.
+	 */
+	if (boundinfo->ndatums == 0)
+	{
+		if (partition_bound_has_default(boundinfo))
+			return bms_make_singleton(default_index);
+		else
+			return NULL;	/* shouldn't happen */
+	}
+
+	minoff = 0;
+	maxoff = boundinfo->ndatums - 1;
+
+	/*
+	 * With range queries, always include the default list partition, because
+	 * list partitions divide the key space in a discontinuous manner, not all
+	 * values in the given range will have a partition assigned.  This may not
+	 * technically be true for some data types (e.g. integer types), however,
+	 * we currently lack any sort of infrastructure to provide us with proofs
+	 * that would allow us to do anything smarter here.
+	 */
+	if (opstrategy != BTEqualStrategyNumber &&
+		partition_bound_has_default(boundinfo))
+		result = bms_make_singleton(default_index);
+	else
+		result = NULL;
+
+	if (nvalues == 0)
+	{
+		/*
+		 * Add indexes of *all* partitions containing non-null values and
+		 * return.
+		 */
+		for (i = minoff; i <= maxoff; i++)
+			result = bms_add_member(result, partindices[i]);
+
+		return result;
+	}
+
+	switch (opstrategy)
+	{
+		case BTEqualStrategyNumber:
+			off = partition_list_bsearch(partsupfunc,
+										 partcollation,
+										 boundinfo, values[0],
+										 &is_equal);
+			if (off >= 0 && is_equal)
 			{
-				greatest_modulus = get_greatest_modulus(boundinfo);
-				rowHash = compute_hash_value(partnatts, partsupfunc, values,
-											 isnull);
-				result_index = partindices[rowHash % greatest_modulus];
-				if (result_index >= 0)
-					return bms_make_singleton(result_index);
+				/* An exact matching datum exists. */
+				Assert(partindices[off] >= 0);
+				return bms_make_singleton(partindices[off]);
 			}
+			else if (partition_bound_has_default(boundinfo))
+				return bms_make_singleton(default_index);
 			else
-				/* Can't do pruning otherwise, so return all partitions. */
-				return bms_add_range(NULL, 0, context->nparts - 1);
+				return NULL;
 			break;
-		}
 
-		case PARTITION_STRATEGY_LIST:
-		{
-			int		off,
-					minoff,
-					maxoff,
-					i;
-			bool	is_equal;
-			bool	inclusive = false;
-
-			Assert(partnatts == 1);
-
-			if (!bms_is_empty(nullkeys))
+		case BTGreaterEqualStrategyNumber:
+			inclusive = true;
+			/* fall through */
+		case BTGreaterStrategyNumber:
+			off = partition_list_bsearch(partsupfunc,
+										 partcollation,
+										 boundinfo, values[0],
+										 &is_equal);
+			if (off >= 0)
+			{
+				/* We don't want the matched datum to be in the result. */
+				if (!is_equal || !inclusive)
+					off++;
+			}
+			else
 			{
 				/*
-				 * Nulls may exist in only one partition - the partition whose
-				 * accepted set of values includes null or the default
-				 * partition if the former doesn't exist.
+				 * This case means all partition bounds are greater, which in
+				 * turn means that all partition satisfy this key.
 				 */
-				if (partition_bound_accepts_nulls(boundinfo))
-					return bms_make_singleton(boundinfo->null_index);
-				else if (partition_bound_has_default(boundinfo))
-					return bms_make_singleton(boundinfo->default_index);
-				else
-					return NULL;
+				off = 0;
 			}
 
 			/*
-			 * If there are no datums to compare keys with, but there are
-			 * partitions, just return the default partition if one exists.
+			 * off is greater than the numbers of datums we have partitions
+			 * for.  The only possible partition that could contain a match is
+			 * the default partition, which is already set in 'result' if one
+			 * exists.
 			 */
-			if (boundinfo->ndatums == 0)
-			{
-				if (partition_bound_has_default(boundinfo))
-					return bms_make_singleton(default_index);
-				else
-					return NULL;	/* shouldn't happen */
-			}
+			if (off > boundinfo->ndatums - 1)
+				return result;
+
+			minoff = off;
+			break;
 
-			minoff = 0;
-			maxoff = boundinfo->ndatums - 1;
+		case BTLessEqualStrategyNumber:
+			inclusive = true;
+			/* fall through */
+		case BTLessStrategyNumber:
+			off = partition_list_bsearch(partsupfunc,
+										 partcollation,
+										 boundinfo, values[0],
+										 &is_equal);
+			if (off >= 0 && is_equal && !inclusive)
+				off--;
 
 			/*
-			 * For range queries, always include the default list partition,
-			 * because list partitions divide the key space in a discontinuous
-			 * manner, not all values in the given range will have a partition
-			 * assigned.  This may not technically be true for some data types
-			 * (e.g. integer types), however, we currently lack any sort of
-			 * infrastructure to provide us with proofs that would allow us to
-			 * do anything smarter here.
+			 * off is smaller than the datums of all non-default partitions.
+			 * The only possible partition that could contain a match is the
+			 * default partition, which is already set in 'result' if one
+			 * exists.
 			 */
-			if (opstrategy != BTEqualStrategyNumber &&
-				partition_bound_has_default(boundinfo))
-				result = bms_add_member(result, default_index);
+			if (off < 0)
+				return result;
 
-			if (nvalues == 0)
-			{
-				/*
-				 * Add indexes of *all* partitions containing non-null
-				 * values and return.
-				 */
-				for (i = minoff; i <= maxoff; i++)
-					result = bms_add_member(result, partindices[i]);
+			maxoff = off;
+			break;
 
-				return result;
-			}
+		default:
+			elog(ERROR, "invalid strategy number %d", opstrategy);
+			break;
+	}
+
+	/* Finally add the partition indexes. */
+	for (i = minoff; i <= maxoff; i++)
+		result = bms_add_member(result, partindices[i]);
+
+	return result;
+}
+
+/*
+ * get_partitions_for_keys_range
+ *		Determine the minimum set of partitions matching the specified values
+ *		using range partitioning.
+ */
+static Bitmapset *
+get_partitions_for_keys_range(PartitionPruneContext *context,
+							  int opstrategy, Datum *values, int nvalues,
+							  Bitmapset *nullkeys)
+{
+	FmgrInfo *partsupfunc = context->partsupfunc;
+	PartitionBoundInfo boundinfo = context->boundinfo;
+	Oid	   *partcollation = context->partcollation;
+	int		partnatts = context->partnatts;
+	int		default_index = boundinfo->default_index;
+	int	   *partindices = boundinfo->indexes;
+	int		off,
+			minoff,
+			maxoff,
+			i;
+	bool	is_equal;
+	bool	inclusive = false;
+	Bitmapset *result = NULL;
+
+	Assert(context->strategy == PARTITION_STRATEGY_RANGE);
+
+	/*
+	 * If there are no datums to compare keys with, or if we got a IS NULL
+	 * clause just return the default partition, if it exists.
+	 */
+	if (boundinfo->ndatums == 0 || !bms_is_empty(nullkeys))
+	{
+		if (partition_bound_has_default(boundinfo))
+			return bms_make_singleton(default_index);
+		else
+			return NULL;
+	}
 
-			switch (opstrategy)
+	minoff = 0;
+	maxoff = boundinfo->ndatums;
+	if (nvalues == 0)
+	{
+		/*
+		 * Add indexes of *all* partitions containing non-null values and
+		 * return.
+		 */
+		if (partindices[minoff] < 0)
+			minoff++;
+		if (partindices[maxoff] < 0)
+			maxoff--;
+
+		result = bms_add_range(result, partindices[minoff],
+							   partindices[maxoff]);
+
+		if (partition_bound_has_default(boundinfo))
+			result = bms_add_member(result, default_index);
+
+		return result;
+	}
+
+	switch (opstrategy)
+	{
+		case BTEqualStrategyNumber:
+			off = partition_range_datum_bsearch(partsupfunc,
+												partcollation,
+												boundinfo,
+												nvalues, values,
+												&is_equal);
+
+			if (off >= 0 && is_equal)
 			{
-				case BTEqualStrategyNumber:
+				if (nvalues == partnatts)
 				{
-					off = partition_list_bsearch(partsupfunc,
-												 partcollation,
-												 boundinfo, values[0],
-												 &is_equal);
-					if (off >= 0 && is_equal)
-					{
-						/* An exact matching datum exists. */
-						Assert(partindices[off] >= 0);
-						return bms_make_singleton(partindices[off]);
-					}
+					/* There can only be one partition. */
+					if (partindices[off + 1] >= 0)
+						return bms_make_singleton(partindices[off + 1]);
 					else if (partition_bound_has_default(boundinfo))
 						return bms_make_singleton(default_index);
 					else
 						return NULL;
-					break;
 				}
-
-				case BTGreaterEqualStrategyNumber:
-					inclusive = true;
-					/* fall through */
-				case BTGreaterStrategyNumber:
+				else
 				{
-					off = partition_list_bsearch(partsupfunc,
-												 partcollation,
-												 boundinfo, values[0],
-												 &is_equal);
-					if (off >= 0)
+					int		saved_off = off;
+
+					/* Matched a prefix of the partition bound at off. */
+					while (off >= 1 && off < boundinfo->ndatums - 1)
 					{
-						/*
-						 * We don't want the matched datum to be in the
-						 * result.
-						 */
-						if (!is_equal || !inclusive)
-							off++;
+						int32	cmpval;
+
+						cmpval =
+							partition_rbound_datum_cmp(partsupfunc,
+											partcollation,
+											boundinfo->datums[off-1],
+											boundinfo->kind[off-1],
+											values, nvalues);
+						if (cmpval != 0)
+							break;
+						off--;
 					}
-					else
+					minoff = off;
+					off = saved_off;
+					while (off < boundinfo->ndatums - 1)
 					{
-						/*
-						 * This case means all partition bounds are
-						 * greater, which in turn means that all
-						 * partition satisfy this key.
-						 */
-						off = 0;
+						int32	cmpval;
+
+						cmpval = partition_rbound_datum_cmp(partsupfunc,
+															partcollation,
+													boundinfo->datums[off + 1],
+													boundinfo->kind[off + 1],
+															values, nvalues);
+						if (cmpval != 0)
+							break;
+						off++;
 					}
-
-					/*
-					 * off is greater than the numbers of datums we have
-					 * partitions for.  The only possible partition that
-					 * could contain a match is the default partition.
-					 * Return that, if it exists.
-					 */
-					if (off > boundinfo->ndatums - 1)
-						return partition_bound_has_default(boundinfo)
-							? bms_make_singleton(default_index)
-							: NULL;
-
-					minoff = off;
-					break;
-				}
-
-				case BTLessEqualStrategyNumber:
-					inclusive = true;
-					/* fall through */
-				case BTLessStrategyNumber:
-				{
-					off = partition_list_bsearch(partsupfunc,
-												 partcollation,
-												 boundinfo, values[0],
-												 &is_equal);
-					if (off >= 0 && is_equal && !inclusive)
-						off--;
-
-					/*
-					 * off is smaller than the datums of all non-default
-					 * partitions, meaning there isn't one to return.
-					 * Return the default partition if one exists.
-					 */
-					if (off < 0)
-						return partition_bound_has_default(boundinfo)
-							? bms_make_singleton(default_index)
-							: NULL;
-
-					maxoff = off;
-					break;
+					maxoff = off+1;
 				}
-
-				default:
-					elog(ERROR, "invalid btree operator strategy: %d",
-						 opstrategy);
-					break;
 			}
-
-			/* Finally add the partition indexes. */
-			for (i = minoff; i <= maxoff; i++)
-				result = bms_add_member(result, partindices[i]);
-		}
-		break;
-
-		case PARTITION_STRATEGY_RANGE:
-		{
-			int		off,
-					minoff,
-					maxoff,
-					i;
-			bool	is_equal;
-			bool	inclusive = false;
-
-			/* Nulls may exist in only the default range partition */
-			if (!bms_is_empty(nullkeys))
-				return partition_bound_has_default(boundinfo)
-						? bms_make_singleton(boundinfo->default_index)
-						: NULL;
-
-			/*
-			 * If there are no datums to compare keys with, but there are
-			 * partitions, just return the default partition if one exists.
-			 */
-			if (boundinfo->ndatums == 0)
+			else if (off >= 0)
 			{
-				if (partition_bound_has_default(boundinfo))
+				if (partindices[off+1] >= 0)
+					minoff = maxoff = off + 1;
+				else if (partition_bound_has_default(boundinfo))
 					return bms_make_singleton(default_index);
 				else
-					return NULL;	/* shouldn't happen */
+					return NULL;
 			}
+			else if (partition_bound_has_default(boundinfo))
+				return bms_make_singleton(default_index);
+			else
+				return NULL;
+
+			if (partindices[minoff] < 0 &&
+				minoff < boundinfo->ndatums)
+				minoff++;
+			if (partindices[maxoff] < 0 && maxoff >= 1)
+				maxoff--;
+			break;
+
+		case BTGreaterEqualStrategyNumber:
+			inclusive = true;
+			/* fall through */
+		case BTGreaterStrategyNumber:
+			off = partition_range_datum_bsearch(partsupfunc,
+												partcollation,
+												boundinfo,
+												nvalues, values,
+												&is_equal);
 
-			minoff = 0;
-			maxoff = boundinfo->ndatums;
-			if (nvalues == 0)
+			if (off < 0)
 			{
 				/*
-				 * Add indexes of *all* partitions containing non-null
-				 * values and return.
+				 * All partition bounds are greater than the key, so include
+				 * all partitions in the result.
 				 */
-				if (partindices[minoff] < 0)
-					minoff++;
-				if (partindices[maxoff] < 0)
-					maxoff--;
-				result = bms_add_range(result,
-									   partindices[minoff],
-									   partindices[maxoff]);
-				if (partition_bound_has_default(boundinfo))
-					result = bms_add_member(result, default_index);
-				return result;
+				off = 0;
 			}
-
-			switch (opstrategy)
+			else
 			{
-				case BTEqualStrategyNumber:
+				if (is_equal && nvalues < partnatts)
 				{
-					off = partition_range_datum_bsearch(partsupfunc,
-														partcollation,
-														boundinfo,
-														nvalues, values,
-														&is_equal);
-
-					if (off >= 0 && is_equal)
+					/* Matched a prefix of the partition bound at off. */
+					while (off < boundinfo->ndatums - 1)
 					{
-						if (nvalues == partnatts)
+						int32	cmpval;
+						int		nextoff;
+
+						nextoff = inclusive ? off - 1 : off + 1;
+						cmpval =
+							partition_rbound_datum_cmp(partsupfunc,
+										partcollation,
+										boundinfo->datums[nextoff],
+										boundinfo->kind[nextoff],
+										values, nvalues);
+						if (cmpval != 0)
 						{
-							/* There can only be one partition. */
-							if (partindices[off+1] >= 0)
-								return bms_make_singleton(partindices[off+1]);
-							else if (partition_bound_has_default(boundinfo))
-								return bms_make_singleton(default_index);
-							else
-								return NULL;
-						}
-						else
-						{
-							int		saved_off = off;
-
-							/*
-							 * Matched a prefix of the partition bound at off.
-							 */
-							while (off >= 1 && off < boundinfo->ndatums - 1)
-							{
-								int32	cmpval;
-
-								cmpval =
-									partition_rbound_datum_cmp(partsupfunc,
-													partcollation,
-													boundinfo->datums[off-1],
-													boundinfo->kind[off-1],
-													values, nvalues);
-								if (cmpval != 0)
-									break;
-								off--;
-							}
-							minoff = off;
-							off = saved_off;
-							while (off < boundinfo->ndatums - 1)
-							{
-								int32	cmpval;
-
-								cmpval =
-									partition_rbound_datum_cmp(partsupfunc,
-													partcollation,
-													boundinfo->datums[off+1],
-													boundinfo->kind[off+1],
-													values, nvalues);
-								if (cmpval != 0)
-									break;
+							if (!inclusive)
 								off++;
-							}
-							maxoff = off+1;
+							break;
 						}
+						off = nextoff;
 					}
-					else if (off >= 0)
-					{
-						if (partindices[off+1] >= 0)
-							minoff = maxoff = off + 1;
-						else if (partition_bound_has_default(boundinfo))
-							return bms_make_singleton(default_index);
-						else
-							return NULL;
-					}
-					else if (partition_bound_has_default(boundinfo))
-						return bms_make_singleton(default_index);
-					else
-						return NULL;
-
-					if (partindices[minoff] < 0 &&
-						minoff < boundinfo->ndatums)
-						minoff++;
-					if (partindices[maxoff] < 0 && maxoff >= 1)
-						maxoff--;
-					break;
 				}
+				else
+					off++;
+			}
 
-				case BTGreaterEqualStrategyNumber:
-					inclusive = true;
-					/* fall through */
-				case BTGreaterStrategyNumber:
-				{
-					off = partition_range_datum_bsearch(partsupfunc,
-														partcollation,
-														boundinfo,
-														nvalues, values,
-														&is_equal);
-
-					if (off < 0)
-					{
-						/*
-						 * All partition bounds are greater than the key, so
-						 * include all partitions in the result.
-						 */
-						off = 0;
-					}
-					else
-					{
-						if (is_equal && nvalues < partnatts)
-						{
-							/*
-							 * Matched a prefix of the partition bound at off.
-							 */
-							while (off < boundinfo->ndatums - 1)
-							{
-								int32	cmpval;
-								int		nextoff;
+			minoff = off;
+			break;
 
-								nextoff = inclusive ? off - 1 : off + 1;
-								cmpval =
-									partition_rbound_datum_cmp(partsupfunc,
+		case BTLessEqualStrategyNumber:
+			inclusive = true;
+			/* fall through */
+		case BTLessStrategyNumber:
+			off = partition_range_datum_bsearch(partsupfunc,
 												partcollation,
-												boundinfo->datums[nextoff],
-												boundinfo->kind[nextoff],
-												values, nvalues);
-								if (cmpval != 0)
-								{
-									if (!inclusive)
-										off++;
-									break;
-								}
-								off = nextoff;
-							}
-						}
-						else
-							off++;
-					}
-
-					minoff = off;
-					break;
-				}
+												boundinfo,
+												nvalues, values,
+												&is_equal);
 
-				case BTLessEqualStrategyNumber:
-					inclusive = true;
-					/* fall through */
-				case BTLessStrategyNumber:
+			if (off >= 0)
+			{
+				/* Matched prefix of the partition bound at off. */
+				if (is_equal && nvalues < partnatts)
 				{
-					off = partition_range_datum_bsearch(partsupfunc,
-														partcollation,
-														boundinfo,
-														nvalues, values,
-														&is_equal);
-
-					if (off >= 0)
+					while (off < boundinfo->ndatums - 1)
 					{
-						/*
-						 * Matched prefix of the partition bound at off.
-						 */
-						if (is_equal && nvalues < partnatts)
-						{
-							while (off < boundinfo->ndatums - 1)
-							{
-								int32	cmpval;
-								int		nextoff;
+						int32	cmpval;
+						int		nextoff;
 
-								nextoff = inclusive ? off + 1 : off - 1;
-								cmpval =
-									partition_rbound_datum_cmp(partsupfunc,
-												partcollation,
+						nextoff = inclusive ? off + 1 : off - 1;
+						cmpval = partition_rbound_datum_cmp(partsupfunc,
+															partcollation,
 												boundinfo->datums[nextoff],
-												boundinfo->kind[nextoff],
-												values, nvalues);
-								if (cmpval != 0)
-								{
-									if (!inclusive)
-										off--;
-									break;
-								}
-								off = nextoff;
-							}
-
-							off++;
+													boundinfo->kind[nextoff],
+															values, nvalues);
+						if (cmpval != 0)
+						{
+							if (!inclusive)
+								off--;
+							break;
 						}
-						else if (!is_equal || inclusive)
-							off++;
-					}
-					else
-					{
-						/*
-						 * All partition bounds are greater than the key, so
-						 * select none of the partitions, except the default.
-						 */
-						if (partition_bound_has_default(boundinfo))
-							return bms_make_singleton(default_index);
-						return NULL;
+						off = nextoff;
 					}
 
-					maxoff = off;
-					break;
+					off++;
 				}
-
-				default:
-					elog(ERROR, "invalid btree operator strategy: %d",
-						 opstrategy);
-					break;
+				else if (!is_equal || inclusive)
+					off++;
 			}
-
-			Assert (minoff >= 0 && maxoff >= 0);
-			if (partindices[minoff] < 0)
+			else
 			{
-				int		lastkey = nvalues - 1;
+				/*
+				 * All partition bounds are greater than the key, so select
+				 * none of the partitions, except the default.
+				 */
+				if (partition_bound_has_default(boundinfo))
+					return bms_make_singleton(default_index);
+				return NULL;
+			}
 
-				if (minoff >=0 && minoff < boundinfo->ndatums &&
-					boundinfo->kind[minoff][lastkey] ==
-									PARTITION_RANGE_DATUM_VALUE &&
-					partition_bound_has_default(boundinfo))
-					result = bms_add_member(result, default_index);
+			maxoff = off;
+			break;
 
-				minoff++;
-			}
+		default:
+			elog(ERROR, "invalid strategy number %d", opstrategy);
+			break;
+	}
 
-			if (maxoff >= 1 && partindices[maxoff] < 0)
-			{
-				int		lastkey = nvalues - 1;
+	Assert (minoff >= 0 && maxoff >= 0);
+	if (partindices[minoff] < 0)
+	{
+		int		lastkey = nvalues - 1;
 
-				if (maxoff >=0 && maxoff <= boundinfo->ndatums &&
-					boundinfo->kind[maxoff - 1][lastkey] ==
-									PARTITION_RANGE_DATUM_VALUE &&
-					partition_bound_has_default(boundinfo))
-					result = bms_add_member(result, default_index);
+		if (minoff >=0 && minoff < boundinfo->ndatums &&
+			boundinfo->kind[minoff][lastkey] ==
+							PARTITION_RANGE_DATUM_VALUE &&
+			partition_bound_has_default(boundinfo))
+			result = bms_add_member(result, default_index);
 
-				maxoff--;
-			}
+		minoff++;
+	}
 
-			if (minoff <= maxoff)
-				result = bms_add_range(result,
-									   partindices[minoff],
-									   partindices[maxoff]);
+	if (maxoff >= 1 && partindices[maxoff] < 0)
+	{
+		int		lastkey = nvalues - 1;
 
-			if (partition_bound_has_default(boundinfo))
-			{
-				/*
-				 * Since partition keys with nulls are mapped to the default
-				 * range partition, we must include the default partition if
-				 * some keys could be null.
-				 */
-				if (nvalues < partnatts)
-					result = bms_add_member(result, default_index);
+		if (maxoff >=0 && maxoff <= boundinfo->ndatums &&
+			boundinfo->kind[maxoff - 1][lastkey] ==
+							PARTITION_RANGE_DATUM_VALUE &&
+			partition_bound_has_default(boundinfo))
+			result = bms_add_member(result, default_index);
 
-				/*
-				 * There may exist a range of values unassigned to any
-				 * non-default partition between the datums at minoff and
-				 * maxoff.  Add the default partition in that case.
-				 */
-				for (i = minoff; i <= maxoff; i++)
-				{
-					if (partindices[i] < 0)
-						return bms_add_member(result, default_index);
-				}
-			}
-		}
-		break;
+		maxoff--;
+	}
 
-		default:
-			elog(ERROR, "unexpected partition strategy: %d",
-				 context->strategy);
-			break;
+	if (minoff <= maxoff)
+		result = bms_add_range(result,
+								partindices[minoff],
+								partindices[maxoff]);
+
+	if (partition_bound_has_default(boundinfo))
+	{
+		/*
+		 * Since partition keys with nulls are mapped to the default range
+		 * partition, we must include the default partition if some keys could
+		 * be null.
+		 */
+		if (nvalues < partnatts)
+			result = bms_add_member(result, default_index);
+
+		/*
+		 * There may exist a range of values unassigned to any non-default
+		 * partition between the datums at minoff and maxoff.  Add the default
+		 * partition in that case.
+		 */
+		for (i = minoff; i <= maxoff; i++)
+		{
+			if (partindices[i] < 0)
+				return bms_add_member(result, default_index);
+		}
 	}
 
 	return result;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2f1d5bd2a1e..ea890385a33 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2132,19 +2132,6 @@ _copyOnConflictExpr(const OnConflictExpr *from)
 	return newnode;
 }
 
-/*
- * _copyPartitionPruneStepNoop
- */
-static PartitionPruneStepNoop *
-_copyPartitionPruneStepNoop(const PartitionPruneStepNoop *from)
-{
-	PartitionPruneStepNoop *newnode = makeNode(PartitionPruneStepNoop);
-
-	/* Nothing to copy. */
-
-	return newnode;
-}
-
 /*
  * _copyPartitionPruneStepOp
  */
@@ -5051,9 +5038,6 @@ copyObjectImpl(const void *from)
 		case T_OnConflictExpr:
 			retval = _copyOnConflictExpr(from);
 			break;
-		case T_PartitionPruneStepNoop:
-			retval = _copyPartitionPruneStepNoop(from);
-			break;
 		case T_PartitionPruneStepOp:
 			retval = _copyPartitionPruneStepOp(from);
 			break;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 9f50552e4e9..0189a931e97 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -2146,9 +2146,6 @@ expression_tree_walker(Node *node,
 					return true;
 			}
 			break;
-		case T_PartitionPruneStepNoop:
-			/* No sub-structure. */
-			return true;
 		case T_PartitionPruneStepOp:
 			{
 				PartitionPruneStepOp *opstep = (PartitionPruneStepOp *) node;
@@ -2953,16 +2950,6 @@ expression_tree_mutator(Node *node,
 				return (Node *) newnode;
 			}
 			break;
-		case T_PartitionPruneStepNoop:
-			{
-				PartitionPruneStepNoop *noopstep = (PartitionPruneStepNoop *) node;
-				PartitionPruneStepNoop *newnode;
-
-				FLATCOPY(newnode, noopstep, PartitionPruneStepNoop);
-
-				return (Node *) newnode;
-			}
-			break;
 		case T_PartitionPruneStepOp:
 			{
 				PartitionPruneStepOp *opstep = (PartitionPruneStepOp *) node;
diff --git a/src/backend/optimizer/util/partprune.c b/src/backend/optimizer/util/partprune.c
index aa18cc2ae44..95adf3e7abf 100644
--- a/src/backend/optimizer/util/partprune.c
+++ b/src/backend/optimizer/util/partprune.c
@@ -284,17 +284,16 @@ generate_partition_pruning_steps_internal(RelOptInfo *rel, List *clauses,
 					{
 						/*
 						 * No steps means the arg wasn't a clause matching
-						 * this partition key.  We cannot prune using such
-						 * an arg.  To indicate that to the pruning code,
-						 * we must construct a PartitionPruneStepNoop and
-						 * append it as an argument of the OR pruning combine
-						 * step.  However, if we can prove using constraint
-						 * exclusion that the clause refutes the table's
-						 * partition constraint (if it's sub-partitioned),
-						 * we need not bother with that.
+						 * this partition key.  We cannot prune using such an
+						 * arg.  To indicate that to the pruning code, we must
+						 * construct a PartitionPruneStepCombine and set the
+						 * argsteps to an empty List.  However, if we can
+						 * prove using constraint exclusion that the clause
+						 * refutes the table's partition constraint (if it's
+						 * sub-partitioned), we need not bother with that.
 						 */
 						List *partconstr = rel->partition_qual;
-						PartitionPruneStepNoop *noop;
+						PartitionPruneStepCombine *orstep;
 
 						if (partconstr)
 						{
@@ -309,8 +308,10 @@ generate_partition_pruning_steps_internal(RelOptInfo *rel, List *clauses,
 								continue;
 						}
 
-						noop = makeNode(PartitionPruneStepNoop);
-						all_arg_steps = lappend(all_arg_steps, noop);
+						orstep = makeNode(PartitionPruneStepCombine);
+						orstep->combineOp = COMBINE_OR;
+						orstep->argsteps = NIL;
+						all_arg_steps = lappend(all_arg_steps, orstep);
 					}
 				}
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 959fed848b2..7a14bbb10b1 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -192,7 +192,6 @@ typedef enum NodeTag
 	T_OnConflictExpr,
 	T_IntoClause,
 	T_PartitionPruneStep,
-	T_PartitionPruneStepNoop,
 	T_PartitionPruneStepOp,
 	T_PartitionPruneStepCombine,
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 47ac3da77a1..2af9512dd92 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1516,12 +1516,6 @@ typedef struct PartitionPruneStep
 	NodeTag		type;
 } PartitionPruneStep;
 
-/* a no-op step that doesn't prune any of the partitions. */
-typedef struct PartitionPruneStepNoop
-{
-	PartitionPruneStep step;
-} PartitionPruneStepNoop;
-
 typedef struct PartitionPruneStepOp
 {
 	PartitionPruneStep step;
