From: Tom Lane Date: Mon, 20 Apr 2026 14:21:52 +0000 (-0400) Subject: Make ExecForPortionOfLeftovers() obey SRF protocol. X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=207cb2abcba00f78d57cdaca896f41c9453b0f2f;p=thirdparty%2Fpostgresql.git Make ExecForPortionOfLeftovers() obey SRF protocol. Before each call to the SRF, initialize isnull and isDone, as per the comments for struct ReturnSetInfo. This fixes a Coverity warning about rsi.isDone not being initialized. The built-in {multi,}range_minus_multi functions don't return without setting it, but a user-supplied function might not be as accommodating. We also add statistics tracking around the function call, which will be expected once user-defined withoutPortionProcs functions are supported, and a cross-check on rsi.returnMode just for paranoia's sake. Author: Tom Lane Co-authored-by: Paul A Jungwirth Discussion: https://postgr.es/m/4126231.1776622202@sss.pgh.pa.us --- diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index ef2a6bc6e9d..e8a044f56c6 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -65,6 +65,7 @@ #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" +#include "pgstat.h" #include "rewrite/rewriteHandler.h" #include "rewrite/rewriteManip.h" #include "storage/lmgr.h" @@ -1419,6 +1420,7 @@ ExecForPortionOfLeftovers(ModifyTableContext *context, CmdType oldOperation; TransitionCaptureState *oldTcs; FmgrInfo flinfo; + PgStat_FunctionCallUsage fcusage; ReturnSetInfo rsi; bool didInit = false; bool shouldFree = false; @@ -1514,6 +1516,7 @@ ExecForPortionOfLeftovers(ModifyTableContext *context, rsi.expectedDesc = NULL; rsi.allowedModes = (int) (SFRM_ValuePerCall); rsi.returnMode = SFRM_ValuePerCall; + /* isDone is filled below */ rsi.setResult = NULL; rsi.setDesc = NULL; @@ -1537,14 +1540,27 @@ ExecForPortionOfLeftovers(ModifyTableContext *context, */ while (true) { - Datum leftover = FunctionCallInvoke(fcinfo); + Datum leftover; + + /* Call the function one time */ + pgstat_init_function_usage(fcinfo, &fcusage); + + fcinfo->isnull = false; + rsi.isDone = ExprSingleResult; + leftover = FunctionCallInvoke(fcinfo); + + pgstat_end_function_usage(&fcusage, + rsi.isDone != ExprMultipleResult); + + if (rsi.returnMode != SFRM_ValuePerCall) + elog(ERROR, "without_portion function violated function call protocol"); /* Are we done? */ if (rsi.isDone == ExprEndResult) break; if (fcinfo->isnull) - elog(ERROR, "Got a null from without_portion function"); + elog(ERROR, "got a null from without_portion function"); /* * Does the new Datum violate domain checks? Row-level CHECK