diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 67dca78..6f45973 100644
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
*************** tupledesc_match(TupleDesc dst_tupdesc, T
*** 1634,1642 ****
   * init_fcache is presumed already run on the FuncExprState.
   *
   * This function handles the most general case, wherein the function or
!  * one of its arguments might (or might not) return a set.	If we find
!  * no sets involved, we will change the FuncExprState's function pointer
!  * to use a simpler method on subsequent calls.
   */
  static Datum
  ExecMakeFunctionResult(FuncExprState *fcache,
--- 1634,1640 ----
   * init_fcache is presumed already run on the FuncExprState.
   *
   * This function handles the most general case, wherein the function or
!  * one of its arguments can return a set.
   */
  static Datum
  ExecMakeFunctionResult(FuncExprState *fcache,
*************** restart:
*** 1906,1918 ****
  		/*
  		 * Non-set case: much easier.
  		 *
! 		 * We change the ExprState function pointer to use the simpler
! 		 * ExecMakeFunctionResultNoSets on subsequent calls.  This amounts to
! 		 * assuming that no argument can return a set if it didn't do so the
! 		 * first time.
  		 */
- 		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
- 
  		if (isDone)
  			*isDone = ExprSingleResult;
  
--- 1904,1915 ----
  		/*
  		 * 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;
  
*************** ExecEvalFunc(FuncExprState *fcache,
*** 2371,2380 ****
  	init_fcache(func->funcid, func->inputcollid, fcache,
  				econtext->ecxt_per_query_memory, true);
  
! 	/* Go directly to ExecMakeFunctionResult on subsequent uses */
! 	fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
! 
! 	return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
  }
  
  /* ----------------------------------------------------------------
--- 2368,2389 ----
  	init_fcache(func->funcid, func->inputcollid, fcache,
  				econtext->ecxt_per_query_memory, true);
  
! 	/*
! 	 * We need to invoke ExecMakeFunctionResult if either the function itself
! 	 * or any of its input expressions can return a set.  Otherwise, invoke
! 	 * ExecMakeFunctionResultNoSets.  In either case, change the evalfunc
! 	 * pointer to go directly there on subsequent uses.
! 	 */
! 	if (fcache->func.fn_retset || expression_returns_set((Node *) func->args))
! 	{
! 		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
! 		return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
! 	}
! 	else
! 	{
! 		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
! 		return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone);
! 	}
  }
  
  /* ----------------------------------------------------------------
*************** ExecEvalOper(FuncExprState *fcache,
*** 2394,2403 ****
  	init_fcache(op->opfuncid, op->inputcollid, fcache,
  				econtext->ecxt_per_query_memory, true);
  
! 	/* Go directly to ExecMakeFunctionResult on subsequent uses */
! 	fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
! 
! 	return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
  }
  
  /* ----------------------------------------------------------------
--- 2403,2424 ----
  	init_fcache(op->opfuncid, op->inputcollid, fcache,
  				econtext->ecxt_per_query_memory, true);
  
! 	/*
! 	 * We need to invoke ExecMakeFunctionResult if either the function itself
! 	 * or any of its input expressions can return a set.  Otherwise, invoke
! 	 * ExecMakeFunctionResultNoSets.  In either case, change the evalfunc
! 	 * pointer to go directly there on subsequent uses.
! 	 */
! 	if (fcache->func.fn_retset || expression_returns_set((Node *) op->args))
! 	{
! 		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
! 		return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
! 	}
! 	else
! 	{
! 		fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
! 		return ExecMakeFunctionResultNoSets(fcache, econtext, isNull, isDone);
! 	}
  }
  
  /* ----------------------------------------------------------------
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index a988dd0..9d40510 100644
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** select * from foobar();  -- fail
*** 1992,1994 ****
--- 1992,2008 ----
  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       
+ ----+------------------+------------------
+   1 |                  | 
+   2 | 0000000049404    | 49404
+   3 | FROM 10000000876 | from 10000000876
+ (3 rows)
+ 
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index ac2769f..07d2e1a 100644
*** a/src/test/regress/sql/rangefuncs.sql
--- b/src/test/regress/sql/rangefuncs.sql
*************** $$ select (1, 2.1, 3) $$ language sql;
*** 599,601 ****
--- 599,610 ----
  select * from foobar();  -- fail
  
  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);
