@@ -1631,9 +1631,7 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
1631
1631
* init_fcache is presumed already run on the FuncExprState.
1632
1632
*
1633
1633
* This function handles the most general case, wherein the function or
1634
- * one of its arguments might (or might not) return a set. If we find
1635
- * no sets involved, we will change the FuncExprState's function pointer
1636
- * to use a simpler method on subsequent calls.
1634
+ * one of its arguments can return a set.
1637
1635
*/
1638
1636
static Datum
1639
1637
ExecMakeFunctionResult (FuncExprState * fcache ,
@@ -1895,13 +1893,12 @@ ExecMakeFunctionResult(FuncExprState *fcache,
1895
1893
/*
1896
1894
* Non-set case: much easier.
1897
1895
*
1898
- * We change the ExprState function pointer to use the simpler
1899
- * ExecMakeFunctionResultNoSets on subsequent calls. This amounts to
1900
- * assuming that no argument can return a set if it didn't do so the
1901
- * first time.
1896
+ * In common cases, this code path is unreachable because we'd have
1897
+ * selected ExecMakeFunctionResultNoSets instead. However, it's
1898
+ * possible to get here if an argument sometimes produces set results
1899
+ * and sometimes scalar results. For example, a CASE expression might
1900
+ * call a set-returning function in only some of its arms.
1902
1901
*/
1903
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
1904
-
1905
1902
if (isDone )
1906
1903
* isDone = ExprSingleResult ;
1907
1904
@@ -2360,10 +2357,22 @@ ExecEvalFunc(FuncExprState *fcache,
2360
2357
init_fcache (func -> funcid , func -> inputcollid , fcache ,
2361
2358
econtext -> ecxt_per_query_memory , true);
2362
2359
2363
- /* Go directly to ExecMakeFunctionResult on subsequent uses */
2364
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2365
-
2366
- return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2360
+ /*
2361
+ * We need to invoke ExecMakeFunctionResult if either the function itself
2362
+ * or any of its input expressions can return a set. Otherwise, invoke
2363
+ * ExecMakeFunctionResultNoSets. In either case, change the evalfunc
2364
+ * pointer to go directly there on subsequent uses.
2365
+ */
2366
+ if (fcache -> func .fn_retset || expression_returns_set ((Node * ) func -> args ))
2367
+ {
2368
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2369
+ return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2370
+ }
2371
+ else
2372
+ {
2373
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
2374
+ return ExecMakeFunctionResultNoSets (fcache , econtext , isNull , isDone );
2375
+ }
2367
2376
}
2368
2377
2369
2378
/* ----------------------------------------------------------------
@@ -2383,10 +2392,22 @@ ExecEvalOper(FuncExprState *fcache,
2383
2392
init_fcache (op -> opfuncid , op -> inputcollid , fcache ,
2384
2393
econtext -> ecxt_per_query_memory , true);
2385
2394
2386
- /* Go directly to ExecMakeFunctionResult on subsequent uses */
2387
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2388
-
2389
- return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2395
+ /*
2396
+ * We need to invoke ExecMakeFunctionResult if either the function itself
2397
+ * or any of its input expressions can return a set. Otherwise, invoke
2398
+ * ExecMakeFunctionResultNoSets. In either case, change the evalfunc
2399
+ * pointer to go directly there on subsequent uses.
2400
+ */
2401
+ if (fcache -> func .fn_retset || expression_returns_set ((Node * ) op -> args ))
2402
+ {
2403
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2404
+ return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2405
+ }
2406
+ else
2407
+ {
2408
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
2409
+ return ExecMakeFunctionResultNoSets (fcache , econtext , isNull , isDone );
2410
+ }
2390
2411
}
2391
2412
2392
2413
/* ----------------------------------------------------------------
0 commit comments