diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 15d693fac4d45929b441cf384a323afbc5dbbdca..5a34a46712d964a5249520d9891a168fd91d5fff 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2103,7 +2103,9 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
 	if (flinfo->fn_retset)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("set-valued function called in context that cannot accept a set")));
+				 errmsg("set-valued function called in context that cannot accept a set"),
+				 parent ? executor_errposition(parent->state,
+										  exprLocation((Node *) node)) : 0));
 
 	/* Build code to evaluate arguments directly into the fcinfo struct */
 	argno = 0;
diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c
index 4badd5c576fc12d07b7a2af3800c2cd7da3cf1ab..077ac208c13e3a6db2d6ed735961466ab27073ce 100644
--- a/src/backend/executor/execSRF.c
+++ b/src/backend/executor/execSRF.c
@@ -34,7 +34,8 @@
 
 
 /* static function decls */
-static void init_sexpr(Oid foid, Oid input_collation, SetExprState *sexpr,
+static void init_sexpr(Oid foid, Oid input_collation, Expr *node,
+		   SetExprState *sexpr, PlanState *parent,
 		   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF);
 static void ShutdownSetExpr(Datum arg);
 static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
@@ -77,7 +78,7 @@ ExecInitTableFunctionResult(Expr *expr,
 		state->funcReturnsSet = func->funcretset;
 		state->args = ExecInitExprList(func->args, parent);
 
-		init_sexpr(func->funcid, func->inputcollid, state,
+		init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
 				   econtext->ecxt_per_query_memory, func->funcretset, false);
 	}
 	else
@@ -438,7 +439,7 @@ ExecInitFunctionResultSet(Expr *expr,
 		FuncExpr   *func = (FuncExpr *) expr;
 
 		state->args = ExecInitExprList(func->args, parent);
-		init_sexpr(func->funcid, func->inputcollid, state,
+		init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
 				   econtext->ecxt_per_query_memory, true, true);
 	}
 	else if (IsA(expr, OpExpr))
@@ -446,7 +447,7 @@ ExecInitFunctionResultSet(Expr *expr,
 		OpExpr	   *op = (OpExpr *) expr;
 
 		state->args = ExecInitExprList(op->args, parent);
-		init_sexpr(op->opfuncid, op->inputcollid, state,
+		init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent,
 				   econtext->ecxt_per_query_memory, true, true);
 	}
 	else
@@ -645,7 +646,8 @@ restart:
  * init_sexpr - initialize a SetExprState node during first use
  */
 static void
-init_sexpr(Oid foid, Oid input_collation, SetExprState *sexpr,
+init_sexpr(Oid foid, Oid input_collation, Expr *node,
+		   SetExprState *sexpr, PlanState *parent,
 		   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
 {
 	AclResult	aclresult;
@@ -683,7 +685,9 @@ init_sexpr(Oid foid, Oid input_collation, SetExprState *sexpr,
 	if (sexpr->func.fn_retset && !allowSRF)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("set-valued function called in context that cannot accept a set")));
+				 errmsg("set-valued function called in context that cannot accept a set"),
+				 parent ? executor_errposition(parent->state,
+										  exprLocation((Node *) node)) : 0));
 
 	/* Otherwise, caller should have marked the sexpr correctly */
 	Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index df3d6503d149d27f6d06818c2ffc062274f60ea7..08229bd6a727a4fd19519e793fc76b2794934086 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -28,6 +28,8 @@
  *		ExecOpenScanRelation	Common code for scan node init routines.
  *		ExecCloseScanRelation
  *
+ *		executor_errposition	Report syntactic position of an error.
+ *
  *		RegisterExprContextCallback    Register function shutdown callback
  *		UnregisterExprContextCallback  Deregister function shutdown callback
  *
@@ -44,6 +46,7 @@
 #include "access/relscan.h"
 #include "access/transam.h"
 #include "executor/executor.h"
+#include "mb/pg_wchar.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/parsetree.h"
 #include "storage/lmgr.h"
@@ -685,6 +688,36 @@ UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
 		bms_free(parmset);
 }
 
+/*
+ * executor_errposition
+ *		Report an execution-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call.  The return value
+ * is a dummy (always 0, in fact).
+ *
+ * The locations stored in parsetrees are byte offsets into the source string.
+ * We have to convert them to 1-based character indexes for reporting to
+ * clients.  (We do things this way to avoid unnecessary overhead in the
+ * normal non-error case: computing character indexes would be much more
+ * expensive than storing token offsets.)
+ */
+int
+executor_errposition(EState *estate, int location)
+{
+	int			pos;
+
+	/* No-op if location was not provided */
+	if (location < 0)
+		return 0;
+	/* Can't do anything if source text is not available */
+	if (estate == NULL || estate->es_sourceText == NULL)
+		return 0;
+	/* Convert offset to character number */
+	pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
+	/* And pass it to the ereport mechanism */
+	return errposition(pos);
+}
+
 /*
  * Register a shutdown callback in an ExprContext.
  *
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index a4a6e5bae437977b340858587faed1f4b20fdda4..35021e1839b4cbba04003ba0eb79901049cd6539 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1197,9 +1197,6 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 	cplan = GetCachedPlan(plansource, paramLI, false, _SPI_current->queryEnv);
 	stmt_list = cplan->stmt_list;
 
-	/* Pop the error context stack */
-	error_context_stack = spierrcontext.previous;
-
 	if (!plan->saved)
 	{
 		/*
@@ -1318,6 +1315,9 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 
 	Assert(portal->strategy != PORTAL_MULTI_QUERY);
 
+	/* Pop the error context stack */
+	error_context_stack = spierrcontext.previous;
+
 	/* Pop the SPI stack */
 	_SPI_end_call(true);
 
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index f7f3189a1a096d2ccefafe3ba9a2015c97d22c0d..3107cf5b89e9b481fd86ec60f9313340c3278187 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -482,6 +482,8 @@ extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
 extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
 extern void ExecCloseScanRelation(Relation scanrel);
 
+extern int	executor_errposition(EState *estate, int location);
+
 extern void RegisterExprContextCallback(ExprContext *econtext,
 							ExprContextCallbackFunction function,
 							Datum arg);
diff --git a/src/test/regress/expected/tsrf.out b/src/test/regress/expected/tsrf.out
index 33f370b49498f88d4ec6ffa5007a84f1e60d9942..c8ae361e75638e0a7fb1d3f1619834ad31beb555 100644
--- a/src/test/regress/expected/tsrf.out
+++ b/src/test/regress/expected/tsrf.out
@@ -193,9 +193,13 @@ SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest
 -- SRFs are not allowed in aggregate arguments
 SELECT min(generate_series(1, 3)) FROM few;
 ERROR:  set-valued function called in context that cannot accept a set
+LINE 1: SELECT min(generate_series(1, 3)) FROM few;
+                   ^
 -- SRFs are not allowed in window function arguments, either
 SELECT min(generate_series(1, 3)) OVER() FROM few;
 ERROR:  set-valued function called in context that cannot accept a set
+LINE 1: SELECT min(generate_series(1, 3)) OVER() FROM few;
+                   ^
 -- SRFs are normally computed after window functions
 SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few;
  id | lag | count | generate_series 
@@ -424,6 +428,8 @@ SELECT int4mul(generate_series(1,2), 10);
 -- but SRFs in function RTEs must be at top level (annoying restriction)
 SELECT * FROM int4mul(generate_series(1,2), 10);
 ERROR:  set-valued function called in context that cannot accept a set
+LINE 1: SELECT * FROM int4mul(generate_series(1,2), 10);
+                              ^
 -- DISTINCT ON is evaluated before tSRF evaluation if SRF is not
 -- referenced either in ORDER BY or in the DISTINCT ON list. The ORDER
 -- BY reference can be implicitly generated, if there's no other ORDER BY.