postgres.git / summary / log / commit / refs

commit    207cb2abcba00f78d57cdaca896f41c9453b0f2f
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Mon Apr 20 14:21:52 2026 +0000

    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 <tgl@sss.pgh.pa.us>
    Co-authored-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
    Discussion: https://postgr.es/m/4126231.1776622202@sss.pgh.pa.us


src/backend/executor/nodeModifyTable.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) 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 [parent: 5dbb63fc82b7]