diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 99c5ad9..eb311fa 100644
*** a/src/backend/optimizer/path/costsize.c
--- b/src/backend/optimizer/path/costsize.c
*************** cost_qual_eval_walker(Node *node, cost_q
*** 3929,3936 ****
  	}
  	else if (IsA(node, SubLink))
  	{
! 		/* This routine should not be applied to un-planned expressions */
! 		elog(ERROR, "cannot handle unplanned sub-select");
  	}
  	else if (IsA(node, SubPlan))
  	{
--- 3929,3943 ----
  	}
  	else if (IsA(node, SubLink))
  	{
! 		/*
! 		 * In normal usage we won't see un-planned SubLinks here, because they
! 		 * will previously have been converted to SubPlans or InitPlans.
! 		 * However, we can reach here due to inline_function() wishing to
! 		 * estimate costs for function parameter expressions.  Arbitrarily
! 		 * return a fairly large cost to discourage inlining when that would
! 		 * cause multiple eval of a subplan.
! 		 */
! 		context->total.per_tuple += 100000 * cpu_operator_cost;
  	}
  	else if (IsA(node, SubPlan))
  	{
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f0ef102..84fdcc6 100644
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
*************** evaluate_function(Oid funcid, Oid result
*** 4645,4651 ****
   * unreasonably expensive to evaluate.  The expensiveness check not only
   * prevents us from doing multiple evaluations of an expensive parameter
   * at runtime, but is a safety value to limit growth of an expression due
!  * to repeated inlining.
   *
   * We must also beware of changing the volatility or strictness status of
   * functions by inlining them.
--- 4645,4653 ----
   * unreasonably expensive to evaluate.  The expensiveness check not only
   * prevents us from doing multiple evaluations of an expensive parameter
   * at runtime, but is a safety value to limit growth of an expression due
!  * to repeated inlining.  (Currently, the expensiveness check is expressed
!  * as a limit on the total additional cost of extra parameter evaluations,
!  * rather than of any one parameter.)
   *
   * We must also beware of changing the volatility or strictness status of
   * functions by inlining them.
*************** inline_function(Oid funcid, Oid result_t
*** 4682,4687 ****
--- 4684,4690 ----
  	Query	   *querytree;
  	Node	   *newexpr;
  	int		   *usecounts;
+ 	Cost		delta_param_cost;
  	ListCell   *arg;
  	int			i;
  
*************** inline_function(Oid funcid, Oid result_t
*** 4876,4882 ****
  	newexpr = substitute_actual_parameters(newexpr, funcform->pronargs,
  										   args, usecounts);
  
! 	/* Now check for parameter usage */
  	i = 0;
  	foreach(arg, args)
  	{
--- 4879,4889 ----
  	newexpr = substitute_actual_parameters(newexpr, funcform->pronargs,
  										   args, usecounts);
  
! 	/*
! 	 * Check for parameter usage, and estimate the delta in evaluation cost
! 	 * resulting from parameters possibly being evaluated more than once.
! 	 */
! 	delta_param_cost = 0.0;
  	i = 0;
  	foreach(arg, args)
  	{
*************** inline_function(Oid funcid, Oid result_t
*** 4888,4922 ****
  			if (funcform->proisstrict)
  				goto fail;
  		}
! 		else if (usecounts[i] != 1)
  		{
! 			/* Param used multiple times: uncool if expensive or volatile */
! 			QualCost	eval_cost;
! 
! 			/*
! 			 * We define "expensive" as "contains any subplan or more than 10
! 			 * operators".  Note that the subplan search has to be done
! 			 * explicitly, since cost_qual_eval() will barf on unplanned
! 			 * subselects.
! 			 */
! 			if (contain_subplans(param))
! 				goto fail;
! 			cost_qual_eval(&eval_cost, list_make1(param), NULL);
! 			if (eval_cost.startup + eval_cost.per_tuple >
! 				10 * cpu_operator_cost)
  				goto fail;
  
  			/*
! 			 * Check volatility last since this is more expensive than the
! 			 * above tests
  			 */
! 			if (contain_volatile_functions(param))
! 				goto fail;
  		}
  		i++;
  	}
  
  	/*
  	 * Whew --- we can make the substitution.  Copy the modified expression
  	 * out of the temporary memory context, and clean up.
  	 */
--- 4895,4939 ----
  			if (funcform->proisstrict)
  				goto fail;
  		}
! 		else if (usecounts[i] > 1)
  		{
! 			/* Param used multiple times: uncool if volatile */
! 			if (contain_volatile_functions(param))
  				goto fail;
+ 		}
  
+ 		if (usecounts[i] != 1)
+ 		{
  			/*
! 			 * Estimate the evaluation cost of the param, and charge for the
! 			 * N-1 extra evaluations --- or, if it's not used at all, credit
! 			 * the savings.  Note that we consider only per-tuple cost, not
! 			 * startup cost.  Ideally we'd account for that somehow, but it's
! 			 * hard since we have as yet no idea how many times the query will
! 			 * execute this expression.
  			 */
! 			QualCost	eval_cost;
! 
! 			cost_qual_eval_node(&eval_cost, param, context->root);
! 			delta_param_cost += eval_cost.per_tuple * (usecounts[i] - 1);
  		}
+ 
  		i++;
  	}
  
  	/*
+ 	 * If the incremental cost of multiple parameter evaluation exceeds the
+ 	 * nominal cost of the function we're inlining, don't inline.  With the
+ 	 * default cost for a SQL-language function, this rule causes us to not
+ 	 * inline if multiple evaluation would add more than 100 times
+ 	 * cpu_operator_cost.  However, function authors can adjust the claimed
+ 	 * cost of inlinable functions to encourage or discourage inlining in the
+ 	 * presence of multiple parameter usage.
+ 	 */
+ 	if (delta_param_cost > funcform->procost * cpu_operator_cost)
+ 		goto fail;
+ 
+ 	/*
  	 * Whew --- we can make the substitution.  Copy the modified expression
  	 * out of the temporary memory context, and clean up.
  	 */
