diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 59f34f5cac..79494db3fb 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -39,6 +39,7 @@
 #include "access/nbtree.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_opfamily.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -83,6 +84,17 @@ typedef enum PartClauseMatchStatus
 	PARTCLAUSE_UNSUPPORTED
 } PartClauseMatchStatus;
 
+/*
+ * PruneEnvironment
+ *		Provides the pruning code context about where the pruning steps
+ *		will be executed.
+ */
+typedef enum PruneEnvironment
+{
+	PRUNEENV_PLANNER,
+	PRUNEENV_EXECUTOR
+} PruneEnvironment;
+
 /*
  * GeneratePruningStepsContext
  *		Information about the current state of generation of "pruning steps"
@@ -116,11 +128,11 @@ static List *make_partitionedrel_pruneinfo(PlannerInfo *root,
 							  int *relid_subplan_map,
 							  List *partitioned_rels, List *prunequal,
 							  Bitmapset **matchedsubplans);
-static List *gen_partprune_steps(RelOptInfo *rel, List *clauses,
-					bool *contradictory);
+static List *gen_partprune_steps(RelOptInfo *rel, PruneEnvironment pruneenv,
+					List *clauses, bool *contradictory);
 static List *gen_partprune_steps_internal(GeneratePruningStepsContext *context,
-							 RelOptInfo *rel, List *clauses,
-							 bool *contradictory);
+							 RelOptInfo *rel, PruneEnvironment pruneenv,
+							 List *clauses, bool *contradictory);
 static PartitionPruneStep *gen_prune_step_op(GeneratePruningStepsContext *context,
 				  StrategyNumber opstrategy, bool op_is_ne,
 				  List *exprs, List *cmpfns, Bitmapset *nullkeys);
@@ -132,6 +144,7 @@ static PartitionPruneStep *gen_prune_steps_from_opexps(PartitionScheme part_sche
 							List **keyclauses, Bitmapset *nullkeys);
 static PartClauseMatchStatus match_clause_to_partition_key(RelOptInfo *rel,
 							  GeneratePruningStepsContext *context,
+							  PruneEnvironment pruneenv,
 							  Expr *clause, Expr *partkey, int partkeyidx,
 							  bool *clause_is_not_null,
 							  PartClauseInfo **pc, List **clause_steps);
@@ -410,8 +423,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
 		}
 
 		/* Convert pruning qual to pruning steps. */
-		pruning_steps = gen_partprune_steps(subpart, partprunequal,
-											&contradictory);
+		pruning_steps = gen_partprune_steps(subpart, PRUNEENV_EXECUTOR,
+											partprunequal, &contradictory);
 
 		if (contradictory)
 		{
@@ -523,13 +536,16 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
 /*
  * gen_partprune_steps
  *		Process 'clauses' (a rel's baserestrictinfo list of clauses) and return
- *		a list of "partition pruning steps"
+ *		a list of "partition pruning steps".
+ *
+ * 'pruneenv' defines where the pruning steps will be executed.
  *
  * If the clauses in the input list are contradictory or there is a
  * pseudo-constant "false", *contradictory is set to true upon return.
  */
 static List *
-gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory)
+gen_partprune_steps(RelOptInfo *rel, PruneEnvironment pruneenv, List *clauses,
+					bool *contradictory)
 {
 	GeneratePruningStepsContext context;
 
@@ -567,7 +583,8 @@ gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory)
 	}
 
 	/* Down into the rabbit-hole. */
-	gen_partprune_steps_internal(&context, rel, clauses, contradictory);
+	gen_partprune_steps_internal(&context, rel, pruneenv, clauses,
+								 contradictory);
 
 	return context.steps;
 }
@@ -605,7 +622,8 @@ prune_append_rel_partitions(RelOptInfo *rel)
 	 * Process clauses.  If the clauses are found to be contradictory, we can
 	 * return the empty set.
 	 */
-	pruning_steps = gen_partprune_steps(rel, clauses, &contradictory);
+	pruning_steps = gen_partprune_steps(rel, PRUNEENV_PLANNER, clauses,
+										&contradictory);
 	if (contradictory)
 		return NULL;
 
@@ -761,8 +779,8 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
  */
 static List *
 gen_partprune_steps_internal(GeneratePruningStepsContext *context,
-							 RelOptInfo *rel, List *clauses,
-							 bool *contradictory)
+							 RelOptInfo *rel, PruneEnvironment pruneenv,
+							 List *clauses, bool *contradictory)
 {
 	PartitionScheme part_scheme = rel->part_scheme;
 	List	   *keyclauses[PARTITION_MAX_KEYS];
@@ -822,6 +840,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
 
 					argsteps =
 						gen_partprune_steps_internal(context, rel,
+													 pruneenv,
 													 list_make1(arg),
 													 &arg_contradictory);
 					if (!arg_contradictory)
@@ -906,7 +925,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
 				 * recurse and later combine the component partitions sets
 				 * using a combine step.
 				 */
-				argsteps = gen_partprune_steps_internal(context, rel, args,
+				argsteps = gen_partprune_steps_internal(context, rel, pruneenv, args,
 														contradictory);
 				if (*contradictory)
 					return NIL;
@@ -948,7 +967,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
 			PartClauseInfo *pc = NULL;
 			List	   *clause_steps = NIL;
 
-			switch (match_clause_to_partition_key(rel, context,
+			switch (match_clause_to_partition_key(rel, context, pruneenv,
 												  clause, partkey, i,
 												  &clause_is_not_null,
 												  &pc, &clause_steps))
@@ -1562,6 +1581,7 @@ gen_prune_steps_from_opexps(PartitionScheme part_scheme,
 static PartClauseMatchStatus
 match_clause_to_partition_key(RelOptInfo *rel,
 							  GeneratePruningStepsContext *context,
+							  PruneEnvironment pruneenv,
 							  Expr *clause, Expr *partkey, int partkeyidx,
 							  bool *clause_is_not_null, PartClauseInfo **pc,
 							  List **clause_steps)
@@ -1651,13 +1671,39 @@ match_clause_to_partition_key(RelOptInfo *rel,
 		 * matter which partkey it's matched to.
 		 */
 
-		/*
-		 * We can't prune using an expression with Vars.  (Report failure as
-		 * UNSUPPORTED, not NOMATCH: as in the no-commutator case above, we
-		 * now know there are Vars on both sides, so it's no good.)
-		 */
-		if (contain_var_clause((Node *) expr))
-			return PARTCLAUSE_UNSUPPORTED;
+		if (pruneenv == PRUNEENV_PLANNER)
+		{
+			/*
+			 * When pruning in the planner, we only support pruning using
+			 * constants.  Immutable functions will have been folded to consts
+			 * already so we could be dealing with a Var or an unsupported
+			 * function call.
+			 */
+			if (!IsA(expr, Const))
+				return PARTCLAUSE_UNSUPPORTED;
+
+			/*
+			 * Only allow immutable comparison functions when called during
+			 * planning.
+			 */
+			if (op_volatile(opno) != PROVOLATILE_IMMUTABLE)
+				return PARTCLAUSE_UNSUPPORTED;
+		}
+		else
+		{
+			/*
+			 * Otherwise, non-consts are supported, but we can't prune using
+			 * an expression with Vars.  (Report failure as UNSUPPORTED, not
+			 * NOMATCH: as in the no-commutator case above, we now know there
+			 * are Vars on both sides, so it's no good.)
+			 */
+			if (contain_var_clause((Node *) expr))
+				return PARTCLAUSE_UNSUPPORTED;
+
+			/* And we must reject anything containing a volatile function. */
+			if (contain_volatile_functions((Node *) expr))
+				return PARTCLAUSE_UNSUPPORTED;
+		}
 
 		/*
 		 * Only allow strict operators.  This will guarantee nulls are
@@ -1666,10 +1712,6 @@ match_clause_to_partition_key(RelOptInfo *rel,
 		if (!op_strict(opno))
 			return PARTCLAUSE_UNSUPPORTED;
 
-		/* We can't use any volatile expressions to prune partitions. */
-		if (contain_volatile_functions((Node *) expr))
-			return PARTCLAUSE_UNSUPPORTED;
-
 		/*
 		 * See if the operator is relevant to the partitioning opfamily.
 		 *
@@ -1945,7 +1987,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
 
 		/* Finally, generate steps */
 		*clause_steps =
-			gen_partprune_steps_internal(context, rel, elem_clauses,
+			gen_partprune_steps_internal(context, rel, pruneenv, elem_clauses,
 										 &contradictory);
 		if (contradictory)
 			return PARTCLAUSE_MATCH_CONTRADICT;
@@ -2961,15 +3003,18 @@ analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps,
 	{
 		PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc);
 		ListCell   *lc2;
+		ListCell   *lc3;
 		int			keyno;
 
 		if (!IsA(step, PartitionPruneStepOp))
 			continue;
 
 		keyno = 0;
-		foreach(lc2, step->exprs)
+		forboth(lc2, step->exprs, lc3, step->cmpfns)
 		{
 			Expr	   *expr = lfirst(lc2);
+			Oid			fnoid = lfirst_oid(lc3);
+
 
 			if (!IsA(expr, Const))
 			{
@@ -2992,6 +3037,12 @@ analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps,
 
 				doruntimeprune = true;
 			}
+			else if (func_volatile(fnoid) != PROVOLATILE_IMMUTABLE)
+			{
+				/* No need to check for exec params inside a Const */
+				doruntimeprune = true;
+				pinfo->do_initial_prune = true;
+			}
 			keyno++;
 		}
 	}
