On 2017-01-18 16:56:46 -0500, Tom Lane wrote:
> Andres Freund <and...@anarazel.de> writes:
> I have not actually looked at 0003 at all yet.  So yeah, please post
> for review after you're done rebasing.

Here's a rebased and lightly massaged version. I'm vanishing in a
meeting for a bit, thought it'd be more useful to get it now rather than
later.

(I also noticed the previous patch should have had a catversion bump :(,
will do after the meeting).

- Andres
>From 5a0bdc9543291c051c2dbab26492f6e0320e8f82 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 18 Jan 2017 13:51:47 -0800
Subject: [PATCH] Remove obsoleted code relating to targetlist SRF evaluation.

Author: Andres Freund
Discussion: https://postgr.es/m/20160822214023.aaxz5l4igypow...@alap3.anarazel.de
---
 src/backend/catalog/index.c               |   3 +-
 src/backend/catalog/partition.c           |   5 +-
 src/backend/commands/copy.c               |   2 +-
 src/backend/commands/prepare.c            |   3 +-
 src/backend/commands/tablecmds.c          |   3 +-
 src/backend/commands/typecmds.c           |   2 +-
 src/backend/executor/execAmi.c            |  44 +-
 src/backend/executor/execQual.c           | 919 ++++++++----------------------
 src/backend/executor/execScan.c           |  30 +-
 src/backend/executor/execUtils.c          |   6 -
 src/backend/executor/nodeAgg.c            |  52 +-
 src/backend/executor/nodeBitmapHeapscan.c |   2 -
 src/backend/executor/nodeCtescan.c        |   2 -
 src/backend/executor/nodeCustom.c         |   2 -
 src/backend/executor/nodeForeignscan.c    |   2 -
 src/backend/executor/nodeFunctionscan.c   |   2 -
 src/backend/executor/nodeGather.c         |  25 +-
 src/backend/executor/nodeGroup.c          |  42 +-
 src/backend/executor/nodeHash.c           |   2 +-
 src/backend/executor/nodeHashjoin.c       |  58 +-
 src/backend/executor/nodeIndexonlyscan.c  |   2 -
 src/backend/executor/nodeIndexscan.c      |  11 +-
 src/backend/executor/nodeLimit.c          |  19 +-
 src/backend/executor/nodeMergejoin.c      |  59 +-
 src/backend/executor/nodeModifyTable.c    |   4 +-
 src/backend/executor/nodeNestloop.c       |  41 +-
 src/backend/executor/nodeProjectSet.c     |   2 +-
 src/backend/executor/nodeResult.c         |  33 +-
 src/backend/executor/nodeSamplescan.c     |   8 +-
 src/backend/executor/nodeSeqscan.c        |   2 -
 src/backend/executor/nodeSubplan.c        |  31 +-
 src/backend/executor/nodeSubqueryscan.c   |   2 -
 src/backend/executor/nodeTidscan.c        |   8 +-
 src/backend/executor/nodeValuesscan.c     |   5 +-
 src/backend/executor/nodeWindowAgg.c      |  58 +-
 src/backend/executor/nodeWorktablescan.c  |   2 -
 src/backend/optimizer/util/clauses.c      |   4 +-
 src/backend/optimizer/util/predtest.c     |   2 +-
 src/backend/utils/adt/domains.c           |   2 +-
 src/backend/utils/adt/xml.c               |   4 +-
 src/include/executor/executor.h           |   9 +-
 src/include/nodes/execnodes.h             |  16 +-
 src/pl/plpgsql/src/pl_exec.c              |   5 +-
 43 files changed, 346 insertions(+), 1189 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index cac0cbf7d4..26cbc0e06a 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1805,8 +1805,7 @@ FormIndexDatum(IndexInfo *indexInfo,
 				elog(ERROR, "wrong number of index expressions");
 			iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item),
 											   GetPerTupleExprContext(estate),
-											   &isNull,
-											   NULL);
+											   &isNull);
 			indexpr_item = lnext(indexpr_item);
 		}
 		values[i] = iDatum;
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 874e69d8d6..6dec75b59e 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1339,7 +1339,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
 			test_exprstate = ExecInitExpr(test_expr, NULL);
 			test_result = ExecEvalExprSwitchContext(test_exprstate,
 											  GetPerTupleExprContext(estate),
-													&isNull, NULL);
+													&isNull);
 			MemoryContextSwitchTo(oldcxt);
 			FreeExecutorState(estate);
 
@@ -1610,8 +1610,7 @@ FormPartitionKeyDatum(PartitionDispatch pd,
 				elog(ERROR, "wrong number of partition key expressions");
 			datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
 											  GetPerTupleExprContext(estate),
-											  &isNull,
-											  NULL);
+											  &isNull);
 			partexpr_item = lnext(partexpr_item);
 		}
 		values[i] = datum;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 1fd2162794..ab666b9bdd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -3395,7 +3395,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 		Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);
 
 		values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
-										 &nulls[defmap[i]], NULL);
+										 &nulls[defmap[i]]);
 	}
 
 	return true;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 1ff41661a5..7d7e3daf1e 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -413,8 +413,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
 		prm->pflags = PARAM_FLAG_CONST;
 		prm->value = ExecEvalExprSwitchContext(n,
 											   GetPerTupleExprContext(estate),
-											   &prm->isnull,
-											   NULL);
+											   &prm->isnull);
 
 		i++;
 	}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e633a50dd2..ae92b2c1b7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4461,8 +4461,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
 					values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
 														  econtext,
-													 &isnull[ex->attnum - 1],
-														  NULL);
+													 &isnull[ex->attnum - 1]);
 				}
 
 				/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 3ff6cbca56..4c33d55484 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2735,7 +2735,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 
 				conResult = ExecEvalExprSwitchContext(exprstate,
 													  econtext,
-													  &isNull, NULL);
+													  &isNull);
 
 				if (!isNull && !DatumGetBool(conResult))
 				{
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index b52cfaa41f..1ca4bcb117 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -59,7 +59,6 @@
 #include "utils/syscache.h"
 
 
-static bool TargetListSupportsBackwardScan(List *targetlist);
 static bool IndexSupportsBackwardScan(Oid indexid);
 
 
@@ -120,7 +119,7 @@ ExecReScan(PlanState *node)
 			UpdateChangedParamSet(node->righttree, node->chgParam);
 	}
 
-	/* Shut down any SRFs in the plan node's targetlist */
+	/* Call expression callbacks */
 	if (node->ps_ExprContext)
 		ReScanExprContext(node->ps_ExprContext);
 
@@ -460,8 +459,7 @@ ExecSupportsBackwardScan(Plan *node)
 	{
 		case T_Result:
 			if (outerPlan(node) != NULL)
-				return ExecSupportsBackwardScan(outerPlan(node)) &&
-					TargetListSupportsBackwardScan(node->targetlist);
+				return ExecSupportsBackwardScan(outerPlan(node));
 			else
 				return false;
 
@@ -478,13 +476,6 @@ ExecSupportsBackwardScan(Plan *node)
 				return true;
 			}
 
-		case T_SeqScan:
-		case T_TidScan:
-		case T_FunctionScan:
-		case T_ValuesScan:
-		case T_CteScan:
-			return TargetListSupportsBackwardScan(node->targetlist);
-
 		case T_SampleScan:
 			/* Simplify life for tablesample methods by disallowing this */
 			return false;
@@ -493,35 +484,34 @@ ExecSupportsBackwardScan(Plan *node)
 			return false;
 
 		case T_IndexScan:
-			return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) &&
-				TargetListSupportsBackwardScan(node->targetlist);
+			return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
 
 		case T_IndexOnlyScan:
-			return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid) &&
-				TargetListSupportsBackwardScan(node->targetlist);
+			return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
 
 		case T_SubqueryScan:
-			return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
-				TargetListSupportsBackwardScan(node->targetlist);
+			return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
 
 		case T_CustomScan:
 			{
 				uint32		flags = ((CustomScan *) node)->flags;
 
-				if ((flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN) &&
-					TargetListSupportsBackwardScan(node->targetlist))
+				if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
 					return true;
 			}
 			return false;
 
+		case T_SeqScan:
+		case T_TidScan:
+		case T_FunctionScan:
+		case T_ValuesScan:
+		case T_CteScan:
 		case T_Material:
 		case T_Sort:
-			/* these don't evaluate tlist */
 			return true;
 
 		case T_LockRows:
 		case T_Limit:
-			/* these don't evaluate tlist */
 			return ExecSupportsBackwardScan(outerPlan(node));
 
 		default:
@@ -530,18 +520,6 @@ ExecSupportsBackwardScan(Plan *node)
 }
 
 /*
- * If the tlist contains set-returning functions, we can't support backward
- * scan, because the TupFromTlist code is direction-ignorant.
- */
-static bool
-TargetListSupportsBackwardScan(List *targetlist)
-{
-	if (expression_returns_set((Node *) targetlist))
-		return false;
-	return true;
-}
-
-/*
  * An IndexScan or IndexOnlyScan node supports backward scan only if the
  * index's AM does.
  */
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index eed7e95c75..88abf596e1 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -64,40 +64,40 @@
 /* static function decls */
 static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
 				 ExprContext *econtext,
-				 bool *isNull, ExprDoneCond *isDone);
+				 bool *isNull);
 static bool isAssignmentIndirectionExpr(ExprState *exprstate);
 static Datum ExecEvalAggref(AggrefExprState *aggref,
 			   ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone);
+			   bool *isNull);
 static Datum ExecEvalWindowFunc(WindowFuncExprState *wfunc,
 				   ExprContext *econtext,
-				   bool *isNull, ExprDoneCond *isDone);
+				   bool *isNull);
 static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
-				  bool *isNull, ExprDoneCond *isDone);
+				  bool *isNull);
 static Datum ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone);
+					  bool *isNull);
 static Datum ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static Datum ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate,
 					 ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone);
+					 bool *isNull);
 static Datum ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate,
 					 ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone);
+					 bool *isNull);
 static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
-			  bool *isNull, ExprDoneCond *isDone);
+			  bool *isNull);
 static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
-				  bool *isNull, ExprDoneCond *isDone);
+				  bool *isNull);
 static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static void init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
 			MemoryContext fcacheCxt, bool allowSRF, bool needDescForSRF);
 static void ShutdownFuncExpr(Datum arg);
 static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
 				   TupleDesc *cache_field, ExprContext *econtext);
 static void ShutdownTupleDescRef(Datum arg);
-static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,
+static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
 				 List *argList, ExprContext *econtext);
 static void ExecPrepareTuplestoreResult(FuncExprState *fcache,
 							ExprContext *econtext,
@@ -106,85 +106,85 @@ static void ExecPrepareTuplestoreResult(FuncExprState *fcache,
 static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
 static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache,
 							 ExprContext *econtext,
-							 bool *isNull, ExprDoneCond *isDone);
+							 bool *isNull);
 static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,
-			 bool *isNull, ExprDoneCond *isDone);
+			 bool *isNull);
 static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,
-			 bool *isNull, ExprDoneCond *isDone);
+			 bool *isNull);
 static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,
-				 bool *isNull, ExprDoneCond *isDone);
+				 bool *isNull);
 static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
 					  ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone);
+					  bool *isNull);
 static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone);
+			bool *isNull);
 static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
-		   bool *isNull, ExprDoneCond *isDone);
+		   bool *isNull);
 static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone);
+			bool *isNull);
 static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
 					   ExprContext *econtext,
-					   bool *isNull, ExprDoneCond *isDone);
+					   bool *isNull);
 static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
-			 bool *isNull, ExprDoneCond *isDone);
+			 bool *isNull);
 static Datum ExecEvalCaseTestExpr(ExprState *exprstate,
 					 ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone);
+					 bool *isNull);
 static Datum ExecEvalArray(ArrayExprState *astate,
 			  ExprContext *econtext,
-			  bool *isNull, ExprDoneCond *isDone);
+			  bool *isNull);
 static Datum ExecEvalRow(RowExprState *rstate,
 			ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone);
+			bool *isNull);
 static Datum ExecEvalRowCompare(RowCompareExprState *rstate,
 				   ExprContext *econtext,
-				   bool *isNull, ExprDoneCond *isDone);
+				   bool *isNull);
 static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
 				 ExprContext *econtext,
-				 bool *isNull, ExprDoneCond *isDone);
+				 bool *isNull);
 static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
 			   ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone);
+			   bool *isNull);
 static Datum ExecEvalSQLValueFunction(ExprState *svfExpr,
 						 ExprContext *econtext,
-						 bool *isNull, ExprDoneCond *isDone);
+						 bool *isNull);
 static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone);
+			bool *isNull);
 static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
 			   ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone);
+			   bool *isNull);
 static Datum ExecEvalNullTest(NullTestState *nstate,
 				 ExprContext *econtext,
-				 bool *isNull, ExprDoneCond *isDone);
+				 bool *isNull);
 static Datum ExecEvalBooleanTest(GenericExprState *bstate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,
 					   ExprContext *econtext,
-					   bool *isNull, ExprDoneCond *isDone);
+					   bool *isNull);
 static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate,
 							ExprContext *econtext,
-							bool *isNull, ExprDoneCond *isDone);
+							bool *isNull);
 static Datum ExecEvalFieldSelect(FieldSelectState *fstate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static Datum ExecEvalFieldStore(FieldStoreState *fstate,
 				   ExprContext *econtext,
-				   bool *isNull, ExprDoneCond *isDone);
+				   bool *isNull);
 static Datum ExecEvalRelabelType(GenericExprState *exprstate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone);
+					bool *isNull);
 static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
 						ExprContext *econtext,
-						bool *isNull, ExprDoneCond *isDone);
+						bool *isNull);
 static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone);
+					  bool *isNull);
 static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
 						 ExprContext *econtext,
-						 bool *isNull, ExprDoneCond *isDone);
+						 bool *isNull);
 
 
 /* ----------------------------------------------------------------
@@ -195,8 +195,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
  * Each of the following routines having the signature
  *		Datum ExecEvalFoo(ExprState *expression,
  *						  ExprContext *econtext,
- *						  bool *isNull,
- *						  ExprDoneCond *isDone);
+ *						  bool *isNull);
  * is responsible for evaluating one type or subtype of ExprState node.
  * They are normally called via the ExecEvalExpr macro, which makes use of
  * the function pointer set up when the ExprState node was built by
@@ -220,22 +219,6 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
  *		return value: Datum value of result
  *		*isNull: set to TRUE if result is NULL (actual return value is
  *				 meaningless if so); set to FALSE if non-null result
- *		*isDone: set to indicator of set-result status
- *
- * A caller that can only accept a singleton (non-set) result should pass
- * NULL for isDone; if the expression computes a set result then an error
- * will be reported via ereport.  If the caller does pass an isDone pointer
- * then *isDone is set to one of these three states:
- *		ExprSingleResult		singleton result (not a set)
- *		ExprMultipleResult		return value is one element of a set
- *		ExprEndResult			there are no more elements in the set
- * When ExprMultipleResult is returned, the caller should invoke
- * ExecEvalExpr() repeatedly until ExprEndResult is returned.  ExprEndResult
- * is returned after the last real set element.  For convenience isNull will
- * always be set TRUE when ExprEndResult is returned, but this should not be
- * taken as indicating a NULL element of the set.  Note that these return
- * conventions allow us to distinguish among a singleton NULL, a NULL element
- * of a set, and an empty set.
  *
  * The caller should already have switched into the temporary memory
  * context econtext->ecxt_per_tuple_memory.  The convenience entry point
@@ -260,8 +243,7 @@ static Datum ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
 static Datum
 ExecEvalArrayRef(ArrayRefExprState *astate,
 				 ExprContext *econtext,
-				 bool *isNull,
-				 ExprDoneCond *isDone)
+				 bool *isNull)
 {
 	ArrayRef   *arrayRef = (ArrayRef *) astate->xprstate.expr;
 	Datum		array_source;
@@ -278,8 +260,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 
 	array_source = ExecEvalExpr(astate->refexpr,
 								econtext,
-								isNull,
-								isDone);
+								isNull);
 
 	/*
 	 * If refexpr yields NULL, and it's a fetch, then result is NULL. In the
@@ -287,8 +268,6 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 	 */
 	if (*isNull)
 	{
-		if (isDone && *isDone == ExprEndResult)
-			return (Datum) NULL;	/* end of set result */
 		if (!isAssignment)
 			return (Datum) NULL;
 	}
@@ -314,8 +293,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 
 		upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
 													 econtext,
-													 &eisnull,
-													 NULL));
+													 &eisnull));
 		/* If any index expr yields NULL, result is NULL or error */
 		if (eisnull)
 		{
@@ -350,8 +328,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 
 			lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
 														 econtext,
-														 &eisnull,
-														 NULL));
+														 &eisnull));
 			/* If any index expr yields NULL, result is NULL or error */
 			if (eisnull)
 			{
@@ -438,8 +415,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 		 */
 		sourceData = ExecEvalExpr(astate->refassgnexpr,
 								  econtext,
-								  &eisnull,
-								  NULL);
+								  &eisnull);
 
 		econtext->caseValue_datum = save_datum;
 		econtext->caseValue_isNull = save_isNull;
@@ -542,11 +518,8 @@ isAssignmentIndirectionExpr(ExprState *exprstate)
  */
 static Datum
 ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone)
+			   bool *isNull)
 {
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	if (econtext->ecxt_aggvalues == NULL)		/* safety check */
 		elog(ERROR, "no aggregates in this expression context");
 
@@ -563,11 +536,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
  */
 static Datum
 ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext,
-				   bool *isNull, ExprDoneCond *isDone)
+				   bool *isNull)
 {
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	if (econtext->ecxt_aggvalues == NULL)		/* safety check */
 		elog(ERROR, "no window functions in this expression context");
 
@@ -588,15 +558,12 @@ ExecEvalWindowFunc(WindowFuncExprState *wfunc, ExprContext *econtext,
  */
 static Datum
 ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
-				  bool *isNull, ExprDoneCond *isDone)
+				  bool *isNull)
 {
 	Var		   *variable = (Var *) exprstate->expr;
 	TupleTableSlot *slot;
 	AttrNumber	attnum;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/* Get the input slot and attribute number we want */
 	switch (variable->varno)
 	{
@@ -677,15 +644,12 @@ ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone)
+					  bool *isNull)
 {
 	Var		   *variable = (Var *) exprstate->expr;
 	TupleTableSlot *slot;
 	AttrNumber	attnum;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/* Get the input slot and attribute number we want */
 	switch (variable->varno)
 	{
@@ -725,7 +689,7 @@ ExecEvalScalarVarFast(ExprState *exprstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone)
+					bool *isNull)
 {
 	Var		   *variable = (Var *) wrvstate->xprstate.expr;
 	TupleTableSlot *slot;
@@ -733,9 +697,6 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
 	MemoryContext oldcontext;
 	bool		needslow = false;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/* This was checked by ExecInitExpr */
 	Assert(variable->varattno == InvalidAttrNumber);
 
@@ -941,7 +902,7 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
 
 	/* Fetch the value */
 	return (*wrvstate->xprstate.evalfunc) ((ExprState *) wrvstate, econtext,
-										   isNull, isDone);
+										   isNull);
 }
 
 /* ----------------------------------------------------------------
@@ -952,14 +913,12 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone)
+					 bool *isNull)
 {
 	Var		   *variable = (Var *) wrvstate->xprstate.expr;
 	TupleTableSlot *slot;
 	HeapTupleHeader dtuple;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = false;
 
 	/* Get the input slot we want */
@@ -1008,7 +967,7 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone)
+					 bool *isNull)
 {
 	Var		   *variable = (Var *) wrvstate->xprstate.expr;
 	TupleTableSlot *slot;
@@ -1018,8 +977,6 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
 	HeapTupleHeader dtuple;
 	int			i;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = false;
 
 	/* Get the input slot we want */
@@ -1097,13 +1054,10 @@ ExecEvalWholeRowSlow(WholeRowVarExprState *wrvstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
-			  bool *isNull, ExprDoneCond *isDone)
+			  bool *isNull)
 {
 	Const	   *con = (Const *) exprstate->expr;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	*isNull = con->constisnull;
 	return con->constvalue;
 }
@@ -1116,15 +1070,12 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
-				  bool *isNull, ExprDoneCond *isDone)
+				  bool *isNull)
 {
 	Param	   *expression = (Param *) exprstate->expr;
 	int			thisParamId = expression->paramid;
 	ParamExecData *prm;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/*
 	 * PARAM_EXEC params (internal executor parameters) are stored in the
 	 * ecxt_param_exec_vals array, and can be accessed by array index.
@@ -1149,15 +1100,12 @@ ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
  */
 static Datum
 ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone)
+					bool *isNull)
 {
 	Param	   *expression = (Param *) exprstate->expr;
 	int			thisParamId = expression->paramid;
 	ParamListInfo paramInfo = econtext->ecxt_param_list_info;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/*
 	 * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
 	 */
@@ -1421,7 +1369,6 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
 	/* Initialize additional state */
 	fcache->funcResultStore = NULL;
 	fcache->funcResultSlot = NULL;
-	fcache->setArgsValid = false;
 	fcache->shutdown_reg = false;
 }
 
@@ -1508,47 +1455,26 @@ ShutdownTupleDescRef(Datum arg)
 /*
  * Evaluate arguments for a function.
  */
-static ExprDoneCond
+static void
 ExecEvalFuncArgs(FunctionCallInfo fcinfo,
 				 List *argList,
 				 ExprContext *econtext)
 {
-	ExprDoneCond argIsDone;
 	int			i;
 	ListCell   *arg;
 
-	argIsDone = ExprSingleResult;		/* default assumption */
-
 	i = 0;
 	foreach(arg, argList)
 	{
 		ExprState  *argstate = (ExprState *) lfirst(arg);
-		ExprDoneCond thisArgIsDone;
 
 		fcinfo->arg[i] = ExecEvalExpr(argstate,
 									  econtext,
-									  &fcinfo->argnull[i],
-									  &thisArgIsDone);
-
-		if (thisArgIsDone != ExprSingleResult)
-		{
-			/*
-			 * We allow only one argument to have a set value; we'd need much
-			 * more complexity to keep track of multiple set arguments (cf.
-			 * ExecTargetList) and it doesn't seem worth it.
-			 */
-			if (argIsDone != ExprSingleResult)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("functions and operators can take at most one set argument")));
-			argIsDone = thisArgIsDone;
-		}
+									  &fcinfo->argnull[i]);
 		i++;
 	}
 
 	Assert(i == fcinfo->nargs);
-
-	return argIsDone;
 }
 
 /*
@@ -1695,9 +1621,10 @@ ExecMakeFunctionResultSet(FuncExprState *fcache,
 	FunctionCallInfo fcinfo;
 	PgStat_FunctionCallUsage fcusage;
 	ReturnSetInfo rsinfo;		/* for functions returning sets */
-	ExprDoneCond argDone;
-	bool		hasSetArg;
 	int			i;
+	bool		callit;
+
+	Assert(isDone);
 
 restart:
 
@@ -1736,7 +1663,6 @@ restart:
 	 */
 	if (fcache->funcResultStore)
 	{
-		Assert(isDone);			/* it was provided before ... */
 		if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
 									fcache->funcResultSlot))
 		{
@@ -1756,15 +1682,9 @@ restart:
 		/* Exhausted the tuplestore, so clean up */
 		tuplestore_end(fcache->funcResultStore);
 		fcache->funcResultStore = NULL;
-		/* We are done unless there was a set-valued argument */
-		if (!fcache->setHasSetArg)
-		{
-			*isDone = ExprEndResult;
-			*isNull = true;
-			return (Datum) 0;
-		}
-		/* If there was, continue evaluating the argument values */
-		Assert(!fcache->setArgsValid);
+		*isDone = ExprEndResult;
+		*isNull = true;
+		return (Datum) 0;
 	}
 
 	/*
@@ -1776,233 +1696,119 @@ restart:
 	fcinfo = &fcache->fcinfo_data;
 	arguments = fcache->args;
 	if (!fcache->setArgsValid)
-	{
-		argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext);
-		if (argDone != ExprSingleResult)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("set-valued function called in context that cannot accept a set")));
-		hasSetArg = false;
-	}
+		ExecEvalFuncArgs(fcinfo, arguments, econtext);
 	else
-	{
-		/* Re-use callinfo from previous evaluation */
-		hasSetArg = fcache->setHasSetArg;
 		/* Reset flag (we may set it again below) */
 		fcache->setArgsValid = false;
-	}
+
+	/* shouldn't get here otherwise */
+	Assert (fcache->func.fn_retset);
 
 	/*
 	 * Now call the function, passing the evaluated parameter values.
 	 */
-	if (fcache->func.fn_retset || hasSetArg)
+
+	/* Prepare a resultinfo node for communication. */
+	if (fcache->func.fn_retset)
+		fcinfo->resultinfo = (Node *) &rsinfo;
+	rsinfo.type = T_ReturnSetInfo;
+	rsinfo.econtext = econtext;
+	rsinfo.expectedDesc = fcache->funcResultDesc;
+	rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
+	/* note we do not set SFRM_Materialize_Random or _Preferred */
+	rsinfo.returnMode = SFRM_ValuePerCall;
+	/* isDone is filled below */
+	rsinfo.setResult = NULL;
+	rsinfo.setDesc = NULL;
+
+	/*
+	 * If function is strict, and there are any NULL arguments, skip
+	 * calling the function.
+	 */
+	callit = true;
+	if (fcache->func.fn_strict)
 	{
-		/*
-		 * We need to return a set result.  Complain if caller not ready to
-		 * accept one.
-		 */
-		if (isDone == NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("set-valued function called in context that cannot accept a set")));
-
-		/*
-		 * Prepare a resultinfo node for communication.  If the function
-		 * doesn't itself return set, we don't pass the resultinfo to the
-		 * function, but we need to fill it in anyway for internal use.
-		 */
-		if (fcache->func.fn_retset)
-			fcinfo->resultinfo = (Node *) &rsinfo;
-		rsinfo.type = T_ReturnSetInfo;
-		rsinfo.econtext = econtext;
-		rsinfo.expectedDesc = fcache->funcResultDesc;
-		rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
-		/* note we do not set SFRM_Materialize_Random or _Preferred */
-		rsinfo.returnMode = SFRM_ValuePerCall;
-		/* isDone is filled below */
-		rsinfo.setResult = NULL;
-		rsinfo.setDesc = NULL;
-
-		/*
-		 * This loop handles the situation where we have both a set argument
-		 * and a set-valued function.  Once we have exhausted the function's
-		 * value(s) for a particular argument value, we have to get the next
-		 * argument value and start the function over again. We might have to
-		 * do it more than once, if the function produces an empty result set
-		 * for a particular input value.
-		 */
-		for (;;)
+		for (i = 0; i < fcinfo->nargs; i++)
 		{
-			/*
-			 * If function is strict, and there are any NULL arguments, skip
-			 * calling the function (at least for this set of args).
-			 */
-			bool		callit = true;
-
-			if (fcache->func.fn_strict)
+			if (fcinfo->argnull[i])
 			{
-				for (i = 0; i < fcinfo->nargs; i++)
-				{
-					if (fcinfo->argnull[i])
-					{
-						callit = false;
-						break;
-					}
-				}
-			}
-
-			if (callit)
-			{
-				pgstat_init_function_usage(fcinfo, &fcusage);
-
-				fcinfo->isnull = false;
-				rsinfo.isDone = ExprSingleResult;
-				result = FunctionCallInvoke(fcinfo);
-				*isNull = fcinfo->isnull;
-				*isDone = rsinfo.isDone;
-
-				pgstat_end_function_usage(&fcusage,
-										rsinfo.isDone != ExprMultipleResult);
-			}
-			else if (fcache->func.fn_retset)
-			{
-				/* for a strict SRF, result for NULL is an empty set */
-				result = (Datum) 0;
-				*isNull = true;
-				*isDone = ExprEndResult;
-			}
-			else
-			{
-				/* for a strict non-SRF, result for NULL is a NULL */
-				result = (Datum) 0;
-				*isNull = true;
-				*isDone = ExprSingleResult;
-			}
-
-			/* Which protocol does function want to use? */
-			if (rsinfo.returnMode == SFRM_ValuePerCall)
-			{
-				if (*isDone != ExprEndResult)
-				{
-					/*
-					 * Got a result from current argument. If function itself
-					 * returns set, save the current argument values to re-use
-					 * on the next call.
-					 */
-					if (fcache->func.fn_retset &&
-						*isDone == ExprMultipleResult)
-					{
-						fcache->setHasSetArg = hasSetArg;
-						fcache->setArgsValid = true;
-						/* Register cleanup callback if we didn't already */
-						if (!fcache->shutdown_reg)
-						{
-							RegisterExprContextCallback(econtext,
-														ShutdownFuncExpr,
-													PointerGetDatum(fcache));
-							fcache->shutdown_reg = true;
-						}
-					}
-
-					/*
-					 * Make sure we say we are returning a set, even if the
-					 * function itself doesn't return sets.
-					 */
-					if (hasSetArg)
-						*isDone = ExprMultipleResult;
-					break;
-				}
-			}
-			else if (rsinfo.returnMode == SFRM_Materialize)
-			{
-				/* check we're on the same page as the function author */
-				if (rsinfo.isDone != ExprSingleResult)
-					ereport(ERROR,
-							(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
-							 errmsg("table-function protocol for materialize mode was not followed")));
-				if (rsinfo.setResult != NULL)
-				{
-					/* prepare to return values from the tuplestore */
-					ExecPrepareTuplestoreResult(fcache, econtext,
-												rsinfo.setResult,
-												rsinfo.setDesc);
-					/* remember whether we had set arguments */
-					fcache->setHasSetArg = hasSetArg;
-					/* loop back to top to start returning from tuplestore */
-					goto restart;
-				}
-				/* if setResult was left null, treat it as empty set */
-				*isDone = ExprEndResult;
-				*isNull = true;
-				result = (Datum) 0;
-			}
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
-						 errmsg("unrecognized table-function returnMode: %d",
-								(int) rsinfo.returnMode)));
-
-			/* Else, done with this argument */
-			if (!hasSetArg)
-				break;			/* input not a set, so done */
-
-			/* Re-eval args to get the next element of the input set */
-			argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext);
-
-			if (argDone != ExprMultipleResult)
-			{
-				/* End of argument set, so we're done. */
-				*isNull = true;
-				*isDone = ExprEndResult;
-				result = (Datum) 0;
+				callit = false;
 				break;
 			}
-
-			/*
-			 * If we reach here, loop around to run the function on the new
-			 * argument.
-			 */
 		}
 	}
-	else
+
+	if (callit)
 	{
-		/*
-		 * Non-set case: much easier.
-		 *
-		 * In common cases, this code path is unreachable because we'd have
-		 * selected ExecMakeFunctionResultNoSets instead.  However, it's
-		 * possible to get here if an argument sometimes produces set results
-		 * and sometimes scalar results.  For example, a CASE expression might
-		 * call a set-returning function in only some of its arms.
-		 */
-		if (isDone)
-			*isDone = ExprSingleResult;
-
-		/*
-		 * If function is strict, and there are any NULL arguments, skip
-		 * calling the function and return NULL.
-		 */
-		if (fcache->func.fn_strict)
-		{
-			for (i = 0; i < fcinfo->nargs; i++)
-			{
-				if (fcinfo->argnull[i])
-				{
-					*isNull = true;
-					return (Datum) 0;
-				}
-			}
-		}
-
 		pgstat_init_function_usage(fcinfo, &fcusage);
 
 		fcinfo->isnull = false;
+		rsinfo.isDone = ExprSingleResult;
 		result = FunctionCallInvoke(fcinfo);
 		*isNull = fcinfo->isnull;
+		*isDone = rsinfo.isDone;
 
-		pgstat_end_function_usage(&fcusage, true);
+		pgstat_end_function_usage(&fcusage,
+								  rsinfo.isDone != ExprMultipleResult);
+	}
+	else
+	{
+		/* for a strict SRF, result for NULL is an empty set */
+		result = (Datum) 0;
+		*isNull = true;
+		*isDone = ExprEndResult;
 	}
 
+	/* Which protocol does function want to use? */
+	if (rsinfo.returnMode == SFRM_ValuePerCall)
+	{
+		if (*isDone != ExprEndResult)
+		{
+			/*
+			 * Got a result from current argument. Save the current
+			 * argument values to re-use on the next call.
+			 */
+			if (fcache->func.fn_retset &&
+				*isDone == ExprMultipleResult)
+			{
+				fcache->setArgsValid = true;
+				/* Register cleanup callback if we didn't already */
+				if (!fcache->shutdown_reg)
+				{
+					RegisterExprContextCallback(econtext,
+												ShutdownFuncExpr,
+												PointerGetDatum(fcache));
+					fcache->shutdown_reg = true;
+				}
+			}
+		}
+	}
+	else if (rsinfo.returnMode == SFRM_Materialize)
+	{
+		/* check we're on the same page as the function author */
+		if (rsinfo.isDone != ExprSingleResult)
+			ereport(ERROR,
+					(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+					 errmsg("table-function protocol for materialize mode was not followed")));
+		if (rsinfo.setResult != NULL)
+		{
+			/* prepare to return values from the tuplestore */
+			ExecPrepareTuplestoreResult(fcache, econtext,
+										rsinfo.setResult,
+										rsinfo.setDesc);
+			/* loop back to top to start returning from tuplestore */
+					goto restart;
+		}
+		/* if setResult was left null, treat it as empty set */
+		*isDone = ExprEndResult;
+		*isNull = true;
+		result = (Datum) 0;
+	}
+	else
+		ereport(ERROR,
+				(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+				 errmsg("unrecognized table-function returnMode: %d",
+						(int) rsinfo.returnMode)));
 	return result;
 }
 
@@ -2015,8 +1821,7 @@ restart:
 static Datum
 ExecMakeFunctionResultNoSets(FuncExprState *fcache,
 							 ExprContext *econtext,
-							 bool *isNull,
-							 ExprDoneCond *isDone)
+							 bool *isNull)
 {
 	ListCell   *arg;
 	Datum		result;
@@ -2027,9 +1832,6 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
 	/* Guard against stack overflow due to overly complex expressions */
 	check_stack_depth();
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/* inlined, simplified version of ExecEvalFuncArgs */
 	fcinfo = &fcache->fcinfo_data;
 	i = 0;
@@ -2039,8 +1841,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
 
 		fcinfo->arg[i] = ExecEvalExpr(argstate,
 									  econtext,
-									  &fcinfo->argnull[i],
-									  NULL);
+									  &fcinfo->argnull[i]);
 		i++;
 	}
 
@@ -2137,7 +1938,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 		IsA(funcexpr->expr, FuncExpr))
 	{
 		FuncExprState *fcache = (FuncExprState *) funcexpr;
-		ExprDoneCond argDone;
 
 		/*
 		 * This path is similar to ExecMakeFunctionResultSet.
@@ -2172,15 +1972,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 		 */
 		MemoryContextReset(argContext);
 		oldcontext = MemoryContextSwitchTo(argContext);
-		argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
+		ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
 		MemoryContextSwitchTo(oldcontext);
 
-		/* We don't allow sets in the arguments of the table function */
-		if (argDone != ExprSingleResult)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("set-valued function called in context that cannot accept a set")));
-
 		/*
 		 * If function is strict, and there are any NULL arguments, skip
 		 * calling the function and act like it returned NULL (or an empty
@@ -2240,8 +2034,8 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 		}
 		else
 		{
-			result = ExecEvalExpr(funcexpr, econtext,
-								  &fcinfo.isnull, &rsinfo.isDone);
+			result = ExecEvalExpr(funcexpr, econtext, &fcinfo.isnull);
+			rsinfo.isDone = ExprSingleResult;
 		}
 
 		/* Which protocol does function want to use? */
@@ -2435,8 +2229,7 @@ no_function_result:
 static Datum
 ExecEvalFunc(FuncExprState *fcache,
 			 ExprContext *econtext,
-			 bool *isNull,
-			 ExprDoneCond *isDone)
+			 bool *isNull)
 {
 	/* This is called only the first time through */
 	FuncExpr   *func = (FuncExpr *) fcache->xprstate.expr;
@@ -2447,7 +2240,7 @@ ExecEvalFunc(FuncExprState *fcache,
 
 	/* Change the evalfunc pointer to save a few cycles in additional calls */
 	fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
-	return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone);
+	return ExecMakeFunctionResultNoSets(fcache, econtext, isNull);
 }
 
 /* ----------------------------------------------------------------
@@ -2457,8 +2250,7 @@ ExecEvalFunc(FuncExprState *fcache,
 static Datum
 ExecEvalOper(FuncExprState *fcache,
 			 ExprContext *econtext,
-			 bool *isNull,
-			 ExprDoneCond *isDone)
+			 bool *isNull)
 {
 	/* This is called only the first time through */
 	OpExpr	   *op = (OpExpr *) fcache->xprstate.expr;
@@ -2469,7 +2261,7 @@ ExecEvalOper(FuncExprState *fcache,
 
 	/* Change the evalfunc pointer to save a few cycles in additional calls */
 	fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
-	return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone);
+	return ExecMakeFunctionResultNoSets(fcache, econtext, isNull);
 }
 
 /* ----------------------------------------------------------------
@@ -2486,17 +2278,13 @@ ExecEvalOper(FuncExprState *fcache,
 static Datum
 ExecEvalDistinct(FuncExprState *fcache,
 				 ExprContext *econtext,
-				 bool *isNull,
-				 ExprDoneCond *isDone)
+				 bool *isNull)
 {
 	Datum		result;
 	FunctionCallInfo fcinfo;
-	ExprDoneCond argDone;
 
-	/* Set default values for result flags: non-null, not a set result */
+	/* Set non-null as default */
 	*isNull = false;
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	/*
 	 * Initialize function cache if first time through
@@ -2513,11 +2301,7 @@ ExecEvalDistinct(FuncExprState *fcache,
 	 * Evaluate arguments
 	 */
 	fcinfo = &fcache->fcinfo_data;
-	argDone = ExecEvalFuncArgs(fcinfo, fcache->args, econtext);
-	if (argDone != ExprSingleResult)
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-				 errmsg("IS DISTINCT FROM does not support set arguments")));
+	ExecEvalFuncArgs(fcinfo, fcache->args, econtext);
 	Assert(fcinfo->nargs == 2);
 
 	if (fcinfo->argnull[0] && fcinfo->argnull[1])
@@ -2553,7 +2337,7 @@ ExecEvalDistinct(FuncExprState *fcache,
 static Datum
 ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
 					  ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone)
+					  bool *isNull)
 {
 	ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;
 	bool		useOr = opexpr->useOr;
@@ -2562,7 +2346,6 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
 	Datum		result;
 	bool		resultnull;
 	FunctionCallInfo fcinfo;
-	ExprDoneCond argDone;
 	int			i;
 	int16		typlen;
 	bool		typbyval;
@@ -2571,10 +2354,8 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
 	bits8	   *bitmap;
 	int			bitmask;
 
-	/* Set default values for result flags: non-null, not a set result */
+	/* Set non-null as default */
 	*isNull = false;
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	/*
 	 * Initialize function cache if first time through
@@ -2589,11 +2370,7 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
 	 * Evaluate arguments
 	 */
 	fcinfo = &sstate->fxprstate.fcinfo_data;
-	argDone = ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext);
-	if (argDone != ExprSingleResult)
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-			   errmsg("op ANY/ALL (array) does not support set arguments")));
+	ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext);
 	Assert(fcinfo->nargs == 2);
 
 	/*
@@ -2739,15 +2516,12 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
  */
 static Datum
 ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone)
+			bool *isNull)
 {
 	ExprState  *clause = linitial(notclause->args);
 	Datum		expr_value;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
-	expr_value = ExecEvalExpr(clause, econtext, isNull, NULL);
+	expr_value = ExecEvalExpr(clause, econtext, isNull);
 
 	/*
 	 * if the expression evaluates to null, then we just cascade the null back
@@ -2769,15 +2543,12 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
  */
 static Datum
 ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
-		   bool *isNull, ExprDoneCond *isDone)
+		   bool *isNull)
 {
 	List	   *clauses = orExpr->args;
 	ListCell   *clause;
 	bool		AnyNull;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	AnyNull = false;
 
 	/*
@@ -2798,7 +2569,7 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
 		ExprState  *clausestate = (ExprState *) lfirst(clause);
 		Datum		clause_value;
 
-		clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
+		clause_value = ExecEvalExpr(clausestate, econtext, isNull);
 
 		/*
 		 * if we have a non-null true result, then return it.
@@ -2820,15 +2591,12 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
  */
 static Datum
 ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone)
+			bool *isNull)
 {
 	List	   *clauses = andExpr->args;
 	ListCell   *clause;
 	bool		AnyNull;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	AnyNull = false;
 
 	/*
@@ -2845,7 +2613,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
 		ExprState  *clausestate = (ExprState *) lfirst(clause);
 		Datum		clause_value;
 
-		clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
+		clause_value = ExecEvalExpr(clausestate, econtext, isNull);
 
 		/*
 		 * if we have a non-null false result, then return it.
@@ -2871,7 +2639,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
 static Datum
 ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
 					   ExprContext *econtext,
-					   bool *isNull, ExprDoneCond *isDone)
+					   bool *isNull)
 {
 	ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) cstate->xprstate.expr;
 	HeapTuple	result;
@@ -2879,7 +2647,7 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
 	HeapTupleHeader tuple;
 	HeapTupleData tmptup;
 
-	tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
+	tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull);
 
 	/* this test covers the isDone exception too: */
 	if (*isNull)
@@ -2955,16 +2723,13 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
  */
 static Datum
 ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
-			 bool *isNull, ExprDoneCond *isDone)
+			 bool *isNull)
 {
 	List	   *clauses = caseExpr->args;
 	ListCell   *clause;
 	Datum		save_datum;
 	bool		save_isNull;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/*
 	 * If there's a test expression, we have to evaluate it and save the value
 	 * where the CaseTestExpr placeholders can find it.  We must save and
@@ -2989,8 +2754,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 
 		arg_value = ExecEvalExpr(caseExpr->arg,
 								 econtext,
-								 &arg_isNull,
-								 NULL);
+								 &arg_isNull);
 		/* Since caseValue_datum may be read multiple times, force to R/O */
 		econtext->caseValue_datum =
 			MakeExpandedObjectReadOnly(arg_value,
@@ -3012,8 +2776,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 
 		clause_value = ExecEvalExpr(wclause->expr,
 									econtext,
-									&clause_isNull,
-									NULL);
+									&clause_isNull);
 
 		/*
 		 * if we have a true test, then we return the result, since the case
@@ -3026,8 +2789,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 			econtext->caseValue_isNull = save_isNull;
 			return ExecEvalExpr(wclause->result,
 								econtext,
-								isNull,
-								isDone);
+								isNull);
 		}
 	}
 
@@ -3038,8 +2800,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 	{
 		return ExecEvalExpr(caseExpr->defresult,
 							econtext,
-							isNull,
-							isDone);
+							isNull);
 	}
 
 	*isNull = true;
@@ -3054,10 +2815,8 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 static Datum
 ExecEvalCaseTestExpr(ExprState *exprstate,
 					 ExprContext *econtext,
-					 bool *isNull, ExprDoneCond *isDone)
+					 bool *isNull)
 {
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = econtext->caseValue_isNull;
 	return econtext->caseValue_datum;
 }
@@ -3074,17 +2833,13 @@ ExecEvalCaseTestExpr(ExprState *exprstate,
 static Datum
 ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
 						 ExprContext *econtext,
-						 bool *isNull,
-						 ExprDoneCond *isDone)
+						 bool *isNull)
 {
 	int			result = 0;
 	int			attnum = 0;
 	Bitmapset  *grouped_cols = gstate->aggstate->grouped_cols;
 	ListCell   *lc;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	*isNull = false;
 
 	foreach(lc, (gstate->clauses))
@@ -3106,7 +2861,7 @@ ExecEvalGroupingFuncExpr(GroupingFuncExprState *gstate,
  */
 static Datum
 ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
-			  bool *isNull, ExprDoneCond *isDone)
+			  bool *isNull)
 {
 	ArrayExpr  *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
 	ArrayType  *result;
@@ -3116,10 +2871,8 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 	int			dims[MAXDIM];
 	int			lbs[MAXDIM];
 
-	/* Set default values for result flags: non-null, not a set result */
+	/* Set default values for result flag: non-null */
 	*isNull = false;
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	if (!arrayExpr->multidims)
 	{
@@ -3144,7 +2897,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 		{
 			ExprState  *e = (ExprState *) lfirst(element);
 
-			dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i], NULL);
+			dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i]);
 			i++;
 		}
 
@@ -3194,7 +2947,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 			ArrayType  *array;
 			int			this_ndims;
 
-			arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
+			arraydatum = ExecEvalExpr(e, econtext, &eisnull);
 			/* temporarily ignore null subarrays */
 			if (eisnull)
 			{
@@ -3333,7 +3086,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 static Datum
 ExecEvalRow(RowExprState *rstate,
 			ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone)
+			bool *isNull)
 {
 	HeapTuple	tuple;
 	Datum	   *values;
@@ -3342,10 +3095,8 @@ ExecEvalRow(RowExprState *rstate,
 	ListCell   *arg;
 	int			i;
 
-	/* Set default values for result flags: non-null, not a set result */
+	/* Set default values for result flag: non-null */
 	*isNull = false;
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	/* Allocate workspace */
 	natts = rstate->tupdesc->natts;
@@ -3361,7 +3112,7 @@ ExecEvalRow(RowExprState *rstate,
 	{
 		ExprState  *e = (ExprState *) lfirst(arg);
 
-		values[i] = ExecEvalExpr(e, econtext, &isnull[i], NULL);
+		values[i] = ExecEvalExpr(e, econtext, &isnull[i]);
 		i++;
 	}
 
@@ -3380,7 +3131,7 @@ ExecEvalRow(RowExprState *rstate,
 static Datum
 ExecEvalRowCompare(RowCompareExprState *rstate,
 				   ExprContext *econtext,
-				   bool *isNull, ExprDoneCond *isDone)
+				   bool *isNull)
 {
 	bool		result;
 	RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype;
@@ -3389,8 +3140,6 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
 	ListCell   *r;
 	int			i;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = true;				/* until we get a result */
 
 	i = 0;
@@ -3404,9 +3153,9 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
 								 rstate->collations[i],
 								 NULL, NULL);
 		locfcinfo.arg[0] = ExecEvalExpr(le, econtext,
-										&locfcinfo.argnull[0], NULL);
+										&locfcinfo.argnull[0]);
 		locfcinfo.arg[1] = ExecEvalExpr(re, econtext,
-										&locfcinfo.argnull[1], NULL);
+										&locfcinfo.argnull[1]);
 		if (rstate->funcs[i].fn_strict &&
 			(locfcinfo.argnull[0] || locfcinfo.argnull[1]))
 			return (Datum) 0;	/* force NULL result */
@@ -3450,20 +3199,17 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
  */
 static Datum
 ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
-				 bool *isNull, ExprDoneCond *isDone)
+				 bool *isNull)
 {
 	ListCell   *arg;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/* Simply loop through until something NOT NULL is found */
 	foreach(arg, coalesceExpr->args)
 	{
 		ExprState  *e = (ExprState *) lfirst(arg);
 		Datum		value;
 
-		value = ExecEvalExpr(e, econtext, isNull, NULL);
+		value = ExecEvalExpr(e, econtext, isNull);
 		if (!*isNull)
 			return value;
 	}
@@ -3479,7 +3225,7 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
  */
 static Datum
 ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone)
+			   bool *isNull)
 {
 	Datum		result = (Datum) 0;
 	MinMaxExpr *minmax = (MinMaxExpr *) minmaxExpr->xprstate.expr;
@@ -3488,8 +3234,6 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
 	FunctionCallInfoData locfcinfo;
 	ListCell   *arg;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = true;				/* until we get a result */
 
 	InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2,
@@ -3504,7 +3248,7 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
 		bool		valueIsNull;
 		int32		cmpresult;
 
-		value = ExecEvalExpr(e, econtext, &valueIsNull, NULL);
+		value = ExecEvalExpr(e, econtext, &valueIsNull);
 		if (valueIsNull)
 			continue;			/* ignore NULL inputs */
 
@@ -3540,14 +3284,12 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
 static Datum
 ExecEvalSQLValueFunction(ExprState *svfExpr,
 						 ExprContext *econtext,
-						 bool *isNull, ExprDoneCond *isDone)
+						 bool *isNull)
 {
 	Datum		result = (Datum) 0;
 	SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr;
 	FunctionCallInfoData fcinfo;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = false;
 
 	/*
@@ -3608,7 +3350,7 @@ ExecEvalSQLValueFunction(ExprState *svfExpr,
  */
 static Datum
 ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
-			bool *isNull, ExprDoneCond *isDone)
+			bool *isNull)
 {
 	XmlExpr    *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
 	Datum		value;
@@ -3616,8 +3358,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 	ListCell   *arg;
 	ListCell   *narg;
 
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = true;				/* until we get a result */
 
 	switch (xexpr->op)
@@ -3630,7 +3370,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				{
 					ExprState  *e = (ExprState *) lfirst(arg);
 
-					value = ExecEvalExpr(e, econtext, &isnull, NULL);
+					value = ExecEvalExpr(e, econtext, &isnull);
 					if (!isnull)
 						values = lappend(values, DatumGetPointer(value));
 				}
@@ -3655,7 +3395,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 					ExprState  *e = (ExprState *) lfirst(arg);
 					char	   *argname = strVal(lfirst(narg));
 
-					value = ExecEvalExpr(e, econtext, &isnull, NULL);
+					value = ExecEvalExpr(e, econtext, &isnull);
 					if (!isnull)
 					{
 						appendStringInfo(&buf, "<%s>%s</%s>",
@@ -3698,13 +3438,13 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				Assert(list_length(xmlExpr->args) == 2);
 
 				e = (ExprState *) linitial(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)
 					return (Datum) 0;
 				data = DatumGetTextP(value);
 
 				e = (ExprState *) lsecond(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)		/* probably can't happen */
 					return (Datum) 0;
 				preserve_whitespace = DatumGetBool(value);
@@ -3728,7 +3468,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				if (xmlExpr->args)
 				{
 					e = (ExprState *) linitial(xmlExpr->args);
-					value = ExecEvalExpr(e, econtext, &isnull, NULL);
+					value = ExecEvalExpr(e, econtext, &isnull);
 					if (isnull)
 						arg = NULL;
 					else
@@ -3755,20 +3495,20 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				Assert(list_length(xmlExpr->args) == 3);
 
 				e = (ExprState *) linitial(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)
 					return (Datum) 0;
 				data = DatumGetXmlP(value);
 
 				e = (ExprState *) lsecond(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)
 					version = NULL;
 				else
 					version = DatumGetTextP(value);
 
 				e = (ExprState *) lthird(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				standalone = DatumGetInt32(value);
 
 				*isNull = false;
@@ -3787,7 +3527,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				Assert(list_length(xmlExpr->args) == 1);
 
 				e = (ExprState *) linitial(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)
 					return (Datum) 0;
 
@@ -3805,7 +3545,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 				Assert(list_length(xmlExpr->args) == 1);
 
 				e = (ExprState *) linitial(xmlExpr->args);
-				value = ExecEvalExpr(e, econtext, &isnull, NULL);
+				value = ExecEvalExpr(e, econtext, &isnull);
 				if (isnull)
 					return (Datum) 0;
 				else
@@ -3832,14 +3572,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 static Datum
 ExecEvalNullIf(FuncExprState *nullIfExpr,
 			   ExprContext *econtext,
-			   bool *isNull, ExprDoneCond *isDone)
+			   bool *isNull)
 {
 	Datum		result;
 	FunctionCallInfo fcinfo;
-	ExprDoneCond argDone;
-
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	/*
 	 * Initialize function cache if first time through
@@ -3856,11 +3592,7 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
 	 * Evaluate arguments
 	 */
 	fcinfo = &nullIfExpr->fcinfo_data;
-	argDone = ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext);
-	if (argDone != ExprSingleResult)
-		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-				 errmsg("NULLIF does not support set arguments")));
+	ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext);
 	Assert(fcinfo->nargs == 2);
 
 	/* if either argument is NULL they can't be equal */
@@ -3890,16 +3622,12 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
 static Datum
 ExecEvalNullTest(NullTestState *nstate,
 				 ExprContext *econtext,
-				 bool *isNull,
-				 ExprDoneCond *isDone)
+				 bool *isNull)
 {
 	NullTest   *ntest = (NullTest *) nstate->xprstate.expr;
 	Datum		result;
 
-	result = ExecEvalExpr(nstate->arg, econtext, isNull, isDone);
-
-	if (isDone && *isDone == ExprEndResult)
-		return result;			/* nothing to check */
+	result = ExecEvalExpr(nstate->arg, econtext, isNull);
 
 	if (ntest->argisrow && !(*isNull))
 	{
@@ -3999,16 +3727,12 @@ ExecEvalNullTest(NullTestState *nstate,
 static Datum
 ExecEvalBooleanTest(GenericExprState *bstate,
 					ExprContext *econtext,
-					bool *isNull,
-					ExprDoneCond *isDone)
+					bool *isNull)
 {
 	BooleanTest *btest = (BooleanTest *) bstate->xprstate.expr;
 	Datum		result;
 
-	result = ExecEvalExpr(bstate->arg, econtext, isNull, isDone);
-
-	if (isDone && *isDone == ExprEndResult)
-		return result;			/* nothing to check */
+	result = ExecEvalExpr(bstate->arg, econtext, isNull);
 
 	switch (btest->booltesttype)
 	{
@@ -4084,16 +3808,13 @@ ExecEvalBooleanTest(GenericExprState *bstate,
  */
 static Datum
 ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
-					   bool *isNull, ExprDoneCond *isDone)
+					   bool *isNull)
 {
 	CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
 	Datum		result;
 	ListCell   *l;
 
-	result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
-
-	if (isDone && *isDone == ExprEndResult)
-		return result;			/* nothing to check */
+	result = ExecEvalExpr(cstate->arg, econtext, isNull);
 
 	/* Make sure we have up-to-date constraints */
 	UpdateDomainConstraintRef(cstate->constraint_ref);
@@ -4138,8 +3859,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
 									 cstate->constraint_ref->tcache->typlen);
 					econtext->domainValue_isNull = *isNull;
 
-					conResult = ExecEvalExpr(con->check_expr,
-											 econtext, &conIsNull, NULL);
+					conResult = ExecEvalExpr(con->check_expr, econtext,
+											 &conIsNull);
 
 					if (!conIsNull &&
 						!DatumGetBool(conResult))
@@ -4174,10 +3895,8 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
 static Datum
 ExecEvalCoerceToDomainValue(ExprState *exprstate,
 							ExprContext *econtext,
-							bool *isNull, ExprDoneCond *isDone)
+							bool *isNull)
 {
-	if (isDone)
-		*isDone = ExprSingleResult;
 	*isNull = econtext->domainValue_isNull;
 	return econtext->domainValue_datum;
 }
@@ -4191,8 +3910,7 @@ ExecEvalCoerceToDomainValue(ExprState *exprstate,
 static Datum
 ExecEvalFieldSelect(FieldSelectState *fstate,
 					ExprContext *econtext,
-					bool *isNull,
-					ExprDoneCond *isDone)
+					bool *isNull)
 {
 	FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr;
 	AttrNumber	fieldnum = fselect->fieldnum;
@@ -4205,9 +3923,8 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
 	Form_pg_attribute attr;
 	HeapTupleData tmptup;
 
-	tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone);
+	tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull);
 
-	/* this test covers the isDone exception too: */
 	if (*isNull)
 		return tupDatum;
 
@@ -4270,8 +3987,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
 static Datum
 ExecEvalFieldStore(FieldStoreState *fstate,
 				   ExprContext *econtext,
-				   bool *isNull,
-				   ExprDoneCond *isDone)
+				   bool *isNull)
 {
 	FieldStore *fstore = (FieldStore *) fstate->xprstate.expr;
 	HeapTuple	tuple;
@@ -4284,10 +4000,7 @@ ExecEvalFieldStore(FieldStoreState *fstate,
 	ListCell   *l1,
 			   *l2;
 
-	tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone);
-
-	if (isDone && *isDone == ExprEndResult)
-		return tupDatum;
+	tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull);
 
 	/* Lookup tupdesc if first time through or after rescan */
 	tupDesc = get_cached_rowtype(fstore->resulttype, -1,
@@ -4347,8 +4060,7 @@ ExecEvalFieldStore(FieldStoreState *fstate,
 
 		values[fieldnum - 1] = ExecEvalExpr(newval,
 											econtext,
-											&isnull[fieldnum - 1],
-											NULL);
+											&isnull[fieldnum - 1]);
 	}
 
 	econtext->caseValue_datum = save_datum;
@@ -4371,9 +4083,9 @@ ExecEvalFieldStore(FieldStoreState *fstate,
 static Datum
 ExecEvalRelabelType(GenericExprState *exprstate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone)
+					bool *isNull)
 {
-	return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
+	return ExecEvalExpr(exprstate->arg, econtext, isNull);
 }
 
 /* ----------------------------------------------------------------
@@ -4385,16 +4097,13 @@ ExecEvalRelabelType(GenericExprState *exprstate,
 static Datum
 ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
 					ExprContext *econtext,
-					bool *isNull, ExprDoneCond *isDone)
+					bool *isNull)
 {
 	Datum		result;
 	Datum		inputval;
 	char	   *string;
 
-	inputval = ExecEvalExpr(iostate->arg, econtext, isNull, isDone);
-
-	if (isDone && *isDone == ExprEndResult)
-		return inputval;		/* nothing to do */
+	inputval = ExecEvalExpr(iostate->arg, econtext, isNull);
 
 	if (*isNull)
 		string = NULL;			/* output functions are not called on nulls */
@@ -4419,16 +4128,14 @@ ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
 static Datum
 ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
 						ExprContext *econtext,
-						bool *isNull, ExprDoneCond *isDone)
+						bool *isNull)
 {
 	ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) astate->xprstate.expr;
 	Datum		result;
 	FunctionCallInfoData locfcinfo;
 
-	result = ExecEvalExpr(astate->arg, econtext, isNull, isDone);
+	result = ExecEvalExpr(astate->arg, econtext, isNull);
 
-	if (isDone && *isDone == ExprEndResult)
-		return result;			/* nothing to do */
 	if (*isNull)
 		return result;			/* nothing to do */
 
@@ -4496,7 +4203,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
  */
 static Datum
 ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
-					  bool *isNull, ExprDoneCond *isDone)
+					  bool *isNull)
 {
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -4513,14 +4220,13 @@ ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
 Datum
 ExecEvalExprSwitchContext(ExprState *expression,
 						  ExprContext *econtext,
-						  bool *isNull,
-						  ExprDoneCond *isDone)
+						  bool *isNull)
 {
 	Datum		retDatum;
 	MemoryContext oldContext;
 
 	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
-	retDatum = ExecEvalExpr(expression, econtext, isNull, isDone);
+	retDatum = ExecEvalExpr(expression, econtext, isNull);
 	MemoryContextSwitchTo(oldContext);
 	return retDatum;
 }
@@ -5387,7 +5093,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
 		Datum		expr_value;
 		bool		isNull;
 
-		expr_value = ExecEvalExpr(clause, econtext, &isNull, NULL);
+		expr_value = ExecEvalExpr(clause, econtext, &isNull);
 
 		if (isNull)
 		{
@@ -5445,17 +5151,9 @@ ExecCleanTargetListLength(List *targetlist)
 /*
  * ExecTargetList
  *		Evaluates a targetlist with respect to the given
- *		expression context.  Returns TRUE if we were able to create
- *		a result, FALSE if we have exhausted a set-valued expression.
+ *		expression context.
  *
  * Results are stored into the passed values and isnull arrays.
- * The caller must provide an itemIsDone array that persists across calls.
- *
- * As with ExecEvalExpr, the caller should pass isDone = NULL if not
- * prepared to deal with sets of result tuples.  Otherwise, a return
- * of *isDone = ExprMultipleResult signifies a set element, and a return
- * of *isDone = ExprEndResult signifies end of the set of tuple.
- * We assume that *isDone has been initialized to ExprSingleResult by caller.
  *
  * Since fields of the result tuple might be multiply referenced in higher
  * plan nodes, we have to force any read/write expanded values to read-only
@@ -5464,19 +5162,16 @@ ExecCleanTargetListLength(List *targetlist)
  * actually-multiply-referenced Vars and insert an expression node that
  * would do that only where really required.
  */
-static bool
+static void
 ExecTargetList(List *targetlist,
 			   TupleDesc tupdesc,
 			   ExprContext *econtext,
 			   Datum *values,
-			   bool *isnull,
-			   ExprDoneCond *itemIsDone,
-			   ExprDoneCond *isDone)
+			   bool *isnull)
 {
 	Form_pg_attribute *att = tupdesc->attrs;
 	MemoryContext oldContext;
 	ListCell   *tl;
-	bool		haveDoneSets;
 
 	/*
 	 * Run in short-lived per-tuple context while computing expressions.
@@ -5486,8 +5181,6 @@ ExecTargetList(List *targetlist,
 	/*
 	 * evaluate all the expressions in the target list
 	 */
-	haveDoneSets = false;		/* any exhausted set exprs in tlist? */
-
 	foreach(tl, targetlist)
 	{
 		GenericExprState *gstate = (GenericExprState *) lfirst(tl);
@@ -5496,117 +5189,15 @@ ExecTargetList(List *targetlist,
 
 		values[resind] = ExecEvalExpr(gstate->arg,
 									  econtext,
-									  &isnull[resind],
-									  &itemIsDone[resind]);
+									  &isnull[resind]);
 
 		values[resind] = MakeExpandedObjectReadOnly(values[resind],
 													isnull[resind],
 													att[resind]->attlen);
-
-		if (itemIsDone[resind] != ExprSingleResult)
-		{
-			/* We have a set-valued expression in the tlist */
-			if (isDone == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("set-valued function called in context that cannot accept a set")));
-			if (itemIsDone[resind] == ExprMultipleResult)
-			{
-				/* we have undone sets in the tlist, set flag */
-				*isDone = ExprMultipleResult;
-			}
-			else
-			{
-				/* we have done sets in the tlist, set flag for that */
-				haveDoneSets = true;
-			}
-		}
-	}
-
-	if (haveDoneSets)
-	{
-		/*
-		 * note: can't get here unless we verified isDone != NULL
-		 */
-		if (*isDone == ExprSingleResult)
-		{
-			/*
-			 * all sets are done, so report that tlist expansion is complete.
-			 */
-			*isDone = ExprEndResult;
-			MemoryContextSwitchTo(oldContext);
-			return false;
-		}
-		else
-		{
-			/*
-			 * We have some done and some undone sets.  Restart the done ones
-			 * so that we can deliver a tuple (if possible).
-			 */
-			foreach(tl, targetlist)
-			{
-				GenericExprState *gstate = (GenericExprState *) lfirst(tl);
-				TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
-				AttrNumber	resind = tle->resno - 1;
-
-				if (itemIsDone[resind] == ExprEndResult)
-				{
-					values[resind] = ExecEvalExpr(gstate->arg,
-												  econtext,
-												  &isnull[resind],
-												  &itemIsDone[resind]);
-
-					values[resind] = MakeExpandedObjectReadOnly(values[resind],
-															  isnull[resind],
-														att[resind]->attlen);
-
-					if (itemIsDone[resind] == ExprEndResult)
-					{
-						/*
-						 * Oh dear, this item is returning an empty set. Guess
-						 * we can't make a tuple after all.
-						 */
-						*isDone = ExprEndResult;
-						break;
-					}
-				}
-			}
-
-			/*
-			 * If we cannot make a tuple because some sets are empty, we still
-			 * have to cycle the nonempty sets to completion, else resources
-			 * will not be released from subplans etc.
-			 *
-			 * XXX is that still necessary?
-			 */
-			if (*isDone == ExprEndResult)
-			{
-				foreach(tl, targetlist)
-				{
-					GenericExprState *gstate = (GenericExprState *) lfirst(tl);
-					TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
-					AttrNumber	resind = tle->resno - 1;
-
-					while (itemIsDone[resind] == ExprMultipleResult)
-					{
-						values[resind] = ExecEvalExpr(gstate->arg,
-													  econtext,
-													  &isnull[resind],
-													  &itemIsDone[resind]);
-						/* no need for MakeExpandedObjectReadOnly */
-					}
-				}
-
-				MemoryContextSwitchTo(oldContext);
-				return false;
-			}
-		}
 	}
 
 	/* Report success */
 	MemoryContextSwitchTo(oldContext);
-
-	return true;
 }
 
 /*
@@ -5623,7 +5214,7 @@ ExecTargetList(List *targetlist,
  *		result slot.
  */
 TupleTableSlot *
-ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
+ExecProject(ProjectionInfo *projInfo)
 {
 	TupleTableSlot *slot;
 	ExprContext *econtext;
@@ -5640,10 +5231,6 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
 	slot = projInfo->pi_slot;
 	econtext = projInfo->pi_exprContext;
 
-	/* Assume single result row until proven otherwise */
-	if (isDone)
-		*isDone = ExprSingleResult;
-
 	/*
 	 * Clear any former contents of the result slot.  This makes it safe for
 	 * us to use the slot's Datum/isnull arrays as workspace. (Also, we can
@@ -5711,21 +5298,15 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
 	}
 
 	/*
-	 * If there are any generic expressions, evaluate them.  It's possible
-	 * that there are set-returning functions in such expressions; if so and
-	 * we have reached the end of the set, we return the result slot, which we
-	 * already marked empty.
+	 * If there are any generic expressions, evaluate them.
 	 */
 	if (projInfo->pi_targetlist)
 	{
-		if (!ExecTargetList(projInfo->pi_targetlist,
-							slot->tts_tupleDescriptor,
-							econtext,
-							slot->tts_values,
-							slot->tts_isnull,
-							projInfo->pi_itemIsDone,
-							isDone))
-			return slot;		/* no more result rows, return empty slot */
+		ExecTargetList(projInfo->pi_targetlist,
+					   slot->tts_tupleDescriptor,
+					   econtext,
+					   slot->tts_values,
+					   slot->tts_isnull);
 	}
 
 	/*
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index f97db9c211..c0e4641750 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -125,8 +125,6 @@ ExecScan(ScanState *node,
 	ExprContext *econtext;
 	List	   *qual;
 	ProjectionInfo *projInfo;
-	ExprDoneCond isDone;
-	TupleTableSlot *resultSlot;
 
 	/*
 	 * Fetch data from node
@@ -146,21 +144,6 @@ ExecScan(ScanState *node,
 	}
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous scan
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->ps.ps_TupFromTlist)
-	{
-		Assert(projInfo);		/* can't get here if not projecting */
-		resultSlot = ExecProject(projInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return resultSlot;
-		/* Done with that source tuple... */
-		node->ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note this can't happen
 	 * until we're done projecting out tuples from a scan tuple.
@@ -214,15 +197,9 @@ ExecScan(ScanState *node,
 			{
 				/*
 				 * Form a projection tuple, store it in the result tuple slot
-				 * and return it --- unless we find we can project no tuples
-				 * from this scan tuple, in which case continue scan.
+				 * and return it.
 				 */
-				resultSlot = ExecProject(projInfo, &isDone);
-				if (isDone != ExprEndResult)
-				{
-					node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-					return resultSlot;
-				}
+				return ExecProject(projInfo);
 			}
 			else
 			{
@@ -352,9 +329,6 @@ ExecScanReScan(ScanState *node)
 {
 	EState	   *estate = node->ps.state;
 
-	/* Stop projecting any tuples from SRFs in the targetlist */
-	node->ps.ps_TupFromTlist = false;
-
 	/* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
 	if (estate->es_epqScanDone != NULL)
 	{
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 70646fd15a..e49feff6c0 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -586,12 +586,6 @@ ExecBuildProjectionInfo(List *targetList,
 	projInfo->pi_numSimpleVars = numSimpleVars;
 	projInfo->pi_directMap = directMap;
 
-	if (exprlist == NIL)
-		projInfo->pi_itemIsDone = NULL; /* not needed */
-	else
-		projInfo->pi_itemIsDone = (ExprDoneCond *)
-			palloc(len * sizeof(ExprDoneCond));
-
 	return projInfo;
 }
 
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index dc64b3262a..e4992134bd 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -854,7 +854,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 
 	/* compute input for all aggregates */
 	if (aggstate->evalproj)
-		aggstate->evalslot = ExecProject(aggstate->evalproj, NULL);
+		aggstate->evalslot = ExecProject(aggstate->evalproj);
 
 	for (transno = 0; transno < numTrans; transno++)
 	{
@@ -871,7 +871,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 			bool		isnull;
 
 			res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext,
-											&isnull, NULL);
+											&isnull);
 			if (isnull || !DatumGetBool(res))
 				continue;
 		}
@@ -970,7 +970,7 @@ combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
 	Assert(aggstate->phase->numsets == 0);
 
 	/* compute input for all aggregates */
-	slot = ExecProject(aggstate->evalproj, NULL);
+	slot = ExecProject(aggstate->evalproj);
 
 	for (transno = 0; transno < numTrans; transno++)
 	{
@@ -1368,8 +1368,7 @@ finalize_aggregate(AggState *aggstate,
 
 		fcinfo.arg[i] = ExecEvalExpr(expr,
 									 aggstate->ss.ps.ps_ExprContext,
-									 &fcinfo.argnull[i],
-									 NULL);
+									 &fcinfo.argnull[i]);
 		anynull |= fcinfo.argnull[i];
 		i++;
 	}
@@ -1630,7 +1629,7 @@ finalize_aggregates(AggState *aggstate,
 /*
  * Project the result of a group (whose aggs have already been calculated by
  * finalize_aggregates). Returns the result slot, or NULL if no row is
- * projected (suppressed by qual or by an empty SRF).
+ * projected (suppressed by qual).
  */
 static TupleTableSlot *
 project_aggregates(AggState *aggstate)
@@ -1643,20 +1642,10 @@ project_aggregates(AggState *aggstate)
 	if (ExecQual(aggstate->ss.ps.qual, econtext, false))
 	{
 		/*
-		 * Form and return or store a projection tuple using the aggregate
-		 * results and the representative input tuple.
+		 * Form and return projection tuple using the aggregate results and
+		 * the representative input tuple.
 		 */
-		ExprDoneCond isDone;
-		TupleTableSlot *result;
-
-		result = ExecProject(aggstate->ss.ps.ps_ProjInfo, &isDone);
-
-		if (isDone != ExprEndResult)
-		{
-			aggstate->ss.ps.ps_TupFromTlist =
-				(isDone == ExprMultipleResult);
-			return result;
-		}
+		return ExecProject(aggstate->ss.ps.ps_ProjInfo);
 	}
 	else
 		InstrCountFiltered1(aggstate, 1);
@@ -1911,27 +1900,6 @@ ExecAgg(AggState *node)
 {
 	TupleTableSlot *result;
 
-	/*
-	 * Check to see if we're still projecting out tuples from a previous agg
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->ss.ps.ps_TupFromTlist)
-	{
-		ExprDoneCond isDone;
-
-		result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		node->ss.ps.ps_TupFromTlist = false;
-	}
-
-	/*
-	 * (We must do the ps_TupFromTlist check first, because in some cases
-	 * agg_done gets set before we emit the final aggregate tuple, and we have
-	 * to finish running SRFs for it.)
-	 */
 	if (!node->agg_done)
 	{
 		/* Dispatch based on strategy */
@@ -2571,8 +2539,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
 	ExecAssignResultTypeFromTL(&aggstate->ss.ps);
 	ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
 
-	aggstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * get the count of aggregates in targetlist and quals
 	 */
@@ -3575,8 +3541,6 @@ ExecReScanAgg(AggState *node)
 
 	node->agg_done = false;
 
-	node->ss.ps.ps_TupFromTlist = false;
-
 	if (aggnode->aggstrategy == AGG_HASHED)
 	{
 		/*
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index d5fd57ae4b..f18827de0b 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -575,8 +575,6 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &scanstate->ss.ps);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * initialize child expressions
 	 */
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 2f9c007409..610797b36b 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -269,8 +269,6 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
 	ExecAssignResultTypeFromTL(&scanstate->ss.ps);
 	ExecAssignScanProjectionInfo(&scanstate->ss);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	return scanstate;
 }
 
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index b01e65f362..a27430242a 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -48,8 +48,6 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
 	/* create expression context for node */
 	ExecAssignExprContext(estate, &css->ss.ps);
 
-	css->ss.ps.ps_TupFromTlist = false;
-
 	/* initialize child expressions */
 	css->ss.ps.targetlist = (List *)
 		ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 8f21c17f24..86a77e356c 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -152,8 +152,6 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &scanstate->ss.ps);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * initialize child expressions
 	 */
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 1b593dcd71..972022784d 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -331,8 +331,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &scanstate->ss.ps);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * tuple table initialization
 	 */
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index f95c3d1b19..92b361ebb3 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -100,8 +100,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
 	outerNode = outerPlan(node);
 	outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
 
-	gatherstate->ps.ps_TupFromTlist = false;
-
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
@@ -132,8 +130,6 @@ ExecGather(GatherState *node)
 	TupleTableSlot *fslot = node->funnel_slot;
 	int			i;
 	TupleTableSlot *slot;
-	TupleTableSlot *resultSlot;
-	ExprDoneCond isDone;
 	ExprContext *econtext;
 
 	/*
@@ -200,20 +196,6 @@ ExecGather(GatherState *node)
 	}
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous scan
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->ps.ps_TupFromTlist)
-	{
-		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return resultSlot;
-		/* Done with that source tuple... */
-		node->ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note we can't do this
 	 * until we're done projecting.  This will also clear any previous tuple
@@ -241,13 +223,8 @@ ExecGather(GatherState *node)
 		 * back around for another tuple
 		 */
 		econtext->ecxt_outertuple = slot;
-		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
 
-		if (isDone != ExprEndResult)
-		{
-			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-			return resultSlot;
-		}
+		return ExecProject(node->ps.ps_ProjInfo);
 	}
 
 	return slot;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 6a05023e50..66c095bc72 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -50,23 +50,6 @@ ExecGroup(GroupState *node)
 	grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous group
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->ss.ps.ps_TupFromTlist)
-	{
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
-
-		result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		node->ss.ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * The ScanTupleSlot holds the (copied) first tuple of each group.
 	 */
 	firsttupleslot = node->ss.ss_ScanTupleSlot;
@@ -107,16 +90,7 @@ ExecGroup(GroupState *node)
 			/*
 			 * Form and return a projection tuple using the first input tuple.
 			 */
-			TupleTableSlot *result;
-			ExprDoneCond isDone;
-
-			result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-
-			if (isDone != ExprEndResult)
-			{
-				node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-				return result;
-			}
+			return ExecProject(node->ss.ps.ps_ProjInfo);
 		}
 		else
 			InstrCountFiltered1(node, 1);
@@ -170,16 +144,7 @@ ExecGroup(GroupState *node)
 			/*
 			 * Form and return a projection tuple using the first input tuple.
 			 */
-			TupleTableSlot *result;
-			ExprDoneCond isDone;
-
-			result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone);
-
-			if (isDone != ExprEndResult)
-			{
-				node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-				return result;
-			}
+			return ExecProject(node->ss.ps.ps_ProjInfo);
 		}
 		else
 			InstrCountFiltered1(node, 1);
@@ -246,8 +211,6 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
 	ExecAssignResultTypeFromTL(&grpstate->ss.ps);
 	ExecAssignProjectionInfo(&grpstate->ss.ps, NULL);
 
-	grpstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * Precompute fmgr lookup data for inner loop
 	 */
@@ -283,7 +246,6 @@ ExecReScanGroup(GroupState *node)
 	PlanState  *outerPlan = outerPlanState(node);
 
 	node->grp_done = FALSE;
-	node->ss.ps.ps_TupFromTlist = false;
 	/* must clear first tuple */
 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 11db08f5fa..af5934d2bc 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -959,7 +959,7 @@ ExecHashGetHashValue(HashJoinTable hashtable,
 		/*
 		 * Get the join attribute value of the tuple
 		 */
-		keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL);
+		keyval = ExecEvalExpr(keyexpr, econtext, &isNull);
 
 		/*
 		 * If the attribute is NULL, and the join operator is strict, then
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index b41e4e2f98..f34e476bad 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -66,7 +66,6 @@ ExecHashJoin(HashJoinState *node)
 	List	   *joinqual;
 	List	   *otherqual;
 	ExprContext *econtext;
-	ExprDoneCond isDone;
 	HashJoinTable hashtable;
 	TupleTableSlot *outerTupleSlot;
 	uint32		hashvalue;
@@ -83,22 +82,6 @@ ExecHashJoin(HashJoinState *node)
 	econtext = node->js.ps.ps_ExprContext;
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous join
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->js.ps.ps_TupFromTlist)
-	{
-		TupleTableSlot *result;
-
-		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		node->js.ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note this can't happen
 	 * until we're done projecting out tuples from a join tuple.
@@ -314,18 +297,7 @@ ExecHashJoin(HashJoinState *node)
 
 					if (otherqual == NIL ||
 						ExecQual(otherqual, econtext, false))
-					{
-						TupleTableSlot *result;
-
-						result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-						if (isDone != ExprEndResult)
-						{
-							node->js.ps.ps_TupFromTlist =
-								(isDone == ExprMultipleResult);
-							return result;
-						}
-					}
+						return ExecProject(node->js.ps.ps_ProjInfo);
 					else
 						InstrCountFiltered2(node, 1);
 				}
@@ -353,18 +325,7 @@ ExecHashJoin(HashJoinState *node)
 
 					if (otherqual == NIL ||
 						ExecQual(otherqual, econtext, false))
-					{
-						TupleTableSlot *result;
-
-						result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-						if (isDone != ExprEndResult)
-						{
-							node->js.ps.ps_TupFromTlist =
-								(isDone == ExprMultipleResult);
-							return result;
-						}
-					}
+						return ExecProject(node->js.ps.ps_ProjInfo);
 					else
 						InstrCountFiltered2(node, 1);
 				}
@@ -392,18 +353,7 @@ ExecHashJoin(HashJoinState *node)
 
 				if (otherqual == NIL ||
 					ExecQual(otherqual, econtext, false))
-				{
-					TupleTableSlot *result;
-
-					result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-					if (isDone != ExprEndResult)
-					{
-						node->js.ps.ps_TupFromTlist =
-							(isDone == ExprMultipleResult);
-						return result;
-					}
-				}
+					return ExecProject(node->js.ps.ps_ProjInfo);
 				else
 					InstrCountFiltered2(node, 1);
 				break;
@@ -586,7 +536,6 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
 	/* child Hash node needs to evaluate inner hash keys, too */
 	((HashState *) innerPlanState(hjstate))->hashkeys = rclauses;
 
-	hjstate->js.ps.ps_TupFromTlist = false;
 	hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;
 	hjstate->hj_MatchedOuter = false;
 	hjstate->hj_OuterNotEmpty = false;
@@ -1000,7 +949,6 @@ ExecReScanHashJoin(HashJoinState *node)
 	node->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO;
 	node->hj_CurTuple = NULL;
 
-	node->js.ps.ps_TupFromTlist = false;
 	node->hj_MatchedOuter = false;
 	node->hj_FirstOuterTupleSlot = NULL;
 
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index ddef3a42bf..d5b19b7c11 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -412,8 +412,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &indexstate->ss.ps);
 
-	indexstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * initialize child expressions
 	 *
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 97a6fac34d..5734550d2c 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -336,8 +336,7 @@ EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
 
 		node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
 												  econtext,
-												  &node->iss_OrderByNulls[i],
-												  NULL);
+												  &node->iss_OrderByNulls[i]);
 		i++;
 	}
 
@@ -590,8 +589,7 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
 		 */
 		scanvalue = ExecEvalExpr(key_expr,
 								 econtext,
-								 &isNull,
-								 NULL);
+								 &isNull);
 		if (isNull)
 		{
 			scan_key->sk_argument = scanvalue;
@@ -648,8 +646,7 @@ ExecIndexEvalArrayKeys(ExprContext *econtext,
 		 */
 		arraydatum = ExecEvalExpr(array_expr,
 								  econtext,
-								  &isNull,
-								  NULL);
+								  &isNull);
 		if (isNull)
 		{
 			result = false;
@@ -837,8 +834,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &indexstate->ss.ps);
 
-	indexstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * initialize child expressions
 	 *
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 885931e594..aaec132218 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -239,8 +239,7 @@ recompute_limits(LimitState *node)
 	{
 		val = ExecEvalExprSwitchContext(node->limitOffset,
 										econtext,
-										&isNull,
-										NULL);
+										&isNull);
 		/* Interpret NULL offset as no offset */
 		if (isNull)
 			node->offset = 0;
@@ -263,8 +262,7 @@ recompute_limits(LimitState *node)
 	{
 		val = ExecEvalExprSwitchContext(node->limitCount,
 										econtext,
-										&isNull,
-										NULL);
+										&isNull);
 		/* Interpret NULL count as no count (LIMIT ALL) */
 		if (isNull)
 		{
@@ -346,18 +344,11 @@ pass_down_bound(LimitState *node, PlanState *child_node)
 	else if (IsA(child_node, ResultState))
 	{
 		/*
-		 * An extra consideration here is that if the Result is projecting a
-		 * targetlist that contains any SRFs, we can't assume that every input
-		 * tuple generates an output tuple, so a Sort underneath might need to
-		 * return more than N tuples to satisfy LIMIT N. So we cannot use
-		 * bounded sort.
-		 *
 		 * If Result supported qual checking, we'd have to punt on seeing a
-		 * qual, too.  Note that having a resconstantqual is not a
-		 * showstopper: if that fails we're not getting any rows at all.
+		 * qual.  Note that having a resconstantqual is not a showstopper: if
+		 * that fails we're not getting any rows at all.
 		 */
-		if (outerPlanState(child_node) &&
-			!expression_returns_set((Node *) child_node->plan->targetlist))
+		if (outerPlanState(child_node))
 			pass_down_bound(node, outerPlanState(child_node));
 	}
 }
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 2fd1856603..5150776b00 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -313,7 +313,7 @@ MJEvalOuterValues(MergeJoinState *mergestate)
 		MergeJoinClause clause = &mergestate->mj_Clauses[i];
 
 		clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
-									  &clause->lisnull, NULL);
+									  &clause->lisnull);
 		if (clause->lisnull)
 		{
 			/* match is impossible; can we end the join early? */
@@ -360,7 +360,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
 		MergeJoinClause clause = &mergestate->mj_Clauses[i];
 
 		clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
-									  &clause->risnull, NULL);
+									  &clause->risnull);
 		if (clause->risnull)
 		{
 			/* match is impossible; can we end the join early? */
@@ -465,19 +465,10 @@ MJFillOuter(MergeJoinState *node)
 		 * qualification succeeded.  now form the desired projection tuple and
 		 * return the slot containing it.
 		 */
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
 
 		MJ_printf("ExecMergeJoin: returning outer fill tuple\n");
 
-		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-		if (isDone != ExprEndResult)
-		{
-			node->js.ps.ps_TupFromTlist =
-				(isDone == ExprMultipleResult);
-			return result;
-		}
+		return ExecProject(node->js.ps.ps_ProjInfo);
 	}
 	else
 		InstrCountFiltered2(node, 1);
@@ -506,19 +497,9 @@ MJFillInner(MergeJoinState *node)
 		 * qualification succeeded.  now form the desired projection tuple and
 		 * return the slot containing it.
 		 */
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
-
 		MJ_printf("ExecMergeJoin: returning inner fill tuple\n");
 
-		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-		if (isDone != ExprEndResult)
-		{
-			node->js.ps.ps_TupFromTlist =
-				(isDone == ExprMultipleResult);
-			return result;
-		}
+		return ExecProject(node->js.ps.ps_ProjInfo);
 	}
 	else
 		InstrCountFiltered2(node, 1);
@@ -642,23 +623,6 @@ ExecMergeJoin(MergeJoinState *node)
 	doFillInner = node->mj_FillInner;
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous join
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->js.ps.ps_TupFromTlist)
-	{
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
-
-		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		node->js.ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note this can't happen
 	 * until we're done projecting out tuples from a join tuple.
@@ -856,20 +820,9 @@ ExecMergeJoin(MergeJoinState *node)
 						 * qualification succeeded.  now form the desired
 						 * projection tuple and return the slot containing it.
 						 */
-						TupleTableSlot *result;
-						ExprDoneCond isDone;
-
 						MJ_printf("ExecMergeJoin: returning tuple\n");
 
-						result = ExecProject(node->js.ps.ps_ProjInfo,
-											 &isDone);
-
-						if (isDone != ExprEndResult)
-						{
-							node->js.ps.ps_TupFromTlist =
-								(isDone == ExprMultipleResult);
-							return result;
-						}
+						return ExecProject(node->js.ps.ps_ProjInfo);
 					}
 					else
 						InstrCountFiltered2(node, 1);
@@ -1629,7 +1582,6 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
 	 * initialize join state
 	 */
 	mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
-	mergestate->js.ps.ps_TupFromTlist = false;
 	mergestate->mj_MatchedOuter = false;
 	mergestate->mj_MatchedInner = false;
 	mergestate->mj_OuterTupleSlot = NULL;
@@ -1684,7 +1636,6 @@ ExecReScanMergeJoin(MergeJoinState *node)
 	ExecClearTuple(node->mj_MarkedTupleSlot);
 
 	node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
-	node->js.ps.ps_TupFromTlist = false;
 	node->mj_MatchedOuter = false;
 	node->mj_MatchedInner = false;
 	node->mj_OuterTupleSlot = NULL;
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 4692427e60..dab9c4129a 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -175,7 +175,7 @@ ExecProcessReturning(ResultRelInfo *resultRelInfo,
 	econtext->ecxt_outertuple = planSlot;
 
 	/* Compute the RETURNING expressions */
-	return ExecProject(projectReturning, NULL);
+	return ExecProject(projectReturning);
 }
 
 /*
@@ -1302,7 +1302,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
 	}
 
 	/* Project the new tuple version */
-	ExecProject(resultRelInfo->ri_onConflictSetProj, NULL);
+	ExecProject(resultRelInfo->ri_onConflictSetProj);
 
 	/*
 	 * Note that it is possible that the target tuple has been modified in
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index e05842768a..5af04fde04 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -82,23 +82,6 @@ ExecNestLoop(NestLoopState *node)
 	econtext = node->js.ps.ps_ExprContext;
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous join
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->js.ps.ps_TupFromTlist)
-	{
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
-
-		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		node->js.ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note this can't happen
 	 * until we're done projecting out tuples from a join tuple.
@@ -201,19 +184,10 @@ ExecNestLoop(NestLoopState *node)
 					 * the slot containing the result tuple using
 					 * ExecProject().
 					 */
-					TupleTableSlot *result;
-					ExprDoneCond isDone;
 
 					ENL1_printf("qualification succeeded, projecting tuple");
 
-					result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-					if (isDone != ExprEndResult)
-					{
-						node->js.ps.ps_TupFromTlist =
-							(isDone == ExprMultipleResult);
-						return result;
-					}
+					return ExecProject(node->js.ps.ps_ProjInfo);
 				}
 				else
 					InstrCountFiltered2(node, 1);
@@ -259,19 +233,10 @@ ExecNestLoop(NestLoopState *node)
 				 * qualification was satisfied so we project and return the
 				 * slot containing the result tuple using ExecProject().
 				 */
-				TupleTableSlot *result;
-				ExprDoneCond isDone;
 
 				ENL1_printf("qualification succeeded, projecting tuple");
 
-				result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-				if (isDone != ExprEndResult)
-				{
-					node->js.ps.ps_TupFromTlist =
-						(isDone == ExprMultipleResult);
-					return result;
-				}
+				return ExecProject(node->js.ps.ps_ProjInfo);
 			}
 			else
 				InstrCountFiltered2(node, 1);
@@ -377,7 +342,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
 	/*
 	 * finally, wipe the current outer tuple clean.
 	 */
-	nlstate->js.ps.ps_TupFromTlist = false;
 	nlstate->nl_NeedNewOuter = true;
 	nlstate->nl_MatchedOuter = false;
 
@@ -441,7 +405,6 @@ ExecReScanNestLoop(NestLoopState *node)
 	 * outer Vars are used as run-time keys...
 	 */
 
-	node->js.ps.ps_TupFromTlist = false;
 	node->nl_NeedNewOuter = true;
 	node->nl_MatchedOuter = false;
 }
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 391e97ea6f..eae0f1dad9 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -169,7 +169,7 @@ ExecProjectSRF(ProjectSetState *node, bool continuing)
 		else
 		{
 			/* Non-SRF tlist expression, just evaluate normally. */
-			*result = ExecEvalExpr(gstate->arg, econtext, isnull, NULL);
+			*result = ExecEvalExpr(gstate->arg, econtext, isnull);
 			*isdone = ExprSingleResult;
 		}
 
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 59dacd33ef..759cbe6aec 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -67,10 +67,8 @@ TupleTableSlot *
 ExecResult(ResultState *node)
 {
 	TupleTableSlot *outerTupleSlot;
-	TupleTableSlot *resultSlot;
 	PlanState  *outerPlan;
 	ExprContext *econtext;
-	ExprDoneCond isDone;
 
 	econtext = node->ps.ps_ExprContext;
 
@@ -92,20 +90,6 @@ ExecResult(ResultState *node)
 	}
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous scan
-	 * tuple (because there is a function-returning-set in the projection
-	 * expressions).  If so, try to project another one.
-	 */
-	if (node->ps.ps_TupFromTlist)
-	{
-		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return resultSlot;
-		/* Done with that source tuple... */
-		node->ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Reset per-tuple memory context to free any expression evaluation
 	 * storage allocated in the previous tuple cycle.  Note this can't happen
 	 * until we're done projecting out tuples from a scan tuple.
@@ -147,18 +131,8 @@ ExecResult(ResultState *node)
 			node->rs_done = true;
 		}
 
-		/*
-		 * form the result tuple using ExecProject(), and return it --- unless
-		 * the projection produces an empty set, in which case we must loop
-		 * back to see if there are more outerPlan tuples.
-		 */
-		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
-
-		if (isDone != ExprEndResult)
-		{
-			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
-			return resultSlot;
-		}
+		/* form the result tuple using ExecProject(), and return it */
+		return ExecProject(node->ps.ps_ProjInfo);
 	}
 
 	return NULL;
@@ -228,8 +202,6 @@ ExecInitResult(Result *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &resstate->ps);
 
-	resstate->ps.ps_TupFromTlist = false;
-
 	/*
 	 * tuple table initialization
 	 */
@@ -295,7 +267,6 @@ void
 ExecReScanResult(ResultState *node)
 {
 	node->rs_done = false;
-	node->ps.ps_TupFromTlist = false;
 	node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
 
 	/*
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 8db5469d5a..d38265e810 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -189,8 +189,6 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
 	 */
 	InitScanRelation(scanstate, estate, eflags);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
@@ -300,8 +298,7 @@ tablesample_init(SampleScanState *scanstate)
 
 		params[i] = ExecEvalExprSwitchContext(argstate,
 											  econtext,
-											  &isnull,
-											  NULL);
+											  &isnull);
 		if (isnull)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT),
@@ -313,8 +310,7 @@ tablesample_init(SampleScanState *scanstate)
 	{
 		datum = ExecEvalExprSwitchContext(scanstate->repeatable,
 										  econtext,
-										  &isnull,
-										  NULL);
+										  &isnull);
 		if (isnull)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TABLESAMPLE_REPEAT),
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 439a94694b..e61895de0a 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -206,8 +206,6 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
 	 */
 	InitScanRelation(scanstate, estate, eflags);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 68edcd4567..12115bc541 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -41,12 +41,10 @@
 
 static Datum ExecSubPlan(SubPlanState *node,
 			ExprContext *econtext,
-			bool *isNull,
-			ExprDoneCond *isDone);
+			bool *isNull);
 static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node,
 					   ExprContext *econtext,
-					   bool *isNull,
-					   ExprDoneCond *isDone);
+					   bool *isNull);
 static Datum ExecHashSubPlan(SubPlanState *node,
 				ExprContext *econtext,
 				bool *isNull);
@@ -69,15 +67,12 @@ static bool slotNoNulls(TupleTableSlot *slot);
 static Datum
 ExecSubPlan(SubPlanState *node,
 			ExprContext *econtext,
-			bool *isNull,
-			ExprDoneCond *isDone)
+			bool *isNull)
 {
 	SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
 
 	/* Set default values for result flags: non-null, not a set result */
 	*isNull = false;
-	if (isDone)
-		*isDone = ExprSingleResult;
 
 	/* Sanity checks */
 	if (subplan->subLinkType == CTE_SUBLINK)
@@ -128,7 +123,7 @@ ExecHashSubPlan(SubPlanState *node,
 	 * have to set the econtext to use (hack alert!).
 	 */
 	node->projLeft->pi_exprContext = econtext;
-	slot = ExecProject(node->projLeft, NULL);
+	slot = ExecProject(node->projLeft);
 
 	/*
 	 * Note: because we are typically called in a per-tuple context, we have
@@ -285,8 +280,7 @@ ExecScanSubPlan(SubPlanState *node,
 
 		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
 											   econtext,
-											   &(prm->isnull),
-											   NULL);
+											   &(prm->isnull));
 		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
 	}
 
@@ -403,7 +397,7 @@ ExecScanSubPlan(SubPlanState *node,
 		}
 
 		rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
-											  &rownull, NULL);
+											  &rownull);
 
 		if (subLinkType == ANY_SUBLINK)
 		{
@@ -572,7 +566,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
 										  &(prmdata->isnull));
 			col++;
 		}
-		slot = ExecProject(node->projRight, NULL);
+		slot = ExecProject(node->projRight);
 
 		/*
 		 * If result contains any nulls, store separately or not at all.
@@ -985,8 +979,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 
 		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
 											   econtext,
-											   &(prm->isnull),
-											   NULL);
+											   &(prm->isnull));
 		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
 	}
 
@@ -1222,8 +1215,7 @@ ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
 static Datum
 ExecAlternativeSubPlan(AlternativeSubPlanState *node,
 					   ExprContext *econtext,
-					   bool *isNull,
-					   ExprDoneCond *isDone)
+					   bool *isNull)
 {
 	/* Just pass control to the active subplan */
 	SubPlanState *activesp = (SubPlanState *) list_nth(node->subplans,
@@ -1231,8 +1223,5 @@ ExecAlternativeSubPlan(AlternativeSubPlanState *node,
 
 	Assert(IsA(activesp, SubPlanState));
 
-	return ExecSubPlan(activesp,
-					   econtext,
-					   isNull,
-					   isDone);
+	return ExecSubPlan(activesp, econtext, isNull);
 }
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index a4387da80a..230a96f9d2 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -138,8 +138,6 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
 	 */
 	subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags);
 
-	subquerystate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
 	 */
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e3d3fc3842..13ed886577 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -104,8 +104,7 @@ TidListCreate(TidScanState *tidstate)
 			itemptr = (ItemPointer)
 				DatumGetPointer(ExecEvalExprSwitchContext(exstate,
 														  econtext,
-														  &isNull,
-														  NULL));
+														  &isNull));
 			if (!isNull &&
 				ItemPointerIsValid(itemptr) &&
 				ItemPointerGetBlockNumber(itemptr) < nblocks)
@@ -133,8 +132,7 @@ TidListCreate(TidScanState *tidstate)
 			exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
 			arraydatum = ExecEvalExprSwitchContext(exstate,
 												   econtext,
-												   &isNull,
-												   NULL);
+												   &isNull);
 			if (isNull)
 				continue;
 			itemarray = DatumGetArrayTypeP(arraydatum);
@@ -469,8 +467,6 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &tidstate->ss.ps);
 
-	tidstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * initialize child expressions
 	 */
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 5b42ca93cf..9883a8b130 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -140,8 +140,7 @@ ValuesNext(ValuesScanState *node)
 
 			values[resind] = ExecEvalExpr(estate,
 										  econtext,
-										  &isnull[resind],
-										  NULL);
+										  &isnull[resind]);
 
 			/*
 			 * We must force any R/W expanded datums to read-only state, in
@@ -272,8 +271,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
 		scanstate->exprlists[i++] = (List *) lfirst(vtl);
 	}
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 17884d2c44..6ac6b83cdd 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -256,7 +256,7 @@ advance_windowaggregate(WindowAggState *winstate,
 	if (filter)
 	{
 		bool		isnull;
-		Datum		res = ExecEvalExpr(filter, econtext, &isnull, NULL);
+		Datum		res = ExecEvalExpr(filter, econtext, &isnull);
 
 		if (isnull || !DatumGetBool(res))
 		{
@@ -272,7 +272,7 @@ advance_windowaggregate(WindowAggState *winstate,
 		ExprState  *argstate = (ExprState *) lfirst(arg);
 
 		fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
-									  &fcinfo->argnull[i], NULL);
+									  &fcinfo->argnull[i]);
 		i++;
 	}
 
@@ -433,7 +433,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
 	if (filter)
 	{
 		bool		isnull;
-		Datum		res = ExecEvalExpr(filter, econtext, &isnull, NULL);
+		Datum		res = ExecEvalExpr(filter, econtext, &isnull);
 
 		if (isnull || !DatumGetBool(res))
 		{
@@ -449,7 +449,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
 		ExprState  *argstate = (ExprState *) lfirst(arg);
 
 		fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
-									  &fcinfo->argnull[i], NULL);
+									  &fcinfo->argnull[i]);
 		i++;
 	}
 
@@ -1584,15 +1584,12 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
  *	ExecWindowAgg receives tuples from its outer subplan and
  *	stores them into a tuplestore, then processes window functions.
  *	This node doesn't reduce nor qualify any row so the number of
- *	returned rows is exactly the same as its outer subplan's result
- *	(ignoring the case of SRFs in the targetlist, that is).
+ *	returned rows is exactly the same as its outer subplan's result.
  * -----------------
  */
 TupleTableSlot *
 ExecWindowAgg(WindowAggState *winstate)
 {
-	TupleTableSlot *result;
-	ExprDoneCond isDone;
 	ExprContext *econtext;
 	int			i;
 	int			numfuncs;
@@ -1601,23 +1598,6 @@ ExecWindowAgg(WindowAggState *winstate)
 		return NULL;
 
 	/*
-	 * Check to see if we're still projecting out tuples from a previous
-	 * output tuple (because there is a function-returning-set in the
-	 * projection expressions).  If so, try to project another one.
-	 */
-	if (winstate->ss.ps.ps_TupFromTlist)
-	{
-		TupleTableSlot *result;
-		ExprDoneCond isDone;
-
-		result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
-		if (isDone == ExprMultipleResult)
-			return result;
-		/* Done with that source tuple... */
-		winstate->ss.ps.ps_TupFromTlist = false;
-	}
-
-	/*
 	 * Compute frame offset values, if any, during first call.
 	 */
 	if (winstate->all_first)
@@ -1634,8 +1614,7 @@ ExecWindowAgg(WindowAggState *winstate)
 			Assert(winstate->startOffset != NULL);
 			value = ExecEvalExprSwitchContext(winstate->startOffset,
 											  econtext,
-											  &isnull,
-											  NULL);
+											  &isnull);
 			if (isnull)
 				ereport(ERROR,
 						(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
@@ -1660,8 +1639,7 @@ ExecWindowAgg(WindowAggState *winstate)
 			Assert(winstate->endOffset != NULL);
 			value = ExecEvalExprSwitchContext(winstate->endOffset,
 											  econtext,
-											  &isnull,
-											  NULL);
+											  &isnull);
 			if (isnull)
 				ereport(ERROR,
 						(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
@@ -1684,7 +1662,6 @@ ExecWindowAgg(WindowAggState *winstate)
 		winstate->all_first = false;
 	}
 
-restart:
 	if (winstate->buffer == NULL)
 	{
 		/* Initialize for first partition and set current row = 0 */
@@ -1776,17 +1753,8 @@ restart:
 	 * evaluated with respect to that row.
 	 */
 	econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
-	result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
 
-	if (isDone == ExprEndResult)
-	{
-		/* SRF in tlist returned no rows, so advance to next input tuple */
-		goto restart;
-	}
-
-	winstate->ss.ps.ps_TupFromTlist =
-		(isDone == ExprMultipleResult);
-	return result;
+	return ExecProject(winstate->ss.ps.ps_ProjInfo);
 }
 
 /* -----------------
@@ -1896,8 +1864,6 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
 	ExecAssignResultTypeFromTL(&winstate->ss.ps);
 	ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
 
-	winstate->ss.ps.ps_TupFromTlist = false;
-
 	/* Set up data for comparing tuples */
 	if (node->partNumCols > 0)
 		winstate->partEqfunctions = execTuplesMatchPrepare(node->partNumCols,
@@ -2090,8 +2056,6 @@ ExecReScanWindowAgg(WindowAggState *node)
 	ExprContext *econtext = node->ss.ps.ps_ExprContext;
 
 	node->all_done = false;
-
-	node->ss.ps.ps_TupFromTlist = false;
 	node->all_first = true;
 
 	/* release tuplestore et al */
@@ -2712,7 +2676,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno,
 		}
 		econtext->ecxt_outertuple = slot;
 		return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
-							econtext, isnull, NULL);
+							econtext, isnull);
 	}
 }
 
@@ -2811,7 +2775,7 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 		}
 		econtext->ecxt_outertuple = slot;
 		return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
-							econtext, isnull, NULL);
+							econtext, isnull);
 	}
 }
 
@@ -2841,5 +2805,5 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull)
 
 	econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
 	return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
-						econtext, isnull, NULL);
+						econtext, isnull);
 }
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index 73a1a8238a..bdba9e0bfc 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -174,8 +174,6 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignResultTypeFromTL(&scanstate->ss.ps);
 
-	scanstate->ss.ps.ps_TupFromTlist = false;
-
 	return scanstate;
 }
 
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 85ffa3afc7..83519fa140 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -4303,7 +4303,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
 
 	/*
 	 * Forget it if the function is not SQL-language or has other showstopper
-	 * properties.  (The nargs check is just paranoia.)
+	 * properties.  (The nargs and retset checks are just paranoia.)
 	 */
 	if (funcform->prolang != SQLlanguageId ||
 		funcform->prosecdef ||
@@ -4685,7 +4685,7 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
 	 */
 	const_val = ExecEvalExprSwitchContext(exprstate,
 										  GetPerTupleExprContext(estate),
-										  &const_is_null, NULL);
+										  &const_is_null);
 
 	/* Get info needed about result datatype */
 	get_typlenbyval(result_type, &resultTypLen, &resultTypByVal);
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index fd009e135e..c4a04cfa95 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1596,7 +1596,7 @@ operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
 	/* And execute it. */
 	test_result = ExecEvalExprSwitchContext(test_exprstate,
 											GetPerTupleExprContext(estate),
-											&isNull, NULL);
+											&isNull);
 
 	/* Get back to outer memory context */
 	MemoryContextSwitchTo(oldcontext);
diff --git a/src/backend/utils/adt/domains.c b/src/backend/utils/adt/domains.c
index 14fa119f07..c2ad440013 100644
--- a/src/backend/utils/adt/domains.c
+++ b/src/backend/utils/adt/domains.c
@@ -179,7 +179,7 @@ domain_check_input(Datum value, bool isnull, DomainIOData *my_extra)
 
 					conResult = ExecEvalExprSwitchContext(con->check_expr,
 														  econtext,
-														  &conIsNull, NULL);
+														  &conIsNull);
 
 					if (!conIsNull &&
 						!DatumGetBool(conResult))
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index dcc5d6287a..e8bce3b806 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -603,7 +603,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
 		bool		isnull;
 		char	   *str;
 
-		value = ExecEvalExpr(e, econtext, &isnull, NULL);
+		value = ExecEvalExpr(e, econtext, &isnull);
 		if (isnull)
 			str = NULL;
 		else
@@ -620,7 +620,7 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
 		bool		isnull;
 		char	   *str;
 
-		value = ExecEvalExpr(e, econtext, &isnull, NULL);
+		value = ExecEvalExpr(e, econtext, &isnull);
 		/* here we can just forget NULL elements immediately */
 		if (!isnull)
 		{
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index d424031676..d00014a191 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -70,8 +70,8 @@
  * now it's just a macro invoking the function pointed to by an ExprState
  * node.  Beware of double evaluation of the ExprState argument!
  */
-#define ExecEvalExpr(expr, econtext, isNull, isDone) \
-	((*(expr)->evalfunc) (expr, econtext, isNull, isDone))
+#define ExecEvalExpr(expr, econtext, isNull) \
+	((*(expr)->evalfunc) (expr, econtext, isNull))
 
 
 /* Hook for plugins to get control in ExecutorStart() */
@@ -258,14 +258,13 @@ extern Datum ExecMakeFunctionResultSet(FuncExprState *fcache,
 						  bool *isNull,
 						  ExprDoneCond *isDone);
 extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
-						  bool *isNull, ExprDoneCond *isDone);
+						  bool *isNull);
 extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
 extern ExprState *ExecPrepareExpr(Expr *node, EState *estate);
 extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
 extern int	ExecTargetListLength(List *targetlist);
 extern int	ExecCleanTargetListLength(List *targetlist);
-extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
-			ExprDoneCond *isDone);
+extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo);
 
 /*
  * prototypes from functions in execScan.c
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1da1e1f804..cf1e5ef1e8 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -156,7 +156,8 @@ typedef struct ExprContext
 } ExprContext;
 
 /*
- * Set-result status returned by ExecEvalExpr()
+ * Set-result status used when evaluating functions potentially returning a
+ * set.
  */
 typedef enum
 {
@@ -245,7 +246,6 @@ typedef struct ProjectionInfo
 	List	   *pi_targetlist;
 	ExprContext *pi_exprContext;
 	TupleTableSlot *pi_slot;
-	ExprDoneCond *pi_itemIsDone;
 	bool		pi_directMap;
 	int			pi_numSimpleVars;
 	int		   *pi_varSlotOffsets;
@@ -586,8 +586,7 @@ typedef struct ExprState ExprState;
 
 typedef Datum (*ExprStateEvalFunc) (ExprState *expression,
 												ExprContext *econtext,
-												bool *isNull,
-												ExprDoneCond *isDone);
+												bool *isNull);
 
 struct ExprState
 {
@@ -732,13 +731,6 @@ typedef struct FuncExprState
 	bool		setArgsValid;
 
 	/*
-	 * Flag to remember whether we found a set-valued argument to the
-	 * function. This causes the function result to be a set as well. Valid
-	 * only when setArgsValid is true or funcResultStore isn't NULL.
-	 */
-	bool		setHasSetArg;	/* some argument returns a set */
-
-	/*
 	 * Flag to remember whether we have registered a shutdown callback for
 	 * this FuncExprState.  We do so only if funcResultStore or setArgsValid
 	 * has been set at least once (since all the callback is for is to release
@@ -1081,8 +1073,6 @@ typedef struct PlanState
 	TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */
 	ExprContext *ps_ExprContext;	/* node's expression-evaluation context */
 	ProjectionInfo *ps_ProjInfo;	/* info for doing tuple projection */
-	bool		ps_TupFromTlist;/* state flag for processing set-valued
-								 * functions in targetlist */
 } PlanState;
 
 /* ----------------
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index bc7b00199e..b48146a362 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -5606,8 +5606,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
 	 */
 	*result = ExecEvalExpr(expr->expr_simple_state,
 						   econtext,
-						   isNull,
-						   NULL);
+						   isNull);
 
 	/* Assorted cleanup */
 	expr->expr_simple_in_use = false;
@@ -6272,7 +6271,7 @@ exec_cast_value(PLpgSQL_execstate *estate,
 			cast_entry->cast_in_use = true;
 
 			value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
-								 isnull, NULL);
+								 isnull);
 
 			cast_entry->cast_in_use = false;
 
-- 
2.11.0.22.g8d7a455.dirty

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to