diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index cbcd6cf..98bcfa0 100644
*** a/src/backend/catalog/information_schema.sql
--- b/src/backend/catalog/information_schema.sql
*************** CREATE VIEW user_mapping_options AS
*** 2936,2947 ****
      SELECT authorization_identifier,
             foreign_server_catalog,
             foreign_server_name,
!            CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
             CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
                         OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
!                        OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) THEN (pg_options_to_table(um.umoptions)).option_value
                       ELSE NULL END AS character_data) AS option_value
!     FROM _pg_user_mappings um;
  
  GRANT SELECT ON user_mapping_options TO PUBLIC;
  
--- 2936,2949 ----
      SELECT authorization_identifier,
             foreign_server_catalog,
             foreign_server_name,
!            CAST(opts.option_name AS sql_identifier) AS option_name,
             CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
                         OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
!                        OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user)
!                      THEN opts.option_value
                       ELSE NULL END AS character_data) AS option_value
!     FROM _pg_user_mappings um,
!          pg_options_to_table(um.umoptions) opts;
  
  GRANT SELECT ON user_mapping_options TO PUBLIC;
  
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index efe1c37..5241fd2 100644
*** a/src/backend/parser/parse_agg.c
--- b/src/backend/parser/parse_agg.c
*************** check_agg_arguments_walker(Node *node,
*** 705,710 ****
--- 705,717 ----
  		}
  		/* Continue and descend into subtree */
  	}
+ 	/* We can throw error on sight for a set-returning function */
+ 	if ((IsA(node, FuncExpr) &&((FuncExpr *) node)->funcretset) ||
+ 		(IsA(node, OpExpr) &&((OpExpr *) node)->opretset))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("aggregate function calls cannot contain set-returning function calls"),
+ 				 parser_errposition(context->pstate, exprLocation(node))));
  	/* We can throw error on sight for a window function */
  	if (IsA(node, WindowFunc))
  		ereport(ERROR,
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 92101c9..102da58 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*************** transformMultiAssignRef(ParseState *psta
*** 1619,1625 ****
  static Node *
  transformCaseExpr(ParseState *pstate, CaseExpr *c)
  {
! 	CaseExpr   *newc;
  	Node	   *arg;
  	CaseTestExpr *placeholder;
  	List	   *newargs;
--- 1619,1626 ----
  static Node *
  transformCaseExpr(ParseState *pstate, CaseExpr *c)
  {
! 	CaseExpr   *newc = makeNode(CaseExpr);
! 	Node	   *last_srf = pstate->p_last_srf;
  	Node	   *arg;
  	CaseTestExpr *placeholder;
  	List	   *newargs;
*************** transformCaseExpr(ParseState *pstate, Ca
*** 1628,1635 ****
  	Node	   *defresult;
  	Oid			ptype;
  
- 	newc = makeNode(CaseExpr);
- 
  	/* transform the test expression, if any */
  	arg = transformExprRecurse(pstate, (Node *) c->arg);
  
--- 1629,1634 ----
*************** transformCaseExpr(ParseState *pstate, Ca
*** 1741,1746 ****
--- 1740,1755 ----
  								  "CASE/WHEN");
  	}
  
+ 	/* if any subexpression contained a SRF, complain */
+ 	if (pstate->p_last_srf != last_srf)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 		/* translator: %s is name of a SQL construct, eg GROUP BY */
+ 				 errmsg("set-returning functions are not allowed in %s",
+ 						"CASE"),
+ 				 parser_errposition(pstate,
+ 									exprLocation(pstate->p_last_srf))));
+ 
  	newc->location = c->location;
  
  	return (Node *) newc;
*************** static Node *
*** 2177,2182 ****
--- 2186,2192 ----
  transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
  {
  	CoalesceExpr *newc = makeNode(CoalesceExpr);
+ 	Node	   *last_srf = pstate->p_last_srf;
  	List	   *newargs = NIL;
  	List	   *newcoercedargs = NIL;
  	ListCell   *args;
*************** transformCoalesceExpr(ParseState *pstate
*** 2205,2210 ****
--- 2215,2230 ----
  		newcoercedargs = lappend(newcoercedargs, newe);
  	}
  
+ 	/* if any subexpression contained a SRF, complain */
+ 	if (pstate->p_last_srf != last_srf)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 		/* translator: %s is name of a SQL construct, eg GROUP BY */
+ 				 errmsg("set-returning functions are not allowed in %s",
+ 						"COALESCE"),
+ 				 parser_errposition(pstate,
+ 									exprLocation(pstate->p_last_srf))));
+ 
  	newc->args = newcoercedargs;
  	newc->location = c->location;
  	return (Node *) newc;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 55853c2..9c761c4 100644
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 771,776 ****
--- 771,780 ----
  		retval = (Node *) wfunc;
  	}
  
+ 	/* if it returns a set, remember it for error checks at higher levels */
+ 	if (retset)
+ 		pstate->p_last_srf = retval;
+ 
  	return retval;
  }
  
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index e40b10d..b2f9a9c 100644
*** a/src/backend/parser/parse_oper.c
--- b/src/backend/parser/parse_oper.c
*************** make_op(ParseState *pstate, List *opname
*** 843,849 ****
--- 843,853 ----
  
  	/* if it returns a set, check that's OK */
  	if (result->opretset)
+ 	{
  		check_srf_call_placement(pstate, location);
+ 		/* ... and remember it for error checks at higher levels */
+ 		pstate->p_last_srf = (Node *) result;
+ 	}
  
  	ReleaseSysCache(tup);
  
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 0b54840..6a3507f 100644
*** a/src/include/parser/parse_node.h
--- b/src/include/parser/parse_node.h
*************** typedef Node *(*CoerceParamHook) (ParseS
*** 157,162 ****
--- 157,165 ----
   * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated
   * constructs in the query.
   *
+  * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in
+  * the query, or NULL if none.
+  *
   * p_pre_columnref_hook, etc: optional parser hook functions for modifying the
   * interpretation of ColumnRefs and ParamRefs.
   *
*************** struct ParseState
*** 199,204 ****
--- 202,209 ----
  	bool		p_hasSubLinks;
  	bool		p_hasModifyingCTE;
  
+ 	Node	   *p_last_srf;		/* most recent set-returning func/op found */
+ 
  	/*
  	 * Optional hook functions for parser callbacks.  These are null unless
  	 * set up by the caller of make_parsestate.
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 4b6170d..5c82614 100644
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** select * from foobar();  -- fail
*** 1969,1986 ****
  ERROR:  function return row and query-specified return row do not match
  DETAIL:  Returned row contains 3 attributes, but query expects 2.
  drop function foobar();
- -- check behavior when a function's input sometimes returns a set (bug #8228)
- SELECT *,
-   lower(CASE WHEN id = 2 THEN (regexp_matches(str, '^0*([1-9]\d+)$'))[1]
-         ELSE str
-         END)
- FROM
-   (VALUES (1,''), (2,'0000000049404'), (3,'FROM 10000000876')) v(id, str);
-  id |      str      | lower 
- ----+---------------+-------
-   2 | 0000000049404 | 49404
- (1 row)
- 
  -- check whole-row-Var handling in nested lateral functions (bug #11703)
  create function extractq2(t int8_tbl) returns int8 as $$
    select t.q2
--- 1969,1974 ----
diff --git a/src/test/regress/expected/tsrf.out b/src/test/regress/expected/tsrf.out
index c8ae361..6e91ede 100644
*** a/src/test/regress/expected/tsrf.out
--- b/src/test/regress/expected/tsrf.out
*************** SELECT generate_series(1, generate_serie
*** 41,46 ****
--- 41,51 ----
                 3
  (6 rows)
  
+ -- but we've traditionally rejected the same in FROM
+ SELECT * FROM generate_series(1, generate_series(1, 3));
+ ERROR:  set-valued function called in context that cannot accept a set
+ LINE 1: SELECT * FROM generate_series(1, generate_series(1, 3));
+                                          ^
  -- srf, with two SRF arguments
  SELECT generate_series(generate_series(1,3), generate_series(2, 4));
   generate_series 
*************** SELECT few.dataa, count(*) FROM few WHER
*** 190,198 ****
   a     |     4
  (2 rows)
  
  -- 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
--- 195,212 ----
   a     |     4
  (2 rows)
  
+ -- SRFs are not allowed if they'd need to be conditionally executed
+ SELECT q1, case when q1 > 0 then generate_series(1,3) else 0 end FROM int8_tbl;
+ ERROR:  set-returning functions are not allowed in CASE
+ LINE 1: SELECT q1, case when q1 > 0 then generate_series(1,3) else 0...
+                                          ^
+ SELECT q1, coalesce(generate_series(1,3), 0) FROM int8_tbl;
+ ERROR:  set-returning functions are not allowed in COALESCE
+ LINE 1: SELECT q1, coalesce(generate_series(1,3), 0) FROM int8_tbl;
+                             ^
  -- SRFs are not allowed in aggregate arguments
  SELECT min(generate_series(1, 3)) FROM few;
! ERROR:  aggregate function calls cannot contain set-returning function calls
  LINE 1: SELECT min(generate_series(1, 3)) FROM few;
                     ^
  -- SRFs are not allowed in window function arguments, either
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index 4ed84b1..442d397 100644
*** a/src/test/regress/sql/rangefuncs.sql
--- b/src/test/regress/sql/rangefuncs.sql
*************** select * from foobar();  -- fail
*** 600,614 ****
  
  drop function foobar();
  
- -- check behavior when a function's input sometimes returns a set (bug #8228)
- 
- SELECT *,
-   lower(CASE WHEN id = 2 THEN (regexp_matches(str, '^0*([1-9]\d+)$'))[1]
-         ELSE str
-         END)
- FROM
-   (VALUES (1,''), (2,'0000000049404'), (3,'FROM 10000000876')) v(id, str);
- 
  -- check whole-row-Var handling in nested lateral functions (bug #11703)
  
  create function extractq2(t int8_tbl) returns int8 as $$
--- 600,605 ----
diff --git a/src/test/regress/sql/tsrf.sql b/src/test/regress/sql/tsrf.sql
index 417e78c..45de099 100644
*** a/src/test/regress/sql/tsrf.sql
--- b/src/test/regress/sql/tsrf.sql
*************** SELECT generate_series(1, 2), generate_s
*** 14,19 ****
--- 14,22 ----
  -- srf, with SRF argument
  SELECT generate_series(1, generate_series(1, 3));
  
+ -- but we've traditionally rejected the same in FROM
+ SELECT * FROM generate_series(1, generate_series(1, 3));
+ 
  -- srf, with two SRF arguments
  SELECT generate_series(generate_series(1,3), generate_series(2, 4));
  
*************** SELECT dataa, generate_series(1,1), coun
*** 51,56 ****
--- 54,63 ----
  SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa ORDER BY 2;
  SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest('{1,1,3}'::int[]) ORDER BY 2;
  
+ -- SRFs are not allowed if they'd need to be conditionally executed
+ SELECT q1, case when q1 > 0 then generate_series(1,3) else 0 end FROM int8_tbl;
+ SELECT q1, coalesce(generate_series(1,3), 0) FROM int8_tbl;
+ 
  -- SRFs are not allowed in aggregate arguments
  SELECT min(generate_series(1, 3)) FROM few;
  
