aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c140
-rw-r--r--src/include/nodes/execnodes.h19
2 files changed, 70 insertions, 89 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 7d7c1a1a2a9..27ea91c0140 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -1204,6 +1204,10 @@ init_fcache(Oid foid, FuncExprState *fcache,
fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
fcache->func.fn_expr = (Node *) fcache->xprstate.expr;
+ /* Initialize the function call parameter struct as well */
+ InitFunctionCallInfoData(fcache->fcinfo_data, &(fcache->func),
+ list_length(fcache->args), NULL, NULL);
+
/* If function returns set, prepare expected tuple descriptor */
if (fcache->func.fn_retset && needDescForSets)
{
@@ -1385,7 +1389,7 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
i++;
}
- fcinfo->nargs = i;
+ Assert(i == fcinfo->nargs);
return argIsDone;
}
@@ -1535,7 +1539,6 @@ ExecMakeFunctionResult(FuncExprState *fcache,
{
List *arguments;
Datum result;
- FunctionCallInfoData fcinfo_data;
FunctionCallInfo fcinfo;
PgStat_FunctionCallUsage fcusage;
ReturnSetInfo rsinfo; /* for functions returning sets */
@@ -1587,30 +1590,15 @@ restart:
}
/*
- * For non-set-returning functions, we just use a local-variable
- * FunctionCallInfoData. For set-returning functions we keep the callinfo
- * record in fcache->setArgs so that it can survive across multiple
- * value-per-call invocations. (The reason we don't just do the latter
- * all the time is that plpgsql expects to be able to use simple
- * expression trees re-entrantly. Which might not be a good idea, but the
- * penalty for not doing so is high.)
- */
- if (fcache->func.fn_retset)
- fcinfo = &fcache->setArgs;
- else
- fcinfo = &fcinfo_data;
-
- /*
* arguments is a list of expressions to evaluate before passing to the
* function manager. We skip the evaluation if it was already done in the
* previous call (ie, we are continuing the evaluation of a set-valued
* function). Otherwise, collect the current argument values into fcinfo.
*/
+ fcinfo = &fcache->fcinfo_data;
arguments = fcache->args;
if (!fcache->setArgsValid)
{
- /* Need to prep callinfo structure */
- InitFunctionCallInfoData(*fcinfo, &(fcache->func), 0, NULL, NULL);
argDone = ExecEvalFuncArgs(fcinfo, arguments, econtext);
if (argDone == ExprEndResult)
{
@@ -1726,7 +1714,6 @@ restart:
if (fcache->func.fn_retset &&
*isDone == ExprMultipleResult)
{
- Assert(fcinfo == &fcache->setArgs);
fcache->setHasSetArg = hasSetArg;
fcache->setArgsValid = true;
/* Register cleanup callback if we didn't already */
@@ -1856,7 +1843,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
{
ListCell *arg;
Datum result;
- FunctionCallInfoData fcinfo;
+ FunctionCallInfo fcinfo;
PgStat_FunctionCallUsage fcusage;
int i;
@@ -1867,20 +1854,19 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
*isDone = ExprSingleResult;
/* inlined, simplified version of ExecEvalFuncArgs */
+ fcinfo = &fcache->fcinfo_data;
i = 0;
foreach(arg, fcache->args)
{
ExprState *argstate = (ExprState *) lfirst(arg);
- fcinfo.arg[i] = ExecEvalExpr(argstate,
- econtext,
- &fcinfo.argnull[i],
- NULL);
+ fcinfo->arg[i] = ExecEvalExpr(argstate,
+ econtext,
+ &fcinfo->argnull[i],
+ NULL);
i++;
}
- InitFunctionCallInfoData(fcinfo, &(fcache->func), i, NULL, NULL);
-
/*
* If function is strict, and there are any NULL arguments, skip calling
* the function and return NULL.
@@ -1889,7 +1875,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
{
while (--i >= 0)
{
- if (fcinfo.argnull[i])
+ if (fcinfo->argnull[i])
{
*isNull = true;
return (Datum) 0;
@@ -1897,11 +1883,11 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
}
}
- pgstat_init_function_usage(&fcinfo, &fcusage);
+ pgstat_init_function_usage(fcinfo, &fcusage);
- /* fcinfo.isnull = false; */ /* handled by InitFunctionCallInfoData */
- result = FunctionCallInvoke(&fcinfo);
- *isNull = fcinfo.isnull;
+ fcinfo->isnull = false;
+ result = FunctionCallInvoke(fcinfo);
+ *isNull = fcinfo->isnull;
pgstat_end_function_usage(&fcusage, true);
@@ -1948,7 +1934,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
* resultinfo, but set it up anyway because we use some of the fields as
* our own state variables.
*/
- InitFunctionCallInfoData(fcinfo, NULL, 0, NULL, (Node *) &rsinfo);
rsinfo.type = T_ReturnSetInfo;
rsinfo.econtext = econtext;
rsinfo.expectedDesc = expectedDesc;
@@ -1992,6 +1977,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
econtext->ecxt_per_query_memory, false);
}
returnsSet = fcache->func.fn_retset;
+ InitFunctionCallInfoData(fcinfo, &(fcache->func),
+ list_length(fcache->args),
+ NULL, (Node *) &rsinfo);
/*
* Evaluate the function's argument list.
@@ -2001,7 +1989,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
* inner loop. So do it in caller context. Perhaps we should make a
* separate context just to hold the evaluated arguments?
*/
- fcinfo.flinfo = &(fcache->func);
argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
/* We don't allow sets in the arguments of the table function */
if (argDone != ExprSingleResult)
@@ -2029,6 +2016,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
{
/* Treat funcexpr as a generic expression */
direct_function_call = false;
+ InitFunctionCallInfoData(fcinfo, NULL, 0, NULL, NULL);
}
/*
@@ -2312,9 +2300,8 @@ ExecEvalDistinct(FuncExprState *fcache,
ExprDoneCond *isDone)
{
Datum result;
- FunctionCallInfoData fcinfo;
+ FunctionCallInfo fcinfo;
ExprDoneCond argDone;
- List *argList;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
@@ -2334,34 +2321,31 @@ ExecEvalDistinct(FuncExprState *fcache,
}
/*
- * extract info from fcache
+ * Evaluate arguments
*/
- argList = fcache->args;
-
- /* Need to prep callinfo structure */
- InitFunctionCallInfoData(fcinfo, &(fcache->func), 0, NULL, NULL);
- argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
+ fcinfo = &fcache->fcinfo_data;
+ argDone = ExecEvalFuncArgs(fcinfo, fcache->args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("IS DISTINCT FROM does not support set arguments")));
- Assert(fcinfo.nargs == 2);
+ Assert(fcinfo->nargs == 2);
- if (fcinfo.argnull[0] && fcinfo.argnull[1])
+ if (fcinfo->argnull[0] && fcinfo->argnull[1])
{
/* Both NULL? Then is not distinct... */
result = BoolGetDatum(FALSE);
}
- else if (fcinfo.argnull[0] || fcinfo.argnull[1])
+ else if (fcinfo->argnull[0] || fcinfo->argnull[1])
{
/* Only one is NULL? Then is distinct... */
result = BoolGetDatum(TRUE);
}
else
{
- fcinfo.isnull = false;
- result = FunctionCallInvoke(&fcinfo);
- *isNull = fcinfo.isnull;
+ fcinfo->isnull = false;
+ result = FunctionCallInvoke(fcinfo);
+ *isNull = fcinfo->isnull;
/* Must invert result of "=" */
result = BoolGetDatum(!DatumGetBool(result));
}
@@ -2388,7 +2372,7 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
int nitems;
Datum result;
bool resultnull;
- FunctionCallInfoData fcinfo;
+ FunctionCallInfo fcinfo;
ExprDoneCond argDone;
int i;
int16 typlen;
@@ -2413,26 +2397,28 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
Assert(!sstate->fxprstate.func.fn_retset);
}
- /* Need to prep callinfo structure */
- InitFunctionCallInfoData(fcinfo, &(sstate->fxprstate.func), 0, NULL, NULL);
- argDone = ExecEvalFuncArgs(&fcinfo, sstate->fxprstate.args, econtext);
+ /*
+ * Evaluate arguments
+ */
+ fcinfo = &sstate->fxprstate.fcinfo_data;
+ argDone = ExecEvalFuncArgs(fcinfo, sstate->fxprstate.args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("op ANY/ALL (array) does not support set arguments")));
- Assert(fcinfo.nargs == 2);
+ Assert(fcinfo->nargs == 2);
/*
* If the array is NULL then we return NULL --- it's not very meaningful
* to do anything else, even if the operator isn't strict.
*/
- if (fcinfo.argnull[1])
+ if (fcinfo->argnull[1])
{
*isNull = true;
return (Datum) 0;
}
/* Else okay to fetch and detoast the array */
- arr = DatumGetArrayTypeP(fcinfo.arg[1]);
+ arr = DatumGetArrayTypeP(fcinfo->arg[1]);
/*
* If the array is empty, we return either FALSE or TRUE per the useOr
@@ -2448,7 +2434,7 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
* If the scalar is NULL, and the function is strict, return NULL; no
* point in iterating the loop.
*/
- if (fcinfo.argnull[0] && sstate->fxprstate.func.fn_strict)
+ if (fcinfo->argnull[0] && sstate->fxprstate.func.fn_strict)
{
*isNull = true;
return (Datum) 0;
@@ -2486,32 +2472,32 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
/* Get array element, checking for NULL */
if (bitmap && (*bitmap & bitmask) == 0)
{
- fcinfo.arg[1] = (Datum) 0;
- fcinfo.argnull[1] = true;
+ fcinfo->arg[1] = (Datum) 0;
+ fcinfo->argnull[1] = true;
}
else
{
elt = fetch_att(s, typbyval, typlen);
s = att_addlength_pointer(s, typlen, s);
s = (char *) att_align_nominal(s, typalign);
- fcinfo.arg[1] = elt;
- fcinfo.argnull[1] = false;
+ fcinfo->arg[1] = elt;
+ fcinfo->argnull[1] = false;
}
/* Call comparison function */
- if (fcinfo.argnull[1] && sstate->fxprstate.func.fn_strict)
+ if (fcinfo->argnull[1] && sstate->fxprstate.func.fn_strict)
{
- fcinfo.isnull = true;
+ fcinfo->isnull = true;
thisresult = (Datum) 0;
}
else
{
- fcinfo.isnull = false;
- thisresult = FunctionCallInvoke(&fcinfo);
+ fcinfo->isnull = false;
+ thisresult = FunctionCallInvoke(fcinfo);
}
/* Combine results per OR or AND semantics */
- if (fcinfo.isnull)
+ if (fcinfo->isnull)
resultnull = true;
else if (useOr)
{
@@ -3526,9 +3512,8 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
bool *isNull, ExprDoneCond *isDone)
{
Datum result;
- FunctionCallInfoData fcinfo;
+ FunctionCallInfo fcinfo;
ExprDoneCond argDone;
- List *argList;
if (isDone)
*isDone = ExprSingleResult;
@@ -3546,26 +3531,23 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
}
/*
- * extract info from nullIfExpr
+ * Evaluate arguments
*/
- argList = nullIfExpr->args;
-
- /* Need to prep callinfo structure */
- InitFunctionCallInfoData(fcinfo, &(nullIfExpr->func), 0, NULL, NULL);
- argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
+ fcinfo = &nullIfExpr->fcinfo_data;
+ argDone = ExecEvalFuncArgs(fcinfo, nullIfExpr->args, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("NULLIF does not support set arguments")));
- Assert(fcinfo.nargs == 2);
+ Assert(fcinfo->nargs == 2);
/* if either argument is NULL they can't be equal */
- if (!fcinfo.argnull[0] && !fcinfo.argnull[1])
+ if (!fcinfo->argnull[0] && !fcinfo->argnull[1])
{
- fcinfo.isnull = false;
- result = FunctionCallInvoke(&fcinfo);
+ fcinfo->isnull = false;
+ result = FunctionCallInvoke(fcinfo);
/* if the arguments are equal return null */
- if (!fcinfo.isnull && DatumGetBool(result))
+ if (!fcinfo->isnull && DatumGetBool(result))
{
*isNull = true;
return (Datum) 0;
@@ -3573,8 +3555,8 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
}
/* else return first argument */
- *isNull = fcinfo.argnull[0];
- return fcinfo.arg[0];
+ *isNull = fcinfo->argnull[0];
+ return fcinfo->arg[0];
}
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b78ee35ccf8..89f8e202e35 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -623,13 +623,11 @@ typedef struct FuncExprState
* NULL */
/*
- * We need to store argument values across calls when evaluating a SRF
- * that uses value-per-call mode.
- *
- * setArgsValid is true when we are evaluating a set-valued function and
- * we are in the middle of a call series; we want to pass the same
- * argument values to the function again (and again, until it returns
- * ExprEndResult).
+ * setArgsValid is true when we are evaluating a set-returning function
+ * that uses value-per-call mode and we are in the middle of a call
+ * series; we want to pass the same argument values to the function again
+ * (and again, until it returns ExprEndResult). This indicates that
+ * fcinfo_data already contains valid argument data.
*/
bool setArgsValid;
@@ -649,10 +647,11 @@ typedef struct FuncExprState
bool shutdown_reg; /* a shutdown callback is registered */
/*
- * Current argument data for a set-valued function; contains valid data
- * only if setArgsValid is true.
+ * Call parameter structure for the function. This has been initialized
+ * (by InitFunctionCallInfoData) if func.fn_oid is valid. It also saves
+ * argument values between calls, when setArgsValid is true.
*/
- FunctionCallInfoData setArgs;
+ FunctionCallInfoData fcinfo_data;
} FuncExprState;
/* ----------------