@@ -1621,9 +1621,7 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
1621
1621
* init_fcache is presumed already run on the FuncExprState.
1622
1622
*
1623
1623
* This function handles the most general case, wherein the function or
1624
- * one of its arguments might (or might not) return a set. If we find
1625
- * no sets involved, we will change the FuncExprState's function pointer
1626
- * to use a simpler method on subsequent calls.
1624
+ * one of its arguments can return a set.
1627
1625
*/
1628
1626
static Datum
1629
1627
ExecMakeFunctionResult (FuncExprState * fcache ,
@@ -1885,13 +1883,12 @@ ExecMakeFunctionResult(FuncExprState *fcache,
1885
1883
/*
1886
1884
* Non-set case: much easier.
1887
1885
*
1888
- * We change the ExprState function pointer to use the simpler
1889
- * ExecMakeFunctionResultNoSets on subsequent calls. This amounts to
1890
- * assuming that no argument can return a set if it didn't do so the
1891
- * first time.
1886
+ * In common cases, this code path is unreachable because we'd have
1887
+ * selected ExecMakeFunctionResultNoSets instead. However, it's
1888
+ * possible to get here if an argument sometimes produces set results
1889
+ * and sometimes scalar results. For example, a CASE expression might
1890
+ * call a set-returning function in only some of its arms.
1892
1891
*/
1893
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
1894
-
1895
1892
if (isDone )
1896
1893
* isDone = ExprSingleResult ;
1897
1894
@@ -2350,10 +2347,22 @@ ExecEvalFunc(FuncExprState *fcache,
2350
2347
init_fcache (func -> funcid , func -> inputcollid , fcache ,
2351
2348
econtext -> ecxt_per_query_memory , true);
2352
2349
2353
- /* Go directly to ExecMakeFunctionResult on subsequent uses */
2354
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2355
-
2356
- return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2350
+ /*
2351
+ * We need to invoke ExecMakeFunctionResult if either the function itself
2352
+ * or any of its input expressions can return a set. Otherwise, invoke
2353
+ * ExecMakeFunctionResultNoSets. In either case, change the evalfunc
2354
+ * pointer to go directly there on subsequent uses.
2355
+ */
2356
+ if (fcache -> func .fn_retset || expression_returns_set ((Node * ) func -> args ))
2357
+ {
2358
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2359
+ return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2360
+ }
2361
+ else
2362
+ {
2363
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
2364
+ return ExecMakeFunctionResultNoSets (fcache , econtext , isNull , isDone );
2365
+ }
2357
2366
}
2358
2367
2359
2368
/* ----------------------------------------------------------------
@@ -2373,10 +2382,22 @@ ExecEvalOper(FuncExprState *fcache,
2373
2382
init_fcache (op -> opfuncid , op -> inputcollid , fcache ,
2374
2383
econtext -> ecxt_per_query_memory , true);
2375
2384
2376
- /* Go directly to ExecMakeFunctionResult on subsequent uses */
2377
- fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2378
-
2379
- return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2385
+ /*
2386
+ * We need to invoke ExecMakeFunctionResult if either the function itself
2387
+ * or any of its input expressions can return a set. Otherwise, invoke
2388
+ * ExecMakeFunctionResultNoSets. In either case, change the evalfunc
2389
+ * pointer to go directly there on subsequent uses.
2390
+ */
2391
+ if (fcache -> func .fn_retset || expression_returns_set ((Node * ) op -> args ))
2392
+ {
2393
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResult ;
2394
+ return ExecMakeFunctionResult (fcache , econtext , isNull , isDone );
2395
+ }
2396
+ else
2397
+ {
2398
+ fcache -> xprstate .evalfunc = (ExprStateEvalFunc ) ExecMakeFunctionResultNoSets ;
2399
+ return ExecMakeFunctionResultNoSets (fcache , econtext , isNull , isDone );
2400
+ }
2380
2401
}
2381
2402
2382
2403
/* ----------------------------------------------------------------
0 commit comments