Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6719b23

Browse files
committed
Rearrange execution of PARAM_EXTERN Params for plpgsql's benefit.
This patch does three interrelated things: * Create a new expression execution step type EEOP_PARAM_CALLBACK and add the infrastructure needed for add-on modules to generate that. As discussed, the best control mechanism for that seems to be to add another hook function to ParamListInfo, which will be called by ExecInitExpr if it's supplied and a PARAM_EXTERN Param is found. For stand-alone expressions, we add a new entry point to allow the ParamListInfo to be specified directly, since it can't be retrieved from the parent plan node's EState. * Redesign the API for the ParamListInfo paramFetch hook so that the ParamExternData array can be entirely virtual. This also lets us get rid of ParamListInfo.paramMask, instead leaving it to the paramFetch hook to decide which param IDs should be accessible or not. plpgsql_param_fetch was already doing the identical masking check, so having callers do it too seemed redundant. While I was at it, I added a "speculative" flag to paramFetch that the planner can specify as TRUE to avoid unwanted failures. This solves an ancient problem for plpgsql that it couldn't provide values of non-DTYPE_VAR variables to the planner for fear of triggering premature "record not assigned yet" or "field not found" errors during planning. * Rework plpgsql to get rid of the need for "unshared" parameter lists, by dint of turning the single ParamListInfo per estate into a nearly read-only data structure that doesn't instantiate any per-variable data. Instead, the paramFetch hook controls access to per-variable data and can make the right decisions on the fly, replacing the cases that we used to need multiple ParamListInfos for. This might perhaps have been a performance loss on its own, but by using a paramCompile hook we can bypass plpgsql_param_fetch entirely during normal query execution. (It's now only called when, eg, we copy the ParamListInfo into a cursor portal. copyParamList() or SerializeParamList() effectively instantiate the virtual parameter array as a simple physical array without a paramFetch hook, which is what we want in those cases.) This allows reverting most of commit 6c82d8d, though I kept the cosmetic code-consolidation aspects of that (eg the assign_simple_var function). Performance testing shows this to be at worst a break-even change, and it can provide wins ranging up to 20% in test cases involving accesses to fields of "record" variables. The fact that values of such variables can now be exposed to the planner might produce wins in some situations, too, but I've not pursued that angle. In passing, remove the "parent" pointer from the arguments to ExecInitExprRec and related functions, instead storing that pointer in a transient field in ExprState. The ParamListInfo pointer for a stand-alone expression is handled the same way; we'd otherwise have had to add yet another recursively-passed-down argument in expression compilation. Discussion: https://postgr.es/m/32589.1513706441@sss.pgh.pa.us
1 parent 8a0596c commit 6719b23

File tree

16 files changed

+613
-406
lines changed

16 files changed

+613
-406
lines changed

src/backend/commands/prepare.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,11 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
399399
/* we have static list of params, so no hooks needed */
400400
paramLI->paramFetch = NULL;
401401
paramLI->paramFetchArg = NULL;
402+
paramLI->paramCompile = NULL;
403+
paramLI->paramCompileArg = NULL;
402404
paramLI->parserSetup = NULL;
403405
paramLI->parserSetupArg = NULL;
404406
paramLI->numParams = num_params;
405-
paramLI->paramMask = NULL;
406407

407408
i = 0;
408409
foreach(l, exprstates)

src/backend/executor/execCurrent.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,14 @@ fetch_cursor_param_value(ExprContext *econtext, int paramId)
216216
if (paramInfo &&
217217
paramId > 0 && paramId <= paramInfo->numParams)
218218
{
219-
ParamExternData *prm = &paramInfo->params[paramId - 1];
219+
ParamExternData *prm;
220+
ParamExternData prmdata;
220221

221222
/* give hook a chance in case parameter is dynamic */
222-
if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL)
223-
paramInfo->paramFetch(paramInfo, paramId);
223+
if (paramInfo->paramFetch != NULL)
224+
prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
225+
else
226+
prm = &paramInfo->params[paramId - 1];
224227

225228
if (OidIsValid(prm->ptype) && !prm->isnull)
226229
{

0 commit comments

Comments
 (0)