mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Change function call information to be variable length.
Before this change FunctionCallInfoData, the struct arguments etc for V1 function calls are stored in, always had space for FUNC_MAX_ARGS/100 arguments, storing datums and their nullness in two arrays. For nearly every function call 100 arguments is far more than needed, therefore wasting memory. Arg and argnull being two separate arrays also guarantees that to access a single argument, two cachelines have to be touched. Change the layout so there's a single variable-length array with pairs of value / isnull. That drastically reduces memory consumption for most function calls (on x86-64 a two argument function now uses 64bytes, previously 936 bytes), and makes it very likely that argument value and its nullness are on the same cacheline. Arguments are stored in a new NullableDatum struct, which, due to padding, needs more memory per argument than before. But as usually far fewer arguments are stored, and individual arguments are cheaper to access, that's still a clear win. It's likely that there's other places where conversion to NullableDatum arrays would make sense, e.g. TupleTableSlots, but that's for another commit. Because the function call information is now variable-length allocations have to take the number of arguments into account. For heap allocations that can be done with SizeForFunctionCallInfoData(), for on-stack allocations there's a new LOCAL_FCINFO(name, nargs) macro that helps to allocate an appropriately sized and aligned variable. Some places with stack allocation function call information don't know the number of arguments at compile time, and currently variably sized stack allocations aren't allowed in postgres. Therefore allow for FUNC_MAX_ARGS space in these cases. They're not that common, so for now that seems acceptable. Because of the need to allocate FunctionCallInfo of the appropriate size, older extensions may need to update their code. To avoid subtle breakages, the FunctionCallInfoData struct has been renamed to FunctionCallInfoBaseData. Most code only references FunctionCallInfo, so that shouldn't cause much collateral damage. This change is also a prerequisite for more efficient expression JIT compilation (by allocating the function call information on the stack, allowing LLVM to optimize it away); previously the size of the call information caused problems inside LLVM's optimizer. Author: Andres Freund Reviewed-By: Tom Lane Discussion: https://postgr.es/m/20180605172952.x34m5uz6ju6enaem@alap3.anarazel.de
This commit is contained in:
parent
6d3ede5f1c
commit
a9c35cf85c
@ -854,7 +854,7 @@ hstore_to_matrix(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
setup_firstcall(FuncCallContext *funcctx, HStore *hs,
|
setup_firstcall(FuncCallContext *funcctx, HStore *hs,
|
||||||
FunctionCallInfoData *fcinfo)
|
FunctionCallInfo fcinfo)
|
||||||
{
|
{
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
HStore *st;
|
HStore *st;
|
||||||
|
@ -34,15 +34,15 @@
|
|||||||
<para>
|
<para>
|
||||||
The call handler is called in the same way as any other function:
|
The call handler is called in the same way as any other function:
|
||||||
It receives a pointer to a
|
It receives a pointer to a
|
||||||
<structname>FunctionCallInfoData</structname> <type>struct</type> containing
|
<structname>FunctionCallInfoBaseData</structname> <type>struct</type> containing
|
||||||
argument values and information about the called function, and it
|
argument values and information about the called function, and it
|
||||||
is expected to return a <type>Datum</type> result (and possibly
|
is expected to return a <type>Datum</type> result (and possibly
|
||||||
set the <structfield>isnull</structfield> field of the
|
set the <structfield>isnull</structfield> field of the
|
||||||
<structname>FunctionCallInfoData</structname> structure, if it wishes
|
<structname>FunctionCallInfoBaseData</structname> structure, if it wishes
|
||||||
to return an SQL null result). The difference between a call
|
to return an SQL null result). The difference between a call
|
||||||
handler and an ordinary callee function is that the
|
handler and an ordinary callee function is that the
|
||||||
<structfield>flinfo->fn_oid</structfield> field of the
|
<structfield>flinfo->fn_oid</structfield> field of the
|
||||||
<structname>FunctionCallInfoData</structname> structure will contain
|
<structname>FunctionCallInfoBaseData</structname> structure will contain
|
||||||
the OID of the actual function to be called, not of the call
|
the OID of the actual function to be called, not of the call
|
||||||
handler itself. The call handler must use this field to determine
|
handler itself. The call handler must use this field to determine
|
||||||
which function to execute. Also, the passed argument list has
|
which function to execute. Also, the passed argument list has
|
||||||
@ -87,7 +87,7 @@
|
|||||||
<para>
|
<para>
|
||||||
When a procedural-language function is invoked as a trigger, no arguments
|
When a procedural-language function is invoked as a trigger, no arguments
|
||||||
are passed in the usual way, but the
|
are passed in the usual way, but the
|
||||||
<structname>FunctionCallInfoData</structname>'s
|
<structname>FunctionCallInfoBaseData</structname>'s
|
||||||
<structfield>context</structfield> field points at a
|
<structfield>context</structfield> field points at a
|
||||||
<structname>TriggerData</structname> structure, rather than being <symbol>NULL</symbol>
|
<structname>TriggerData</structname> structure, rather than being <symbol>NULL</symbol>
|
||||||
as it is in a plain function call. A language handler should
|
as it is in a plain function call. A language handler should
|
||||||
|
@ -1055,9 +1055,9 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|||||||
/* Call each event trigger. */
|
/* Call each event trigger. */
|
||||||
foreach(lc, fn_oid_list)
|
foreach(lc, fn_oid_list)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
Oid fnoid = lfirst_oid(lc);
|
Oid fnoid = lfirst_oid(lc);
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
|
|
||||||
elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
|
elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
|
||||||
@ -1077,10 +1077,10 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|||||||
fmgr_info(fnoid, &flinfo);
|
fmgr_info(fnoid, &flinfo);
|
||||||
|
|
||||||
/* Call the function, passing no arguments but setting a context. */
|
/* Call the function, passing no arguments but setting a context. */
|
||||||
InitFunctionCallInfoData(fcinfo, &flinfo, 0,
|
InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
|
||||||
InvalidOid, (Node *) trigdata, NULL);
|
InvalidOid, (Node *) trigdata, NULL);
|
||||||
pgstat_init_function_usage(&fcinfo, &fcusage);
|
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||||
FunctionCallInvoke(&fcinfo);
|
FunctionCallInvoke(fcinfo);
|
||||||
pgstat_end_function_usage(&fcusage, true);
|
pgstat_end_function_usage(&fcusage, true);
|
||||||
|
|
||||||
/* Reclaim memory. */
|
/* Reclaim memory. */
|
||||||
|
@ -2216,13 +2216,13 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
|
|||||||
void
|
void
|
||||||
ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
|
ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
FuncExpr *fexpr;
|
FuncExpr *fexpr;
|
||||||
int nargs;
|
int nargs;
|
||||||
int i;
|
int i;
|
||||||
AclResult aclresult;
|
AclResult aclresult;
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
CallContext *callcontext;
|
CallContext *callcontext;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
@ -2297,7 +2297,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
|
|||||||
InvokeFunctionExecuteHook(fexpr->funcid);
|
InvokeFunctionExecuteHook(fexpr->funcid);
|
||||||
fmgr_info(fexpr->funcid, &flinfo);
|
fmgr_info(fexpr->funcid, &flinfo);
|
||||||
fmgr_info_set_expr((Node *) fexpr, &flinfo);
|
fmgr_info_set_expr((Node *) fexpr, &flinfo);
|
||||||
InitFunctionCallInfoData(fcinfo, &flinfo, nargs, fexpr->inputcollid, (Node *) callcontext, NULL);
|
InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
|
||||||
|
(Node *) callcontext, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate procedure arguments inside a suitable execution context. Note
|
* Evaluate procedure arguments inside a suitable execution context. Note
|
||||||
@ -2318,14 +2319,14 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
|
|||||||
|
|
||||||
val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
|
val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
|
||||||
|
|
||||||
fcinfo.arg[i] = val;
|
fcinfo->args[i].value = val;
|
||||||
fcinfo.argnull[i] = isnull;
|
fcinfo->args[i].isnull = isnull;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pgstat_init_function_usage(&fcinfo, &fcusage);
|
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||||
retval = FunctionCallInvoke(&fcinfo);
|
retval = FunctionCallInvoke(fcinfo);
|
||||||
pgstat_end_function_usage(&fcusage, true);
|
pgstat_end_function_usage(&fcusage, true);
|
||||||
|
|
||||||
if (fexpr->funcresulttype == VOIDOID)
|
if (fexpr->funcresulttype == VOIDOID)
|
||||||
@ -2346,7 +2347,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
|
|||||||
TupOutputState *tstate;
|
TupOutputState *tstate;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
if (fcinfo.isnull)
|
if (fcinfo->isnull)
|
||||||
elog(ERROR, "procedure returned null record");
|
elog(ERROR, "procedure returned null record");
|
||||||
|
|
||||||
td = DatumGetHeapTupleHeader(retval);
|
td = DatumGetHeapTupleHeader(retval);
|
||||||
|
@ -8879,7 +8879,7 @@ validateForeignKeyConstraint(char *conname,
|
|||||||
|
|
||||||
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
TriggerData trigdata;
|
TriggerData trigdata;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -8887,7 +8887,7 @@ validateForeignKeyConstraint(char *conname,
|
|||||||
*
|
*
|
||||||
* No parameters are passed, but we do set a context
|
* No parameters are passed, but we do set a context
|
||||||
*/
|
*/
|
||||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume RI_FKey_check_ins won't look at flinfo...
|
* We assume RI_FKey_check_ins won't look at flinfo...
|
||||||
@ -8901,9 +8901,9 @@ validateForeignKeyConstraint(char *conname,
|
|||||||
trigdata.tg_trigtuplebuf = scan->rs_cbuf;
|
trigdata.tg_trigtuplebuf = scan->rs_cbuf;
|
||||||
trigdata.tg_newtuplebuf = InvalidBuffer;
|
trigdata.tg_newtuplebuf = InvalidBuffer;
|
||||||
|
|
||||||
fcinfo.context = (Node *) &trigdata;
|
fcinfo->context = (Node *) &trigdata;
|
||||||
|
|
||||||
RI_FKey_check_ins(&fcinfo);
|
RI_FKey_check_ins(fcinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
|
@ -2357,7 +2357,7 @@ ExecCallTriggerFunc(TriggerData *trigdata,
|
|||||||
Instrumentation *instr,
|
Instrumentation *instr,
|
||||||
MemoryContext per_tuple_context)
|
MemoryContext per_tuple_context)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
Datum result;
|
Datum result;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
@ -2402,15 +2402,15 @@ ExecCallTriggerFunc(TriggerData *trigdata,
|
|||||||
/*
|
/*
|
||||||
* Call the function, passing no arguments but setting a context.
|
* Call the function, passing no arguments but setting a context.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(fcinfo, finfo, 0,
|
InitFunctionCallInfoData(*fcinfo, finfo, 0,
|
||||||
InvalidOid, (Node *) trigdata, NULL);
|
InvalidOid, (Node *) trigdata, NULL);
|
||||||
|
|
||||||
pgstat_init_function_usage(&fcinfo, &fcusage);
|
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||||
|
|
||||||
MyTriggerDepth++;
|
MyTriggerDepth++;
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
result = FunctionCallInvoke(&fcinfo);
|
result = FunctionCallInvoke(fcinfo);
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
@ -2428,11 +2428,11 @@ ExecCallTriggerFunc(TriggerData *trigdata,
|
|||||||
* Trigger protocol allows function to return a null pointer, but NOT to
|
* Trigger protocol allows function to return a null pointer, but NOT to
|
||||||
* set the isnull result flag.
|
* set the isnull result flag.
|
||||||
*/
|
*/
|
||||||
if (fcinfo.isnull)
|
if (fcinfo->isnull)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
||||||
errmsg("trigger function %u returned null value",
|
errmsg("trigger function %u returned null value",
|
||||||
fcinfo.flinfo->fn_oid)));
|
fcinfo->flinfo->fn_oid)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
|
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
|
||||||
|
@ -124,7 +124,7 @@ For example, "a + b" (one OpExpr, with two Var expressions) would be
|
|||||||
represented as two steps to fetch the Var values, and one step for the
|
represented as two steps to fetch the Var values, and one step for the
|
||||||
evaluation of the function underlying the + operator. The steps for the
|
evaluation of the function underlying the + operator. The steps for the
|
||||||
Vars would have their resvalue/resnull pointing directly to the appropriate
|
Vars would have their resvalue/resnull pointing directly to the appropriate
|
||||||
arg[] and argnull[] array elements in the FunctionCallInfoData struct that
|
args[].value .isnull elements in the FunctionCallInfoBaseData struct that
|
||||||
is used by the function evaluation step, thus avoiding extra work to copy
|
is used by the function evaluation step, thus avoiding extra work to copy
|
||||||
the result values around.
|
the result values around.
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ sub-expressions.
|
|||||||
Each ExecInitExprRec() call has to specify where that subexpression's
|
Each ExecInitExprRec() call has to specify where that subexpression's
|
||||||
results are to be stored (via the resv/resnull parameters). This allows
|
results are to be stored (via the resv/resnull parameters). This allows
|
||||||
the above scenario of evaluating a (sub-)expression directly into
|
the above scenario of evaluating a (sub-)expression directly into
|
||||||
fcinfo->arg/argnull, but also requires some care: target Datum/isnull
|
fcinfo->args[].value/isnull, but also requires some care: target Datum/isnull
|
||||||
variables may not be shared with another ExecInitExprRec() unless the
|
variables may not be shared with another ExecInitExprRec() unless the
|
||||||
results are only needed by steps executing before further usages of those
|
results are only needed by steps executing before further usages of those
|
||||||
target Datum/isnull variables. Due to the non-recursiveness of the
|
target Datum/isnull variables. Due to the non-recursiveness of the
|
||||||
@ -158,7 +158,7 @@ not enough space. Because of that it is *not* allowed to point directly
|
|||||||
into any of the steps during expression initialization. Therefore, the
|
into any of the steps during expression initialization. Therefore, the
|
||||||
resv/resnull for a subexpression usually point to some storage that is
|
resv/resnull for a subexpression usually point to some storage that is
|
||||||
palloc'd separately from the steps array. For instance, the
|
palloc'd separately from the steps array. For instance, the
|
||||||
FunctionCallInfoData for a function call step is separately allocated
|
FunctionCallInfoBaseData for a function call step is separately allocated
|
||||||
rather than being part of the ExprEvalStep array. The overall result
|
rather than being part of the ExprEvalStep array. The overall result
|
||||||
of a complete expression is typically returned into the resvalue/resnull
|
of a complete expression is typically returned into the resvalue/resnull
|
||||||
fields of the ExprState node itself.
|
fields of the ExprState node itself.
|
||||||
|
@ -966,7 +966,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* Set up the primary fmgr lookup information */
|
/* Set up the primary fmgr lookup information */
|
||||||
finfo = palloc0(sizeof(FmgrInfo));
|
finfo = palloc0(sizeof(FmgrInfo));
|
||||||
fcinfo = palloc0(sizeof(FunctionCallInfoData));
|
fcinfo = palloc0(SizeForFunctionCallInfo(2));
|
||||||
fmgr_info(opexpr->opfuncid, finfo);
|
fmgr_info(opexpr->opfuncid, finfo);
|
||||||
fmgr_info_set_expr((Node *) node, finfo);
|
fmgr_info_set_expr((Node *) node, finfo);
|
||||||
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
||||||
@ -974,7 +974,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* Evaluate scalar directly into left function argument */
|
/* Evaluate scalar directly into left function argument */
|
||||||
ExecInitExprRec(scalararg, state,
|
ExecInitExprRec(scalararg, state,
|
||||||
&fcinfo->arg[0], &fcinfo->argnull[0]);
|
&fcinfo->args[0].value, &fcinfo->args[0].isnull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate array argument into our return value. There's no
|
* Evaluate array argument into our return value. There's no
|
||||||
@ -1263,7 +1263,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* lookup the source type's output function */
|
/* lookup the source type's output function */
|
||||||
scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
|
scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
|
||||||
scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData));
|
scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1));
|
||||||
|
|
||||||
getTypeOutputInfo(exprType((Node *) iocoerce->arg),
|
getTypeOutputInfo(exprType((Node *) iocoerce->arg),
|
||||||
&iofunc, &typisvarlena);
|
&iofunc, &typisvarlena);
|
||||||
@ -1275,7 +1275,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* lookup the result type's input function */
|
/* lookup the result type's input function */
|
||||||
scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
|
scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
|
||||||
scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData));
|
scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3));
|
||||||
|
|
||||||
getTypeInputInfo(iocoerce->resulttype,
|
getTypeInputInfo(iocoerce->resulttype,
|
||||||
&iofunc, &typioparam);
|
&iofunc, &typioparam);
|
||||||
@ -1290,10 +1290,10 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
* function, since they're constants.
|
* function, since they're constants.
|
||||||
*/
|
*/
|
||||||
fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
|
fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
|
||||||
fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam);
|
fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
|
||||||
fcinfo_in->argnull[1] = false;
|
fcinfo_in->args[1].isnull = false;
|
||||||
fcinfo_in->arg[2] = Int32GetDatum(-1);
|
fcinfo_in->args[2].value = Int32GetDatum(-1);
|
||||||
fcinfo_in->argnull[2] = false;
|
fcinfo_in->args[2].isnull = false;
|
||||||
|
|
||||||
ExprEvalPushStep(state, &scratch);
|
ExprEvalPushStep(state, &scratch);
|
||||||
break;
|
break;
|
||||||
@ -1735,7 +1735,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* Set up the primary fmgr lookup information */
|
/* Set up the primary fmgr lookup information */
|
||||||
finfo = palloc0(sizeof(FmgrInfo));
|
finfo = palloc0(sizeof(FmgrInfo));
|
||||||
fcinfo = palloc0(sizeof(FunctionCallInfoData));
|
fcinfo = palloc0(SizeForFunctionCallInfo(2));
|
||||||
fmgr_info(proc, finfo);
|
fmgr_info(proc, finfo);
|
||||||
fmgr_info_set_expr((Node *) node, finfo);
|
fmgr_info_set_expr((Node *) node, finfo);
|
||||||
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
||||||
@ -1750,9 +1750,9 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* evaluate left and right args directly into fcinfo */
|
/* evaluate left and right args directly into fcinfo */
|
||||||
ExecInitExprRec(left_expr, state,
|
ExecInitExprRec(left_expr, state,
|
||||||
&fcinfo->arg[0], &fcinfo->argnull[0]);
|
&fcinfo->args[0].value, &fcinfo->args[0].isnull);
|
||||||
ExecInitExprRec(right_expr, state,
|
ExecInitExprRec(right_expr, state,
|
||||||
&fcinfo->arg[1], &fcinfo->argnull[1]);
|
&fcinfo->args[1].value, &fcinfo->args[1].isnull);
|
||||||
|
|
||||||
scratch.opcode = EEOP_ROWCOMPARE_STEP;
|
scratch.opcode = EEOP_ROWCOMPARE_STEP;
|
||||||
scratch.d.rowcompare_step.finfo = finfo;
|
scratch.d.rowcompare_step.finfo = finfo;
|
||||||
@ -1878,7 +1878,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
|
|
||||||
/* Perform function lookup */
|
/* Perform function lookup */
|
||||||
finfo = palloc0(sizeof(FmgrInfo));
|
finfo = palloc0(sizeof(FmgrInfo));
|
||||||
fcinfo = palloc0(sizeof(FunctionCallInfoData));
|
fcinfo = palloc0(SizeForFunctionCallInfo(2));
|
||||||
fmgr_info(typentry->cmp_proc, finfo);
|
fmgr_info(typentry->cmp_proc, finfo);
|
||||||
fmgr_info_set_expr((Node *) node, finfo);
|
fmgr_info_set_expr((Node *) node, finfo);
|
||||||
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
||||||
@ -2187,7 +2187,7 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
|
|||||||
|
|
||||||
/* Allocate function lookup data and parameter workspace for this call */
|
/* Allocate function lookup data and parameter workspace for this call */
|
||||||
scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
|
scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
|
||||||
scratch->d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData));
|
scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
|
||||||
flinfo = scratch->d.func.finfo;
|
flinfo = scratch->d.func.finfo;
|
||||||
fcinfo = scratch->d.func.fcinfo_data;
|
fcinfo = scratch->d.func.fcinfo_data;
|
||||||
|
|
||||||
@ -2226,13 +2226,14 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
|
|||||||
*/
|
*/
|
||||||
Const *con = (Const *) arg;
|
Const *con = (Const *) arg;
|
||||||
|
|
||||||
fcinfo->arg[argno] = con->constvalue;
|
fcinfo->args[argno].value = con->constvalue;
|
||||||
fcinfo->argnull[argno] = con->constisnull;
|
fcinfo->args[argno].isnull = con->constisnull;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExecInitExprRec(arg, state,
|
ExecInitExprRec(arg, state,
|
||||||
&fcinfo->arg[argno], &fcinfo->argnull[argno]);
|
&fcinfo->args[argno].value,
|
||||||
|
&fcinfo->args[argno].isnull);
|
||||||
}
|
}
|
||||||
argno++;
|
argno++;
|
||||||
}
|
}
|
||||||
@ -2961,10 +2962,11 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
|
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
|
||||||
int argno;
|
int argno;
|
||||||
int setno;
|
int setno;
|
||||||
FunctionCallInfo trans_fcinfo = &pertrans->transfn_fcinfo;
|
FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
|
||||||
ListCell *arg;
|
ListCell *arg;
|
||||||
ListCell *bail;
|
ListCell *bail;
|
||||||
List *adjust_bailout = NIL;
|
List *adjust_bailout = NIL;
|
||||||
|
NullableDatum *strictargs = NULL;
|
||||||
bool *strictnulls = NULL;
|
bool *strictnulls = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3002,7 +3004,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
Assert(pertrans->numSortCols == 0);
|
Assert(pertrans->numSortCols == 0);
|
||||||
Assert(list_length(pertrans->aggref->args) == 1);
|
Assert(list_length(pertrans->aggref->args) == 1);
|
||||||
|
|
||||||
strictnulls = trans_fcinfo->argnull + 1;
|
strictargs = trans_fcinfo->args + 1;
|
||||||
source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
|
source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3016,21 +3018,21 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
* value
|
* value
|
||||||
*/
|
*/
|
||||||
ExecInitExprRec(source_tle->expr, state,
|
ExecInitExprRec(source_tle->expr, state,
|
||||||
&trans_fcinfo->arg[argno + 1],
|
&trans_fcinfo->args[argno + 1].value,
|
||||||
&trans_fcinfo->argnull[argno + 1]);
|
&trans_fcinfo->args[argno + 1].isnull);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FunctionCallInfo ds_fcinfo = &pertrans->deserialfn_fcinfo;
|
FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
|
||||||
|
|
||||||
/* evaluate argument */
|
/* evaluate argument */
|
||||||
ExecInitExprRec(source_tle->expr, state,
|
ExecInitExprRec(source_tle->expr, state,
|
||||||
&ds_fcinfo->arg[0],
|
&ds_fcinfo->args[0].value,
|
||||||
&ds_fcinfo->argnull[0]);
|
&ds_fcinfo->args[0].isnull);
|
||||||
|
|
||||||
/* Dummy second argument for type-safety reasons */
|
/* Dummy second argument for type-safety reasons */
|
||||||
ds_fcinfo->arg[1] = PointerGetDatum(NULL);
|
ds_fcinfo->args[1].value = PointerGetDatum(NULL);
|
||||||
ds_fcinfo->argnull[1] = false;
|
ds_fcinfo->args[1].isnull = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't call a strict deserialization function with NULL
|
* Don't call a strict deserialization function with NULL
|
||||||
@ -3044,8 +3046,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
scratch.d.agg_deserialize.aggstate = aggstate;
|
scratch.d.agg_deserialize.aggstate = aggstate;
|
||||||
scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
|
scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
|
||||||
scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
|
scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
|
||||||
scratch.resvalue = &trans_fcinfo->arg[argno + 1];
|
scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
|
||||||
scratch.resnull = &trans_fcinfo->argnull[argno + 1];
|
scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
|
||||||
|
|
||||||
ExprEvalPushStep(state, &scratch);
|
ExprEvalPushStep(state, &scratch);
|
||||||
adjust_bailout = lappend_int(adjust_bailout,
|
adjust_bailout = lappend_int(adjust_bailout,
|
||||||
@ -3062,7 +3064,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
/*
|
/*
|
||||||
* Normal transition function without ORDER BY / DISTINCT.
|
* Normal transition function without ORDER BY / DISTINCT.
|
||||||
*/
|
*/
|
||||||
strictnulls = trans_fcinfo->argnull + 1;
|
strictargs = trans_fcinfo->args + 1;
|
||||||
|
|
||||||
foreach(arg, pertrans->aggref->args)
|
foreach(arg, pertrans->aggref->args)
|
||||||
{
|
{
|
||||||
@ -3073,8 +3075,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
* value
|
* value
|
||||||
*/
|
*/
|
||||||
ExecInitExprRec(source_tle->expr, state,
|
ExecInitExprRec(source_tle->expr, state,
|
||||||
&trans_fcinfo->arg[argno + 1],
|
&trans_fcinfo->args[argno + 1].value,
|
||||||
&trans_fcinfo->argnull[argno + 1]);
|
&trans_fcinfo->args[argno + 1].isnull);
|
||||||
argno++;
|
argno++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3122,8 +3124,12 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
*/
|
*/
|
||||||
if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
|
if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
|
||||||
{
|
{
|
||||||
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK;
|
if (strictnulls)
|
||||||
|
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS;
|
||||||
|
else
|
||||||
|
scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS;
|
||||||
scratch.d.agg_strict_input_check.nulls = strictnulls;
|
scratch.d.agg_strict_input_check.nulls = strictnulls;
|
||||||
|
scratch.d.agg_strict_input_check.args = strictargs;
|
||||||
scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
|
scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
|
||||||
scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
|
scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
|
||||||
ExprEvalPushStep(state, &scratch);
|
ExprEvalPushStep(state, &scratch);
|
||||||
@ -3177,7 +3183,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
|
|||||||
Assert(as->d.jump.jumpdone == -1);
|
Assert(as->d.jump.jumpdone == -1);
|
||||||
as->d.jump.jumpdone = state->steps_len;
|
as->d.jump.jumpdone = state->steps_len;
|
||||||
}
|
}
|
||||||
else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK)
|
else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
|
||||||
|
as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
|
||||||
{
|
{
|
||||||
Assert(as->d.agg_strict_input_check.jumpnull == -1);
|
Assert(as->d.agg_strict_input_check.jumpnull == -1);
|
||||||
as->d.agg_strict_input_check.jumpnull = state->steps_len;
|
as->d.agg_strict_input_check.jumpnull = state->steps_len;
|
||||||
@ -3389,7 +3396,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
|
|||||||
|
|
||||||
/* Set up the primary fmgr lookup information */
|
/* Set up the primary fmgr lookup information */
|
||||||
finfo = palloc0(sizeof(FmgrInfo));
|
finfo = palloc0(sizeof(FmgrInfo));
|
||||||
fcinfo = palloc0(sizeof(FunctionCallInfoData));
|
fcinfo = palloc0(SizeForFunctionCallInfo(2));
|
||||||
fmgr_info(foid, finfo);
|
fmgr_info(foid, finfo);
|
||||||
fmgr_info_set_expr(NULL, finfo);
|
fmgr_info_set_expr(NULL, finfo);
|
||||||
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
||||||
@ -3399,16 +3406,16 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
|
|||||||
scratch.opcode = EEOP_INNER_VAR;
|
scratch.opcode = EEOP_INNER_VAR;
|
||||||
scratch.d.var.attnum = attno - 1;
|
scratch.d.var.attnum = attno - 1;
|
||||||
scratch.d.var.vartype = latt->atttypid;
|
scratch.d.var.vartype = latt->atttypid;
|
||||||
scratch.resvalue = &fcinfo->arg[0];
|
scratch.resvalue = &fcinfo->args[0].value;
|
||||||
scratch.resnull = &fcinfo->argnull[0];
|
scratch.resnull = &fcinfo->args[0].isnull;
|
||||||
ExprEvalPushStep(state, &scratch);
|
ExprEvalPushStep(state, &scratch);
|
||||||
|
|
||||||
/* right arg */
|
/* right arg */
|
||||||
scratch.opcode = EEOP_OUTER_VAR;
|
scratch.opcode = EEOP_OUTER_VAR;
|
||||||
scratch.d.var.attnum = attno - 1;
|
scratch.d.var.attnum = attno - 1;
|
||||||
scratch.d.var.vartype = ratt->atttypid;
|
scratch.d.var.vartype = ratt->atttypid;
|
||||||
scratch.resvalue = &fcinfo->arg[1];
|
scratch.resvalue = &fcinfo->args[1].value;
|
||||||
scratch.resnull = &fcinfo->argnull[1];
|
scratch.resnull = &fcinfo->args[1].isnull;
|
||||||
ExprEvalPushStep(state, &scratch);
|
ExprEvalPushStep(state, &scratch);
|
||||||
|
|
||||||
/* evaluate distinctness */
|
/* evaluate distinctness */
|
||||||
|
@ -387,7 +387,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
&&CASE_EEOP_ALTERNATIVE_SUBPLAN,
|
&&CASE_EEOP_ALTERNATIVE_SUBPLAN,
|
||||||
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
|
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
|
||||||
&&CASE_EEOP_AGG_DESERIALIZE,
|
&&CASE_EEOP_AGG_DESERIALIZE,
|
||||||
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK,
|
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
|
||||||
|
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
|
||||||
&&CASE_EEOP_AGG_INIT_TRANS,
|
&&CASE_EEOP_AGG_INIT_TRANS,
|
||||||
&&CASE_EEOP_AGG_STRICT_TRANS_CHECK,
|
&&CASE_EEOP_AGG_STRICT_TRANS_CHECK,
|
||||||
&&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
|
&&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
|
||||||
@ -631,14 +632,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
EEO_CASE(EEOP_FUNCEXPR_STRICT)
|
EEO_CASE(EEOP_FUNCEXPR_STRICT)
|
||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
||||||
bool *argnull = fcinfo->argnull;
|
NullableDatum *args = fcinfo->args;
|
||||||
int argno;
|
int argno;
|
||||||
Datum d;
|
Datum d;
|
||||||
|
|
||||||
/* strict function, so check for NULL args */
|
/* strict function, so check for NULL args */
|
||||||
for (argno = 0; argno < op->d.func.nargs; argno++)
|
for (argno = 0; argno < op->d.func.nargs; argno++)
|
||||||
{
|
{
|
||||||
if (argnull[argno])
|
if (args[argno].isnull)
|
||||||
{
|
{
|
||||||
*op->resnull = true;
|
*op->resnull = true;
|
||||||
goto strictfail;
|
goto strictfail;
|
||||||
@ -1054,8 +1055,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
FunctionCallInfo fcinfo_out;
|
FunctionCallInfo fcinfo_out;
|
||||||
|
|
||||||
fcinfo_out = op->d.iocoerce.fcinfo_data_out;
|
fcinfo_out = op->d.iocoerce.fcinfo_data_out;
|
||||||
fcinfo_out->arg[0] = *op->resvalue;
|
fcinfo_out->args[0].value = *op->resvalue;
|
||||||
fcinfo_out->argnull[0] = false;
|
fcinfo_out->args[0].isnull = false;
|
||||||
|
|
||||||
fcinfo_out->isnull = false;
|
fcinfo_out->isnull = false;
|
||||||
str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
|
str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
|
||||||
@ -1071,8 +1072,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
Datum d;
|
Datum d;
|
||||||
|
|
||||||
fcinfo_in = op->d.iocoerce.fcinfo_data_in;
|
fcinfo_in = op->d.iocoerce.fcinfo_data_in;
|
||||||
fcinfo_in->arg[0] = PointerGetDatum(str);
|
fcinfo_in->args[0].value = PointerGetDatum(str);
|
||||||
fcinfo_in->argnull[0] = *op->resnull;
|
fcinfo_in->args[0].isnull = *op->resnull;
|
||||||
/* second and third arguments are already set up */
|
/* second and third arguments are already set up */
|
||||||
|
|
||||||
fcinfo_in->isnull = false;
|
fcinfo_in->isnull = false;
|
||||||
@ -1099,23 +1100,23 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* IS DISTINCT FROM must evaluate arguments (already done into
|
* IS DISTINCT FROM must evaluate arguments (already done into
|
||||||
* fcinfo->arg/argnull) to determine whether they are NULL; if
|
* fcinfo->args) to determine whether they are NULL; if either is
|
||||||
* either is NULL then the result is determined. If neither is
|
* NULL then the result is determined. If neither is NULL, then
|
||||||
* NULL, then proceed to evaluate the comparison function, which
|
* proceed to evaluate the comparison function, which is just the
|
||||||
* is just the type's standard equality operator. We need not
|
* type's standard equality operator. We need not care whether
|
||||||
* care whether that function is strict. Because the handling of
|
* that function is strict. Because the handling of nulls is
|
||||||
* nulls is different, we can't just reuse EEOP_FUNCEXPR.
|
* different, we can't just reuse EEOP_FUNCEXPR.
|
||||||
*/
|
*/
|
||||||
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
||||||
|
|
||||||
/* check function arguments for NULLness */
|
/* check function arguments for NULLness */
|
||||||
if (fcinfo->argnull[0] && fcinfo->argnull[1])
|
if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
|
||||||
{
|
{
|
||||||
/* Both NULL? Then is not distinct... */
|
/* Both NULL? Then is not distinct... */
|
||||||
*op->resvalue = BoolGetDatum(false);
|
*op->resvalue = BoolGetDatum(false);
|
||||||
*op->resnull = false;
|
*op->resnull = false;
|
||||||
}
|
}
|
||||||
else if (fcinfo->argnull[0] || fcinfo->argnull[1])
|
else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
|
||||||
{
|
{
|
||||||
/* Only one is NULL? Then is distinct... */
|
/* Only one is NULL? Then is distinct... */
|
||||||
*op->resvalue = BoolGetDatum(true);
|
*op->resvalue = BoolGetDatum(true);
|
||||||
@ -1141,12 +1142,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
||||||
|
|
||||||
if (fcinfo->argnull[0] && fcinfo->argnull[1])
|
if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
|
||||||
{
|
{
|
||||||
*op->resvalue = BoolGetDatum(true);
|
*op->resvalue = BoolGetDatum(true);
|
||||||
*op->resnull = false;
|
*op->resnull = false;
|
||||||
}
|
}
|
||||||
else if (fcinfo->argnull[0] || fcinfo->argnull[1])
|
else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
|
||||||
{
|
{
|
||||||
*op->resvalue = BoolGetDatum(false);
|
*op->resvalue = BoolGetDatum(false);
|
||||||
*op->resnull = false;
|
*op->resnull = false;
|
||||||
@ -1167,12 +1168,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
EEO_CASE(EEOP_NULLIF)
|
EEO_CASE(EEOP_NULLIF)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The arguments are already evaluated into fcinfo->arg/argnull.
|
* The arguments are already evaluated into fcinfo->args.
|
||||||
*/
|
*/
|
||||||
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
||||||
|
|
||||||
/* if either argument is NULL they can't be equal */
|
/* if either argument is NULL they can't be equal */
|
||||||
if (!fcinfo->argnull[0] && !fcinfo->argnull[1])
|
if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
|
||||||
{
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
@ -1190,8 +1191,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Arguments aren't equal, so return the first one */
|
/* Arguments aren't equal, so return the first one */
|
||||||
*op->resvalue = fcinfo->arg[0];
|
*op->resvalue = fcinfo->args[0].value;
|
||||||
*op->resnull = fcinfo->argnull[0];
|
*op->resnull = fcinfo->args[0].isnull;
|
||||||
|
|
||||||
EEO_NEXT();
|
EEO_NEXT();
|
||||||
}
|
}
|
||||||
@ -1257,7 +1258,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
|
|
||||||
/* force NULL result if strict fn and NULL input */
|
/* force NULL result if strict fn and NULL input */
|
||||||
if (op->d.rowcompare_step.finfo->fn_strict &&
|
if (op->d.rowcompare_step.finfo->fn_strict &&
|
||||||
(fcinfo->argnull[0] || fcinfo->argnull[1]))
|
(fcinfo->args[0].isnull || fcinfo->args[1].isnull))
|
||||||
{
|
{
|
||||||
*op->resnull = true;
|
*op->resnull = true;
|
||||||
EEO_JUMP(op->d.rowcompare_step.jumpnull);
|
EEO_JUMP(op->d.rowcompare_step.jumpnull);
|
||||||
@ -1496,10 +1497,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
/* evaluate a strict aggregate deserialization function */
|
/* evaluate a strict aggregate deserialization function */
|
||||||
EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
|
EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
|
||||||
{
|
{
|
||||||
bool *argnull = op->d.agg_deserialize.fcinfo_data->argnull;
|
|
||||||
|
|
||||||
/* Don't call a strict deserialization function with NULL input */
|
/* Don't call a strict deserialization function with NULL input */
|
||||||
if (argnull[0])
|
if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
|
||||||
EEO_JUMP(op->d.agg_deserialize.jumpnull);
|
EEO_JUMP(op->d.agg_deserialize.jumpnull);
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
@ -1529,7 +1528,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
* Check that a strict aggregate transition / combination function's
|
* Check that a strict aggregate transition / combination function's
|
||||||
* input is not NULL.
|
* input is not NULL.
|
||||||
*/
|
*/
|
||||||
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK)
|
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
|
||||||
{
|
{
|
||||||
int argno;
|
int argno;
|
||||||
bool *nulls = op->d.agg_strict_input_check.nulls;
|
bool *nulls = op->d.agg_strict_input_check.nulls;
|
||||||
@ -1543,6 +1542,20 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
EEO_NEXT();
|
EEO_NEXT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
|
||||||
|
{
|
||||||
|
int argno;
|
||||||
|
NullableDatum *args = op->d.agg_strict_input_check.args;
|
||||||
|
int nargs = op->d.agg_strict_input_check.nargs;
|
||||||
|
|
||||||
|
for (argno = 0; argno < nargs; argno++)
|
||||||
|
{
|
||||||
|
if (args[argno].isnull)
|
||||||
|
EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
|
||||||
|
}
|
||||||
|
EEO_NEXT();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize an aggregate's first value if necessary.
|
* Initialize an aggregate's first value if necessary.
|
||||||
*/
|
*/
|
||||||
@ -1613,7 +1626,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
|
|
||||||
Assert(pertrans->transtypeByVal);
|
Assert(pertrans->transtypeByVal);
|
||||||
|
|
||||||
fcinfo = &pertrans->transfn_fcinfo;
|
fcinfo = pertrans->transfn_fcinfo;
|
||||||
|
|
||||||
/* cf. select_current_set() */
|
/* cf. select_current_set() */
|
||||||
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
|
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
|
||||||
@ -1625,8 +1638,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
/* invoke transition function in per-tuple context */
|
/* invoke transition function in per-tuple context */
|
||||||
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
|
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
|
||||||
|
|
||||||
fcinfo->arg[0] = pergroup->transValue;
|
fcinfo->args[0].value = pergroup->transValue;
|
||||||
fcinfo->argnull[0] = pergroup->transValueIsNull;
|
fcinfo->args[0].isnull = pergroup->transValueIsNull;
|
||||||
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
||||||
|
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
@ -1664,7 +1677,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
|
|
||||||
Assert(!pertrans->transtypeByVal);
|
Assert(!pertrans->transtypeByVal);
|
||||||
|
|
||||||
fcinfo = &pertrans->transfn_fcinfo;
|
fcinfo = pertrans->transfn_fcinfo;
|
||||||
|
|
||||||
/* cf. select_current_set() */
|
/* cf. select_current_set() */
|
||||||
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
|
aggstate->curaggcontext = op->d.agg_trans.aggcontext;
|
||||||
@ -1676,8 +1689,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
/* invoke transition function in per-tuple context */
|
/* invoke transition function in per-tuple context */
|
||||||
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
|
oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
|
||||||
|
|
||||||
fcinfo->arg[0] = pergroup->transValue;
|
fcinfo->args[0].value = pergroup->transValue;
|
||||||
fcinfo->argnull[0] = pergroup->transValueIsNull;
|
fcinfo->args[0].isnull = pergroup->transValueIsNull;
|
||||||
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
||||||
|
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
@ -2075,7 +2088,7 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
{
|
{
|
||||||
ExprEvalStep *op = &state->steps[0];
|
ExprEvalStep *op = &state->steps[0];
|
||||||
FunctionCallInfo fcinfo;
|
FunctionCallInfo fcinfo;
|
||||||
bool *argnull;
|
NullableDatum *args;
|
||||||
int argno;
|
int argno;
|
||||||
Datum d;
|
Datum d;
|
||||||
|
|
||||||
@ -2089,12 +2102,12 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
op++;
|
op++;
|
||||||
|
|
||||||
fcinfo = op->d.func.fcinfo_data;
|
fcinfo = op->d.func.fcinfo_data;
|
||||||
argnull = fcinfo->argnull;
|
args = fcinfo->args;
|
||||||
|
|
||||||
/* strict function, so check for NULL args */
|
/* strict function, so check for NULL args */
|
||||||
for (argno = 0; argno < op->d.func.nargs; argno++)
|
for (argno = 0; argno < op->d.func.nargs; argno++)
|
||||||
{
|
{
|
||||||
if (argnull[argno])
|
if (args[argno].isnull)
|
||||||
{
|
{
|
||||||
*isnull = true;
|
*isnull = true;
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
@ -2220,14 +2233,14 @@ ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
|
|||||||
|
|
||||||
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
bool *argnull = fcinfo->argnull;
|
NullableDatum *args = fcinfo->args;
|
||||||
int argno;
|
int argno;
|
||||||
Datum d;
|
Datum d;
|
||||||
|
|
||||||
/* strict function, so check for NULL args */
|
/* strict function, so check for NULL args */
|
||||||
for (argno = 0; argno < op->d.func.nargs; argno++)
|
for (argno = 0; argno < op->d.func.nargs; argno++)
|
||||||
{
|
{
|
||||||
if (argnull[argno])
|
if (args[argno].isnull)
|
||||||
{
|
{
|
||||||
*op->resnull = true;
|
*op->resnull = true;
|
||||||
return;
|
return;
|
||||||
@ -2317,8 +2330,8 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
void
|
void
|
||||||
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
|
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
|
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
|
|
||||||
*op->resnull = false;
|
*op->resnull = false;
|
||||||
|
|
||||||
@ -2350,24 +2363,24 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
|
|||||||
case SVFOP_CURRENT_ROLE:
|
case SVFOP_CURRENT_ROLE:
|
||||||
case SVFOP_CURRENT_USER:
|
case SVFOP_CURRENT_USER:
|
||||||
case SVFOP_USER:
|
case SVFOP_USER:
|
||||||
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
*op->resvalue = current_user(&fcinfo);
|
*op->resvalue = current_user(fcinfo);
|
||||||
*op->resnull = fcinfo.isnull;
|
*op->resnull = fcinfo->isnull;
|
||||||
break;
|
break;
|
||||||
case SVFOP_SESSION_USER:
|
case SVFOP_SESSION_USER:
|
||||||
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
*op->resvalue = session_user(&fcinfo);
|
*op->resvalue = session_user(fcinfo);
|
||||||
*op->resnull = fcinfo.isnull;
|
*op->resnull = fcinfo->isnull;
|
||||||
break;
|
break;
|
||||||
case SVFOP_CURRENT_CATALOG:
|
case SVFOP_CURRENT_CATALOG:
|
||||||
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
*op->resvalue = current_database(&fcinfo);
|
*op->resvalue = current_database(fcinfo);
|
||||||
*op->resnull = fcinfo.isnull;
|
*op->resnull = fcinfo->isnull;
|
||||||
break;
|
break;
|
||||||
case SVFOP_CURRENT_SCHEMA:
|
case SVFOP_CURRENT_SCHEMA:
|
||||||
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
*op->resvalue = current_schema(&fcinfo);
|
*op->resvalue = current_schema(fcinfo);
|
||||||
*op->resnull = fcinfo.isnull;
|
*op->resnull = fcinfo->isnull;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2800,8 +2813,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
|
|||||||
int off;
|
int off;
|
||||||
|
|
||||||
/* set at initialization */
|
/* set at initialization */
|
||||||
Assert(fcinfo->argnull[0] == false);
|
Assert(fcinfo->args[0].isnull == false);
|
||||||
Assert(fcinfo->argnull[1] == false);
|
Assert(fcinfo->args[1].isnull == false);
|
||||||
|
|
||||||
/* default to null result */
|
/* default to null result */
|
||||||
*op->resnull = true;
|
*op->resnull = true;
|
||||||
@ -2823,8 +2836,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
|
|||||||
int cmpresult;
|
int cmpresult;
|
||||||
|
|
||||||
/* apply comparison function */
|
/* apply comparison function */
|
||||||
fcinfo->arg[0] = *op->resvalue;
|
fcinfo->args[0].value = *op->resvalue;
|
||||||
fcinfo->arg[1] = values[off];
|
fcinfo->args[1].value = values[off];
|
||||||
|
|
||||||
fcinfo->isnull = false;
|
fcinfo->isnull = false;
|
||||||
cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
|
cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
|
||||||
@ -3324,7 +3337,7 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
|
|||||||
* Evaluate "scalar op ANY/ALL (array)".
|
* Evaluate "scalar op ANY/ALL (array)".
|
||||||
*
|
*
|
||||||
* Source array is in our result area, scalar arg is already evaluated into
|
* Source array is in our result area, scalar arg is already evaluated into
|
||||||
* fcinfo->arg[0]/argnull[0].
|
* fcinfo->args[0].
|
||||||
*
|
*
|
||||||
* The operator always yields boolean, and we combine the results across all
|
* The operator always yields boolean, and we combine the results across all
|
||||||
* array elements using OR and AND (for ANY and ALL respectively). Of course
|
* array elements using OR and AND (for ANY and ALL respectively). Of course
|
||||||
@ -3376,7 +3389,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
|
|||||||
* If the scalar is NULL, and the function is strict, return NULL; no
|
* If the scalar is NULL, and the function is strict, return NULL; no
|
||||||
* point in iterating the loop.
|
* point in iterating the loop.
|
||||||
*/
|
*/
|
||||||
if (fcinfo->argnull[0] && strictfunc)
|
if (fcinfo->args[0].isnull && strictfunc)
|
||||||
{
|
{
|
||||||
*op->resnull = true;
|
*op->resnull = true;
|
||||||
return;
|
return;
|
||||||
@ -3416,20 +3429,20 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
|
|||||||
/* Get array element, checking for NULL */
|
/* Get array element, checking for NULL */
|
||||||
if (bitmap && (*bitmap & bitmask) == 0)
|
if (bitmap && (*bitmap & bitmask) == 0)
|
||||||
{
|
{
|
||||||
fcinfo->arg[1] = (Datum) 0;
|
fcinfo->args[1].value = (Datum) 0;
|
||||||
fcinfo->argnull[1] = true;
|
fcinfo->args[1].isnull = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elt = fetch_att(s, typbyval, typlen);
|
elt = fetch_att(s, typbyval, typlen);
|
||||||
s = att_addlength_pointer(s, typlen, s);
|
s = att_addlength_pointer(s, typlen, s);
|
||||||
s = (char *) att_align_nominal(s, typalign);
|
s = (char *) att_align_nominal(s, typalign);
|
||||||
fcinfo->arg[1] = elt;
|
fcinfo->args[1].value = elt;
|
||||||
fcinfo->argnull[1] = false;
|
fcinfo->args[1].isnull = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call comparison function */
|
/* Call comparison function */
|
||||||
if (fcinfo->argnull[1] && strictfunc)
|
if (fcinfo->args[1].isnull && strictfunc)
|
||||||
{
|
{
|
||||||
fcinfo->isnull = true;
|
fcinfo->isnull = true;
|
||||||
thisresult = (Datum) 0;
|
thisresult = (Datum) 0;
|
||||||
@ -4044,7 +4057,7 @@ ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
|
|||||||
void
|
void
|
||||||
ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup)
|
ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup)
|
||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
|
FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4055,7 +4068,7 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup
|
|||||||
*/
|
*/
|
||||||
oldContext = MemoryContextSwitchTo(
|
oldContext = MemoryContextSwitchTo(
|
||||||
aggstate->curaggcontext->ecxt_per_tuple_memory);
|
aggstate->curaggcontext->ecxt_per_tuple_memory);
|
||||||
pergroup->transValue = datumCopy(fcinfo->arg[1],
|
pergroup->transValue = datumCopy(fcinfo->args[1].value,
|
||||||
pertrans->transtypeByVal,
|
pertrans->transtypeByVal,
|
||||||
pertrans->transtypeLen);
|
pertrans->transtypeLen);
|
||||||
pergroup->transValueIsNull = false;
|
pergroup->transValueIsNull = false;
|
||||||
|
@ -109,7 +109,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
Oid funcrettype;
|
Oid funcrettype;
|
||||||
bool returnsTuple;
|
bool returnsTuple;
|
||||||
bool returnsSet = false;
|
bool returnsSet = false;
|
||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfo fcinfo;
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
ReturnSetInfo rsinfo;
|
ReturnSetInfo rsinfo;
|
||||||
HeapTupleData tmptup;
|
HeapTupleData tmptup;
|
||||||
@ -141,6 +141,8 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
rsinfo.setResult = NULL;
|
rsinfo.setResult = NULL;
|
||||||
rsinfo.setDesc = NULL;
|
rsinfo.setDesc = NULL;
|
||||||
|
|
||||||
|
fcinfo = palloc(SizeForFunctionCallInfo(list_length(setexpr->args)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normally the passed expression tree will be a SetExprState, since the
|
* Normally the passed expression tree will be a SetExprState, since the
|
||||||
* grammar only allows a function call at the top level of a table
|
* grammar only allows a function call at the top level of a table
|
||||||
@ -157,9 +159,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
* This path is similar to ExecMakeFunctionResultSet.
|
* This path is similar to ExecMakeFunctionResultSet.
|
||||||
*/
|
*/
|
||||||
returnsSet = setexpr->funcReturnsSet;
|
returnsSet = setexpr->funcReturnsSet;
|
||||||
InitFunctionCallInfoData(fcinfo, &(setexpr->func),
|
InitFunctionCallInfoData(*fcinfo, &(setexpr->func),
|
||||||
list_length(setexpr->args),
|
list_length(setexpr->args),
|
||||||
setexpr->fcinfo_data.fncollation,
|
setexpr->fcinfo->fncollation,
|
||||||
NULL, (Node *) &rsinfo);
|
NULL, (Node *) &rsinfo);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -174,7 +176,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
*/
|
*/
|
||||||
MemoryContextReset(argContext);
|
MemoryContextReset(argContext);
|
||||||
oldcontext = MemoryContextSwitchTo(argContext);
|
oldcontext = MemoryContextSwitchTo(argContext);
|
||||||
ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext);
|
ExecEvalFuncArgs(fcinfo, setexpr->args, econtext);
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -186,9 +188,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < fcinfo.nargs; i++)
|
for (i = 0; i < fcinfo->nargs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo.argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
goto no_function_result;
|
goto no_function_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,7 +198,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Treat setexpr as a generic expression */
|
/* Treat setexpr as a generic expression */
|
||||||
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -224,11 +226,11 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
/* Call the function or expression one time */
|
/* Call the function or expression one time */
|
||||||
if (!setexpr->elidedFuncState)
|
if (!setexpr->elidedFuncState)
|
||||||
{
|
{
|
||||||
pgstat_init_function_usage(&fcinfo, &fcusage);
|
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||||
|
|
||||||
fcinfo.isnull = false;
|
fcinfo->isnull = false;
|
||||||
rsinfo.isDone = ExprSingleResult;
|
rsinfo.isDone = ExprSingleResult;
|
||||||
result = FunctionCallInvoke(&fcinfo);
|
result = FunctionCallInvoke(fcinfo);
|
||||||
|
|
||||||
pgstat_end_function_usage(&fcusage,
|
pgstat_end_function_usage(&fcusage,
|
||||||
rsinfo.isDone != ExprMultipleResult);
|
rsinfo.isDone != ExprMultipleResult);
|
||||||
@ -236,7 +238,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result =
|
result =
|
||||||
ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull);
|
ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
|
||||||
rsinfo.isDone = ExprSingleResult;
|
rsinfo.isDone = ExprSingleResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +279,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
*/
|
*/
|
||||||
if (returnsTuple)
|
if (returnsTuple)
|
||||||
{
|
{
|
||||||
if (!fcinfo.isnull)
|
if (!fcinfo->isnull)
|
||||||
{
|
{
|
||||||
HeapTupleHeader td = DatumGetHeapTupleHeader(result);
|
HeapTupleHeader td = DatumGetHeapTupleHeader(result);
|
||||||
|
|
||||||
@ -338,7 +340,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Scalar-type case: just store the function result */
|
/* Scalar-type case: just store the function result */
|
||||||
tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
|
tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -547,7 +549,7 @@ restart:
|
|||||||
* rows from this SRF have been returned, otherwise ValuePerCall SRFs
|
* rows from this SRF have been returned, otherwise ValuePerCall SRFs
|
||||||
* would reference freed memory after the first returned row.
|
* would reference freed memory after the first returned row.
|
||||||
*/
|
*/
|
||||||
fcinfo = &fcache->fcinfo_data;
|
fcinfo = fcache->fcinfo;
|
||||||
arguments = fcache->args;
|
arguments = fcache->args;
|
||||||
if (!fcache->setArgsValid)
|
if (!fcache->setArgsValid)
|
||||||
{
|
{
|
||||||
@ -587,7 +589,7 @@ restart:
|
|||||||
{
|
{
|
||||||
for (i = 0; i < fcinfo->nargs; i++)
|
for (i = 0; i < fcinfo->nargs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
{
|
{
|
||||||
callit = false;
|
callit = false;
|
||||||
break;
|
break;
|
||||||
@ -678,6 +680,7 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node,
|
|||||||
MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
|
MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
|
||||||
{
|
{
|
||||||
AclResult aclresult;
|
AclResult aclresult;
|
||||||
|
size_t numargs = list_length(sexpr->args);
|
||||||
|
|
||||||
/* Check permission to call function */
|
/* Check permission to call function */
|
||||||
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
|
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
|
||||||
@ -704,8 +707,10 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node,
|
|||||||
fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
|
fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
|
||||||
|
|
||||||
/* Initialize the function call parameter struct as well */
|
/* Initialize the function call parameter struct as well */
|
||||||
InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func),
|
sexpr->fcinfo =
|
||||||
list_length(sexpr->args),
|
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
|
||||||
|
InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func),
|
||||||
|
numargs,
|
||||||
input_collation, NULL, NULL);
|
input_collation, NULL, NULL);
|
||||||
|
|
||||||
/* If function returns set, check if that's allowed by caller */
|
/* If function returns set, check if that's allowed by caller */
|
||||||
@ -820,9 +825,9 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
|
|||||||
{
|
{
|
||||||
ExprState *argstate = (ExprState *) lfirst(arg);
|
ExprState *argstate = (ExprState *) lfirst(arg);
|
||||||
|
|
||||||
fcinfo->arg[i] = ExecEvalExpr(argstate,
|
fcinfo->args[i].value = ExecEvalExpr(argstate,
|
||||||
econtext,
|
econtext,
|
||||||
&fcinfo->argnull[i]);
|
&fcinfo->args[i].isnull);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -933,8 +933,8 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
|
|||||||
{
|
{
|
||||||
ParamExternData *prm = ¶mLI->params[i];
|
ParamExternData *prm = ¶mLI->params[i];
|
||||||
|
|
||||||
prm->value = fcinfo->arg[i];
|
prm->value = fcinfo->args[i].value;
|
||||||
prm->isnull = fcinfo->argnull[i];
|
prm->isnull = fcinfo->args[i].isnull;
|
||||||
prm->pflags = 0;
|
prm->pflags = 0;
|
||||||
prm->ptype = fcache->pinfo->argtypes[i];
|
prm->ptype = fcache->pinfo->argtypes[i];
|
||||||
}
|
}
|
||||||
|
@ -553,7 +553,7 @@ advance_transition_function(AggState *aggstate,
|
|||||||
AggStatePerTrans pertrans,
|
AggStatePerTrans pertrans,
|
||||||
AggStatePerGroup pergroupstate)
|
AggStatePerGroup pergroupstate)
|
||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
|
FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
Datum newVal;
|
Datum newVal;
|
||||||
|
|
||||||
@ -568,7 +568,7 @@ advance_transition_function(AggState *aggstate,
|
|||||||
|
|
||||||
for (i = 1; i <= numTransInputs; i++)
|
for (i = 1; i <= numTransInputs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pergroupstate->noTransValue)
|
if (pergroupstate->noTransValue)
|
||||||
@ -584,7 +584,7 @@ advance_transition_function(AggState *aggstate,
|
|||||||
*/
|
*/
|
||||||
oldContext = MemoryContextSwitchTo(
|
oldContext = MemoryContextSwitchTo(
|
||||||
aggstate->curaggcontext->ecxt_per_tuple_memory);
|
aggstate->curaggcontext->ecxt_per_tuple_memory);
|
||||||
pergroupstate->transValue = datumCopy(fcinfo->arg[1],
|
pergroupstate->transValue = datumCopy(fcinfo->args[1].value,
|
||||||
pertrans->transtypeByVal,
|
pertrans->transtypeByVal,
|
||||||
pertrans->transtypeLen);
|
pertrans->transtypeLen);
|
||||||
pergroupstate->transValueIsNull = false;
|
pergroupstate->transValueIsNull = false;
|
||||||
@ -613,8 +613,8 @@ advance_transition_function(AggState *aggstate,
|
|||||||
/*
|
/*
|
||||||
* OK to call the transition function
|
* OK to call the transition function
|
||||||
*/
|
*/
|
||||||
fcinfo->arg[0] = pergroupstate->transValue;
|
fcinfo->args[0].value = pergroupstate->transValue;
|
||||||
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
|
fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
|
||||||
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
||||||
|
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
@ -717,7 +717,7 @@ process_ordered_aggregate_single(AggState *aggstate,
|
|||||||
bool isDistinct = (pertrans->numDistinctCols > 0);
|
bool isDistinct = (pertrans->numDistinctCols > 0);
|
||||||
Datum newAbbrevVal = (Datum) 0;
|
Datum newAbbrevVal = (Datum) 0;
|
||||||
Datum oldAbbrevVal = (Datum) 0;
|
Datum oldAbbrevVal = (Datum) 0;
|
||||||
FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
|
FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
|
||||||
Datum *newVal;
|
Datum *newVal;
|
||||||
bool *isNull;
|
bool *isNull;
|
||||||
|
|
||||||
@ -726,8 +726,8 @@ process_ordered_aggregate_single(AggState *aggstate,
|
|||||||
tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
|
tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
|
||||||
|
|
||||||
/* Load the column into argument 1 (arg 0 will be transition value) */
|
/* Load the column into argument 1 (arg 0 will be transition value) */
|
||||||
newVal = fcinfo->arg + 1;
|
newVal = &fcinfo->args[1].value;
|
||||||
isNull = fcinfo->argnull + 1;
|
isNull = &fcinfo->args[1].isnull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: if input type is pass-by-ref, the datums returned by the sort are
|
* Note: if input type is pass-by-ref, the datums returned by the sort are
|
||||||
@ -803,7 +803,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
|
|||||||
AggStatePerGroup pergroupstate)
|
AggStatePerGroup pergroupstate)
|
||||||
{
|
{
|
||||||
ExprContext *tmpcontext = aggstate->tmpcontext;
|
ExprContext *tmpcontext = aggstate->tmpcontext;
|
||||||
FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
|
FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
|
||||||
TupleTableSlot *slot1 = pertrans->sortslot;
|
TupleTableSlot *slot1 = pertrans->sortslot;
|
||||||
TupleTableSlot *slot2 = pertrans->uniqslot;
|
TupleTableSlot *slot2 = pertrans->uniqslot;
|
||||||
int numTransInputs = pertrans->numTransInputs;
|
int numTransInputs = pertrans->numTransInputs;
|
||||||
@ -843,8 +843,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
|
|||||||
/* Start from 1, since the 0th arg will be the transition value */
|
/* Start from 1, since the 0th arg will be the transition value */
|
||||||
for (i = 0; i < numTransInputs; i++)
|
for (i = 0; i < numTransInputs; i++)
|
||||||
{
|
{
|
||||||
fcinfo->arg[i + 1] = slot1->tts_values[i];
|
fcinfo->args[i + 1].value = slot1->tts_values[i];
|
||||||
fcinfo->argnull[i + 1] = slot1->tts_isnull[i];
|
fcinfo->args[i + 1].isnull = slot1->tts_isnull[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
advance_transition_function(aggstate, pertrans, pergroupstate);
|
advance_transition_function(aggstate, pertrans, pergroupstate);
|
||||||
@ -897,7 +897,7 @@ finalize_aggregate(AggState *aggstate,
|
|||||||
AggStatePerGroup pergroupstate,
|
AggStatePerGroup pergroupstate,
|
||||||
Datum *resultVal, bool *resultIsNull)
|
Datum *resultVal, bool *resultIsNull)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
bool anynull = false;
|
bool anynull = false;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
int i;
|
int i;
|
||||||
@ -917,10 +917,10 @@ finalize_aggregate(AggState *aggstate,
|
|||||||
{
|
{
|
||||||
ExprState *expr = (ExprState *) lfirst(lc);
|
ExprState *expr = (ExprState *) lfirst(lc);
|
||||||
|
|
||||||
fcinfo.arg[i] = ExecEvalExpr(expr,
|
fcinfo->args[i].value = ExecEvalExpr(expr,
|
||||||
aggstate->ss.ps.ps_ExprContext,
|
aggstate->ss.ps.ps_ExprContext,
|
||||||
&fcinfo.argnull[i]);
|
&fcinfo->args[i].isnull);
|
||||||
anynull |= fcinfo.argnull[i];
|
anynull |= fcinfo->args[i].isnull;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,27 +934,28 @@ finalize_aggregate(AggState *aggstate,
|
|||||||
/* set up aggstate->curperagg for AggGetAggref() */
|
/* set up aggstate->curperagg for AggGetAggref() */
|
||||||
aggstate->curperagg = peragg;
|
aggstate->curperagg = peragg;
|
||||||
|
|
||||||
InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
|
InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
|
||||||
numFinalArgs,
|
numFinalArgs,
|
||||||
pertrans->aggCollation,
|
pertrans->aggCollation,
|
||||||
(void *) aggstate, NULL);
|
(void *) aggstate, NULL);
|
||||||
|
|
||||||
/* Fill in the transition state value */
|
/* Fill in the transition state value */
|
||||||
fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
|
fcinfo->args[0].value =
|
||||||
|
MakeExpandedObjectReadOnly(pergroupstate->transValue,
|
||||||
pergroupstate->transValueIsNull,
|
pergroupstate->transValueIsNull,
|
||||||
pertrans->transtypeLen);
|
pertrans->transtypeLen);
|
||||||
fcinfo.argnull[0] = pergroupstate->transValueIsNull;
|
fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
|
||||||
anynull |= pergroupstate->transValueIsNull;
|
anynull |= pergroupstate->transValueIsNull;
|
||||||
|
|
||||||
/* Fill any remaining argument positions with nulls */
|
/* Fill any remaining argument positions with nulls */
|
||||||
for (; i < numFinalArgs; i++)
|
for (; i < numFinalArgs; i++)
|
||||||
{
|
{
|
||||||
fcinfo.arg[i] = (Datum) 0;
|
fcinfo->args[i].value = (Datum) 0;
|
||||||
fcinfo.argnull[i] = true;
|
fcinfo->args[i].isnull = true;
|
||||||
anynull = true;
|
anynull = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcinfo.flinfo->fn_strict && anynull)
|
if (fcinfo->flinfo->fn_strict && anynull)
|
||||||
{
|
{
|
||||||
/* don't call a strict function with NULL inputs */
|
/* don't call a strict function with NULL inputs */
|
||||||
*resultVal = (Datum) 0;
|
*resultVal = (Datum) 0;
|
||||||
@ -962,8 +963,8 @@ finalize_aggregate(AggState *aggstate,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*resultVal = FunctionCallInvoke(&fcinfo);
|
*resultVal = FunctionCallInvoke(fcinfo);
|
||||||
*resultIsNull = fcinfo.isnull;
|
*resultIsNull = fcinfo->isnull;
|
||||||
}
|
}
|
||||||
aggstate->curperagg = NULL;
|
aggstate->curperagg = NULL;
|
||||||
}
|
}
|
||||||
@ -1018,12 +1019,13 @@ finalize_partialaggregate(AggState *aggstate,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
|
FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
|
||||||
|
|
||||||
fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
|
fcinfo->args[0].value =
|
||||||
|
MakeExpandedObjectReadOnly(pergroupstate->transValue,
|
||||||
pergroupstate->transValueIsNull,
|
pergroupstate->transValueIsNull,
|
||||||
pertrans->transtypeLen);
|
pertrans->transtypeLen);
|
||||||
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
|
fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
|
||||||
|
|
||||||
*resultVal = FunctionCallInvoke(fcinfo);
|
*resultVal = FunctionCallInvoke(fcinfo);
|
||||||
*resultIsNull = fcinfo->isnull;
|
*resultIsNull = fcinfo->isnull;
|
||||||
@ -2927,7 +2929,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
|||||||
fmgr_info(aggtransfn, &pertrans->transfn);
|
fmgr_info(aggtransfn, &pertrans->transfn);
|
||||||
fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
|
fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
|
||||||
|
|
||||||
InitFunctionCallInfoData(pertrans->transfn_fcinfo,
|
pertrans->transfn_fcinfo =
|
||||||
|
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(2));
|
||||||
|
InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
|
||||||
&pertrans->transfn,
|
&pertrans->transfn,
|
||||||
2,
|
2,
|
||||||
pertrans->aggCollation,
|
pertrans->aggCollation,
|
||||||
@ -2947,6 +2951,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Expr *transfnexpr;
|
Expr *transfnexpr;
|
||||||
|
size_t numInputs = pertrans->numTransInputs + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up infrastructure for calling the transfn. Note that invtrans
|
* Set up infrastructure for calling the transfn. Note that invtrans
|
||||||
@ -2965,9 +2970,11 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
|||||||
fmgr_info(aggtransfn, &pertrans->transfn);
|
fmgr_info(aggtransfn, &pertrans->transfn);
|
||||||
fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
|
fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
|
||||||
|
|
||||||
InitFunctionCallInfoData(pertrans->transfn_fcinfo,
|
pertrans->transfn_fcinfo =
|
||||||
|
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numInputs));
|
||||||
|
InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
|
||||||
&pertrans->transfn,
|
&pertrans->transfn,
|
||||||
pertrans->numTransInputs + 1,
|
numInputs,
|
||||||
pertrans->aggCollation,
|
pertrans->aggCollation,
|
||||||
(void *) aggstate, NULL);
|
(void *) aggstate, NULL);
|
||||||
|
|
||||||
@ -3003,7 +3010,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
|||||||
fmgr_info(aggserialfn, &pertrans->serialfn);
|
fmgr_info(aggserialfn, &pertrans->serialfn);
|
||||||
fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
|
fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
|
||||||
|
|
||||||
InitFunctionCallInfoData(pertrans->serialfn_fcinfo,
|
pertrans->serialfn_fcinfo =
|
||||||
|
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(1));
|
||||||
|
InitFunctionCallInfoData(*pertrans->serialfn_fcinfo,
|
||||||
&pertrans->serialfn,
|
&pertrans->serialfn,
|
||||||
1,
|
1,
|
||||||
InvalidOid,
|
InvalidOid,
|
||||||
@ -3017,7 +3026,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
|
|||||||
fmgr_info(aggdeserialfn, &pertrans->deserialfn);
|
fmgr_info(aggdeserialfn, &pertrans->deserialfn);
|
||||||
fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
|
fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
|
||||||
|
|
||||||
InitFunctionCallInfoData(pertrans->deserialfn_fcinfo,
|
pertrans->deserialfn_fcinfo =
|
||||||
|
(FunctionCallInfo) palloc(SizeForFunctionCallInfo(2));
|
||||||
|
InitFunctionCallInfoData(*pertrans->deserialfn_fcinfo,
|
||||||
&pertrans->deserialfn,
|
&pertrans->deserialfn,
|
||||||
2,
|
2,
|
||||||
InvalidOid,
|
InvalidOid,
|
||||||
|
@ -241,10 +241,9 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||||||
WindowStatePerFunc perfuncstate,
|
WindowStatePerFunc perfuncstate,
|
||||||
WindowStatePerAgg peraggstate)
|
WindowStatePerAgg peraggstate)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
|
WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
|
||||||
int numArguments = perfuncstate->numArguments;
|
int numArguments = perfuncstate->numArguments;
|
||||||
FunctionCallInfoData fcinfodata;
|
|
||||||
FunctionCallInfo fcinfo = &fcinfodata;
|
|
||||||
Datum newVal;
|
Datum newVal;
|
||||||
ListCell *arg;
|
ListCell *arg;
|
||||||
int i;
|
int i;
|
||||||
@ -273,8 +272,8 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||||||
{
|
{
|
||||||
ExprState *argstate = (ExprState *) lfirst(arg);
|
ExprState *argstate = (ExprState *) lfirst(arg);
|
||||||
|
|
||||||
fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
|
fcinfo->args[i].value = ExecEvalExpr(argstate, econtext,
|
||||||
&fcinfo->argnull[i]);
|
&fcinfo->args[i].isnull);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +286,7 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||||||
*/
|
*/
|
||||||
for (i = 1; i <= numArguments; i++)
|
for (i = 1; i <= numArguments; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
{
|
{
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
return;
|
return;
|
||||||
@ -306,7 +305,7 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||||||
if (peraggstate->transValueCount == 0 && peraggstate->transValueIsNull)
|
if (peraggstate->transValueCount == 0 && peraggstate->transValueIsNull)
|
||||||
{
|
{
|
||||||
MemoryContextSwitchTo(peraggstate->aggcontext);
|
MemoryContextSwitchTo(peraggstate->aggcontext);
|
||||||
peraggstate->transValue = datumCopy(fcinfo->arg[1],
|
peraggstate->transValue = datumCopy(fcinfo->args[1].value,
|
||||||
peraggstate->transtypeByVal,
|
peraggstate->transtypeByVal,
|
||||||
peraggstate->transtypeLen);
|
peraggstate->transtypeLen);
|
||||||
peraggstate->transValueIsNull = false;
|
peraggstate->transValueIsNull = false;
|
||||||
@ -339,8 +338,8 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||||||
numArguments + 1,
|
numArguments + 1,
|
||||||
perfuncstate->winCollation,
|
perfuncstate->winCollation,
|
||||||
(void *) winstate, NULL);
|
(void *) winstate, NULL);
|
||||||
fcinfo->arg[0] = peraggstate->transValue;
|
fcinfo->args[0].value = peraggstate->transValue;
|
||||||
fcinfo->argnull[0] = peraggstate->transValueIsNull;
|
fcinfo->args[0].isnull = peraggstate->transValueIsNull;
|
||||||
winstate->curaggcontext = peraggstate->aggcontext;
|
winstate->curaggcontext = peraggstate->aggcontext;
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
winstate->curaggcontext = NULL;
|
winstate->curaggcontext = NULL;
|
||||||
@ -418,10 +417,9 @@ advance_windowaggregate_base(WindowAggState *winstate,
|
|||||||
WindowStatePerFunc perfuncstate,
|
WindowStatePerFunc perfuncstate,
|
||||||
WindowStatePerAgg peraggstate)
|
WindowStatePerAgg peraggstate)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
|
WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
|
||||||
int numArguments = perfuncstate->numArguments;
|
int numArguments = perfuncstate->numArguments;
|
||||||
FunctionCallInfoData fcinfodata;
|
|
||||||
FunctionCallInfo fcinfo = &fcinfodata;
|
|
||||||
Datum newVal;
|
Datum newVal;
|
||||||
ListCell *arg;
|
ListCell *arg;
|
||||||
int i;
|
int i;
|
||||||
@ -450,8 +448,8 @@ advance_windowaggregate_base(WindowAggState *winstate,
|
|||||||
{
|
{
|
||||||
ExprState *argstate = (ExprState *) lfirst(arg);
|
ExprState *argstate = (ExprState *) lfirst(arg);
|
||||||
|
|
||||||
fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
|
fcinfo->args[i].value = ExecEvalExpr(argstate, econtext,
|
||||||
&fcinfo->argnull[i]);
|
&fcinfo->args[i].isnull);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +462,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
|
|||||||
*/
|
*/
|
||||||
for (i = 1; i <= numArguments; i++)
|
for (i = 1; i <= numArguments; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
{
|
{
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
return true;
|
return true;
|
||||||
@ -510,8 +508,8 @@ advance_windowaggregate_base(WindowAggState *winstate,
|
|||||||
numArguments + 1,
|
numArguments + 1,
|
||||||
perfuncstate->winCollation,
|
perfuncstate->winCollation,
|
||||||
(void *) winstate, NULL);
|
(void *) winstate, NULL);
|
||||||
fcinfo->arg[0] = peraggstate->transValue;
|
fcinfo->args[0].value = peraggstate->transValue;
|
||||||
fcinfo->argnull[0] = peraggstate->transValueIsNull;
|
fcinfo->args[0].isnull = peraggstate->transValueIsNull;
|
||||||
winstate->curaggcontext = peraggstate->aggcontext;
|
winstate->curaggcontext = peraggstate->aggcontext;
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
winstate->curaggcontext = NULL;
|
winstate->curaggcontext = NULL;
|
||||||
@ -591,30 +589,31 @@ finalize_windowaggregate(WindowAggState *winstate,
|
|||||||
*/
|
*/
|
||||||
if (OidIsValid(peraggstate->finalfn_oid))
|
if (OidIsValid(peraggstate->finalfn_oid))
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
int numFinalArgs = peraggstate->numFinalArgs;
|
int numFinalArgs = peraggstate->numFinalArgs;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
bool anynull;
|
bool anynull;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn),
|
InitFunctionCallInfoData(fcinfodata.fcinfo, &(peraggstate->finalfn),
|
||||||
numFinalArgs,
|
numFinalArgs,
|
||||||
perfuncstate->winCollation,
|
perfuncstate->winCollation,
|
||||||
(void *) winstate, NULL);
|
(void *) winstate, NULL);
|
||||||
fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue,
|
fcinfo->args[0].value =
|
||||||
|
MakeExpandedObjectReadOnly(peraggstate->transValue,
|
||||||
peraggstate->transValueIsNull,
|
peraggstate->transValueIsNull,
|
||||||
peraggstate->transtypeLen);
|
peraggstate->transtypeLen);
|
||||||
fcinfo.argnull[0] = peraggstate->transValueIsNull;
|
fcinfo->args[0].isnull = peraggstate->transValueIsNull;
|
||||||
anynull = peraggstate->transValueIsNull;
|
anynull = peraggstate->transValueIsNull;
|
||||||
|
|
||||||
/* Fill any remaining argument positions with nulls */
|
/* Fill any remaining argument positions with nulls */
|
||||||
for (i = 1; i < numFinalArgs; i++)
|
for (i = 1; i < numFinalArgs; i++)
|
||||||
{
|
{
|
||||||
fcinfo.arg[i] = (Datum) 0;
|
fcinfo->args[i].value = (Datum) 0;
|
||||||
fcinfo.argnull[i] = true;
|
fcinfo->args[i].isnull = true;
|
||||||
anynull = true;
|
anynull = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcinfo.flinfo->fn_strict && anynull)
|
if (fcinfo->flinfo->fn_strict && anynull)
|
||||||
{
|
{
|
||||||
/* don't call a strict function with NULL inputs */
|
/* don't call a strict function with NULL inputs */
|
||||||
*result = (Datum) 0;
|
*result = (Datum) 0;
|
||||||
@ -623,9 +622,9 @@ finalize_windowaggregate(WindowAggState *winstate,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
winstate->curaggcontext = peraggstate->aggcontext;
|
winstate->curaggcontext = peraggstate->aggcontext;
|
||||||
*result = FunctionCallInvoke(&fcinfo);
|
*result = FunctionCallInvoke(fcinfo);
|
||||||
winstate->curaggcontext = NULL;
|
winstate->curaggcontext = NULL;
|
||||||
*isnull = fcinfo.isnull;
|
*isnull = fcinfo->isnull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1032,7 +1031,7 @@ static void
|
|||||||
eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
|
eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
|
||||||
Datum *result, bool *isnull)
|
Datum *result, bool *isnull)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo;
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
|
|
||||||
oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
|
oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
|
||||||
@ -1043,24 +1042,25 @@ eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
|
|||||||
* implementations to support varying numbers of arguments. The real info
|
* implementations to support varying numbers of arguments. The real info
|
||||||
* goes through the WindowObject, which is passed via fcinfo->context.
|
* goes through the WindowObject, which is passed via fcinfo->context.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo),
|
InitFunctionCallInfoData(*fcinfo, &(perfuncstate->flinfo),
|
||||||
perfuncstate->numArguments,
|
perfuncstate->numArguments,
|
||||||
perfuncstate->winCollation,
|
perfuncstate->winCollation,
|
||||||
(void *) perfuncstate->winobj, NULL);
|
(void *) perfuncstate->winobj, NULL);
|
||||||
/* Just in case, make all the regular argument slots be null */
|
/* Just in case, make all the regular argument slots be null */
|
||||||
memset(fcinfo.argnull, true, perfuncstate->numArguments);
|
for (int argno = 0; argno < perfuncstate->numArguments; argno++)
|
||||||
|
fcinfo->args[argno].isnull = true;
|
||||||
/* Window functions don't have a current aggregate context, either */
|
/* Window functions don't have a current aggregate context, either */
|
||||||
winstate->curaggcontext = NULL;
|
winstate->curaggcontext = NULL;
|
||||||
|
|
||||||
*result = FunctionCallInvoke(&fcinfo);
|
*result = FunctionCallInvoke(fcinfo);
|
||||||
*isnull = fcinfo.isnull;
|
*isnull = fcinfo->isnull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure pass-by-ref data is allocated in the appropriate context. (We
|
* Make sure pass-by-ref data is allocated in the appropriate context. (We
|
||||||
* need this in case the function returns a pointer into some short-lived
|
* need this in case the function returns a pointer into some short-lived
|
||||||
* tuple, as is entirely possible.)
|
* tuple, as is entirely possible.)
|
||||||
*/
|
*/
|
||||||
if (!perfuncstate->resulttypeByVal && !fcinfo.isnull &&
|
if (!perfuncstate->resulttypeByVal && !fcinfo->isnull &&
|
||||||
!MemoryContextContains(CurrentMemoryContext,
|
!MemoryContextContains(CurrentMemoryContext,
|
||||||
DatumGetPointer(*result)))
|
DatumGetPointer(*result)))
|
||||||
*result = datumCopy(*result,
|
*result = datumCopy(*result,
|
||||||
|
@ -53,6 +53,7 @@ LLVMTypeRef TypeSizeT;
|
|||||||
LLVMTypeRef TypeParamBool;
|
LLVMTypeRef TypeParamBool;
|
||||||
LLVMTypeRef TypeStorageBool;
|
LLVMTypeRef TypeStorageBool;
|
||||||
LLVMTypeRef TypePGFunction;
|
LLVMTypeRef TypePGFunction;
|
||||||
|
LLVMTypeRef StructNullableDatum;
|
||||||
LLVMTypeRef StructHeapTupleFieldsField3;
|
LLVMTypeRef StructHeapTupleFieldsField3;
|
||||||
LLVMTypeRef StructHeapTupleFields;
|
LLVMTypeRef StructHeapTupleFields;
|
||||||
LLVMTypeRef StructHeapTupleHeaderData;
|
LLVMTypeRef StructHeapTupleHeaderData;
|
||||||
@ -807,6 +808,7 @@ llvm_create_types(void)
|
|||||||
TypeParamBool = load_return_type(mod, "FunctionReturningBool");
|
TypeParamBool = load_return_type(mod, "FunctionReturningBool");
|
||||||
TypeStorageBool = load_type(mod, "TypeStorageBool");
|
TypeStorageBool = load_type(mod, "TypeStorageBool");
|
||||||
TypePGFunction = load_type(mod, "TypePGFunction");
|
TypePGFunction = load_type(mod, "TypePGFunction");
|
||||||
|
StructNullableDatum = load_type(mod, "StructNullableDatum");
|
||||||
StructExprContext = load_type(mod, "StructExprContext");
|
StructExprContext = load_type(mod, "StructExprContext");
|
||||||
StructExprEvalStep = load_type(mod, "StructExprEvalStep");
|
StructExprEvalStep = load_type(mod, "StructExprEvalStep");
|
||||||
StructExprState = load_type(mod, "StructExprState");
|
StructExprState = load_type(mod, "StructExprState");
|
||||||
|
@ -570,7 +570,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMBasicBlockRef b_nonull;
|
LLVMBasicBlockRef b_nonull;
|
||||||
int argno;
|
int argno;
|
||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_argnullp;
|
|
||||||
LLVMBasicBlockRef *b_checkargnulls;
|
LLVMBasicBlockRef *b_checkargnulls;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -587,12 +586,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
v_fcinfo =
|
v_fcinfo =
|
||||||
l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
||||||
|
|
||||||
v_argnullp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set resnull to true, if the function is actually
|
* set resnull to true, if the function is actually
|
||||||
* called, it'll be reset
|
* called, it'll be reset
|
||||||
@ -624,8 +617,7 @@ llvm_compile_expr(ExprState *state)
|
|||||||
b_argnotnull = b_checkargnulls[argno + 1];
|
b_argnotnull = b_checkargnulls[argno + 1];
|
||||||
|
|
||||||
/* and finally load & check NULLness of arg */
|
/* and finally load & check NULLness of arg */
|
||||||
v_argisnull = l_load_struct_gep(b, v_argnullp,
|
v_argisnull = l_funcnull(b, v_fcinfo, argno);
|
||||||
argno, "");
|
|
||||||
LLVMBuildCondBr(b,
|
LLVMBuildCondBr(b,
|
||||||
LLVMBuildICmp(b, LLVMIntEQ,
|
LLVMBuildICmp(b, LLVMIntEQ,
|
||||||
v_argisnull,
|
v_argisnull,
|
||||||
@ -1276,10 +1268,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMValueRef v_fn_addr_out,
|
LLVMValueRef v_fn_addr_out,
|
||||||
v_fn_addr_in;
|
v_fn_addr_in;
|
||||||
LLVMValueRef v_fcinfo_in_isnullp;
|
LLVMValueRef v_fcinfo_in_isnullp;
|
||||||
LLVMValueRef v_in_argp,
|
|
||||||
v_out_argp;
|
|
||||||
LLVMValueRef v_in_argnullp,
|
|
||||||
v_out_argnullp;
|
|
||||||
LLVMValueRef v_retval;
|
LLVMValueRef v_retval;
|
||||||
LLVMValueRef v_resvalue;
|
LLVMValueRef v_resvalue;
|
||||||
LLVMValueRef v_resnull;
|
LLVMValueRef v_resnull;
|
||||||
@ -1313,22 +1301,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMBuildStructGEP(b, v_fcinfo_in,
|
LLVMBuildStructGEP(b, v_fcinfo_in,
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ISNULL,
|
FIELDNO_FUNCTIONCALLINFODATA_ISNULL,
|
||||||
"v_fcinfo_in_isnull");
|
"v_fcinfo_in_isnull");
|
||||||
v_out_argnullp =
|
|
||||||
LLVMBuildStructGEP(b, v_fcinfo_out,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_fcinfo_out_argnullp");
|
|
||||||
v_in_argnullp =
|
|
||||||
LLVMBuildStructGEP(b, v_fcinfo_in,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_fcinfo_in_argnullp");
|
|
||||||
v_out_argp =
|
|
||||||
LLVMBuildStructGEP(b, v_fcinfo_out,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARG,
|
|
||||||
"v_fcinfo_out_argp");
|
|
||||||
v_in_argp =
|
|
||||||
LLVMBuildStructGEP(b, v_fcinfo_in,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARG,
|
|
||||||
"v_fcinfo_in_argp");
|
|
||||||
|
|
||||||
/* output functions are not called on nulls */
|
/* output functions are not called on nulls */
|
||||||
v_resnull = LLVMBuildLoad(b, v_resnullp, "");
|
v_resnull = LLVMBuildLoad(b, v_resnullp, "");
|
||||||
@ -1348,11 +1320,10 @@ llvm_compile_expr(ExprState *state)
|
|||||||
/* set arg[0] */
|
/* set arg[0] */
|
||||||
LLVMBuildStore(b,
|
LLVMBuildStore(b,
|
||||||
v_resvalue,
|
v_resvalue,
|
||||||
LLVMBuildStructGEP(b, v_out_argp, 0, ""));
|
l_funcvaluep(b, v_fcinfo_out, 0));
|
||||||
LLVMBuildStore(b,
|
LLVMBuildStore(b,
|
||||||
l_sbool_const(0),
|
l_sbool_const(0),
|
||||||
LLVMBuildStructGEP(b, v_out_argnullp,
|
l_funcnullp(b, v_fcinfo_out, 0));
|
||||||
0, ""));
|
|
||||||
/* and call output function (can never return NULL) */
|
/* and call output function (can never return NULL) */
|
||||||
v_output = LLVMBuildCall(b, v_fn_addr_out, &v_fcinfo_out,
|
v_output = LLVMBuildCall(b, v_fn_addr_out, &v_fcinfo_out,
|
||||||
1, "funccall_coerce_out");
|
1, "funccall_coerce_out");
|
||||||
@ -1399,9 +1370,9 @@ llvm_compile_expr(ExprState *state)
|
|||||||
/* set arguments */
|
/* set arguments */
|
||||||
/* arg0: output */
|
/* arg0: output */
|
||||||
LLVMBuildStore(b, v_output,
|
LLVMBuildStore(b, v_output,
|
||||||
LLVMBuildStructGEP(b, v_in_argp, 0, ""));
|
l_funcvaluep(b, v_fcinfo_in, 0));
|
||||||
LLVMBuildStore(b, v_resnull,
|
LLVMBuildStore(b, v_resnull,
|
||||||
LLVMBuildStructGEP(b, v_in_argnullp, 0, ""));
|
l_funcnullp(b, v_fcinfo_in, 0));
|
||||||
|
|
||||||
/* arg1: ioparam: preset in execExpr.c */
|
/* arg1: ioparam: preset in execExpr.c */
|
||||||
/* arg2: typmod: preset in execExpr.c */
|
/* arg2: typmod: preset in execExpr.c */
|
||||||
@ -1426,7 +1397,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_fcinfo_isnull;
|
LLVMValueRef v_fcinfo_isnull;
|
||||||
|
|
||||||
LLVMValueRef v_argnullp;
|
|
||||||
LLVMValueRef v_argnull0,
|
LLVMValueRef v_argnull0,
|
||||||
v_argisnull0;
|
v_argisnull0;
|
||||||
LLVMValueRef v_argnull1,
|
LLVMValueRef v_argnull1,
|
||||||
@ -1449,18 +1419,11 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
||||||
|
|
||||||
v_argnullp =
|
/* load args[0|1].isnull for both arguments */
|
||||||
LLVMBuildStructGEP(b,
|
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
|
|
||||||
/* load argnull[0|1] for both arguments */
|
|
||||||
v_argnull0 = l_load_struct_gep(b, v_argnullp, 0, "");
|
|
||||||
v_argisnull0 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull0,
|
v_argisnull0 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull0,
|
||||||
l_sbool_const(1), "");
|
l_sbool_const(1), "");
|
||||||
|
v_argnull1 = l_funcnull(b, v_fcinfo, 1);
|
||||||
v_argnull1 = l_load_struct_gep(b, v_argnullp, 1, "");
|
|
||||||
v_argisnull1 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull1,
|
v_argisnull1 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull1,
|
||||||
l_sbool_const(1), "");
|
l_sbool_const(1), "");
|
||||||
|
|
||||||
@ -1532,11 +1495,9 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_fcinfo_isnull;
|
LLVMValueRef v_fcinfo_isnull;
|
||||||
LLVMValueRef v_argnullp;
|
|
||||||
LLVMValueRef v_argnull0;
|
LLVMValueRef v_argnull0;
|
||||||
LLVMValueRef v_argnull1;
|
LLVMValueRef v_argnull1;
|
||||||
LLVMValueRef v_anyargisnull;
|
LLVMValueRef v_anyargisnull;
|
||||||
LLVMValueRef v_argp;
|
|
||||||
LLVMValueRef v_arg0;
|
LLVMValueRef v_arg0;
|
||||||
LLVMBasicBlockRef b_hasnull;
|
LLVMBasicBlockRef b_hasnull;
|
||||||
LLVMBasicBlockRef b_nonull;
|
LLVMBasicBlockRef b_nonull;
|
||||||
@ -1553,21 +1514,9 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
|
||||||
|
|
||||||
v_argnullp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
|
|
||||||
v_argp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARG,
|
|
||||||
"v_argp");
|
|
||||||
|
|
||||||
/* if either argument is NULL they can't be equal */
|
/* if either argument is NULL they can't be equal */
|
||||||
v_argnull0 = l_load_struct_gep(b, v_argnullp, 0, "");
|
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
|
||||||
v_argnull1 = l_load_struct_gep(b, v_argnullp, 1, "");
|
v_argnull1 = l_funcnull(b, v_fcinfo, 1);
|
||||||
|
|
||||||
v_anyargisnull =
|
v_anyargisnull =
|
||||||
LLVMBuildOr(b,
|
LLVMBuildOr(b,
|
||||||
@ -1581,7 +1530,7 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
/* one (or both) of the arguments are null, return arg[0] */
|
/* one (or both) of the arguments are null, return arg[0] */
|
||||||
LLVMPositionBuilderAtEnd(b, b_hasnull);
|
LLVMPositionBuilderAtEnd(b, b_hasnull);
|
||||||
v_arg0 = l_load_struct_gep(b, v_argp, 0, "");
|
v_arg0 = l_funcvalue(b, v_fcinfo, 0);
|
||||||
LLVMBuildStore(b, v_argnull0, v_resnullp);
|
LLVMBuildStore(b, v_argnull0, v_resnullp);
|
||||||
LLVMBuildStore(b, v_arg0, v_resvaluep);
|
LLVMBuildStore(b, v_arg0, v_resvaluep);
|
||||||
LLVMBuildBr(b, opblocks[i + 1]);
|
LLVMBuildBr(b, opblocks[i + 1]);
|
||||||
@ -1680,7 +1629,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
if (op->d.rowcompare_step.finfo->fn_strict)
|
if (op->d.rowcompare_step.finfo->fn_strict)
|
||||||
{
|
{
|
||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_argnullp;
|
|
||||||
LLVMValueRef v_argnull0;
|
LLVMValueRef v_argnull0;
|
||||||
LLVMValueRef v_argnull1;
|
LLVMValueRef v_argnull1;
|
||||||
LLVMValueRef v_anyargisnull;
|
LLVMValueRef v_anyargisnull;
|
||||||
@ -1688,13 +1636,8 @@ llvm_compile_expr(ExprState *state)
|
|||||||
v_fcinfo = l_ptr_const(fcinfo,
|
v_fcinfo = l_ptr_const(fcinfo,
|
||||||
l_ptr(StructFunctionCallInfoData));
|
l_ptr(StructFunctionCallInfoData));
|
||||||
|
|
||||||
v_argnullp =
|
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
|
||||||
LLVMBuildStructGEP(b, v_fcinfo,
|
v_argnull1 = l_funcnull(b, v_fcinfo, 1);
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
|
|
||||||
v_argnull0 = l_load_struct_gep(b, v_argnullp, 0, "");
|
|
||||||
v_argnull1 = l_load_struct_gep(b, v_argnullp, 1, "");
|
|
||||||
|
|
||||||
v_anyargisnull =
|
v_anyargisnull =
|
||||||
LLVMBuildOr(b,
|
LLVMBuildOr(b,
|
||||||
@ -2021,7 +1964,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
{
|
{
|
||||||
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
|
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
|
||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_argnullp;
|
|
||||||
LLVMValueRef v_argnull0;
|
LLVMValueRef v_argnull0;
|
||||||
LLVMBasicBlockRef b_deserialize;
|
LLVMBasicBlockRef b_deserialize;
|
||||||
|
|
||||||
@ -2030,14 +1972,7 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
v_fcinfo = l_ptr_const(fcinfo,
|
v_fcinfo = l_ptr_const(fcinfo,
|
||||||
l_ptr(StructFunctionCallInfoData));
|
l_ptr(StructFunctionCallInfoData));
|
||||||
|
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
|
||||||
v_argnullp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
v_argnull0 =
|
|
||||||
l_load_struct_gep(b, v_argnullp, 0, "v_argnull0");
|
|
||||||
|
|
||||||
LLVMBuildCondBr(b,
|
LLVMBuildCondBr(b,
|
||||||
LLVMBuildICmp(b,
|
LLVMBuildICmp(b,
|
||||||
@ -2079,20 +2014,24 @@ llvm_compile_expr(ExprState *state)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EEOP_AGG_STRICT_INPUT_CHECK:
|
case EEOP_AGG_STRICT_INPUT_CHECK_NULLS:
|
||||||
|
case EEOP_AGG_STRICT_INPUT_CHECK_ARGS:
|
||||||
{
|
{
|
||||||
int nargs = op->d.agg_strict_input_check.nargs;
|
int nargs = op->d.agg_strict_input_check.nargs;
|
||||||
|
NullableDatum *args = op->d.agg_strict_input_check.args;
|
||||||
bool *nulls = op->d.agg_strict_input_check.nulls;
|
bool *nulls = op->d.agg_strict_input_check.nulls;
|
||||||
int jumpnull;
|
int jumpnull;
|
||||||
int argno;
|
int argno;
|
||||||
|
|
||||||
LLVMValueRef v_nullp;
|
LLVMValueRef v_argsp;
|
||||||
|
LLVMValueRef v_nullsp;
|
||||||
LLVMBasicBlockRef *b_checknulls;
|
LLVMBasicBlockRef *b_checknulls;
|
||||||
|
|
||||||
Assert(nargs > 0);
|
Assert(nargs > 0);
|
||||||
|
|
||||||
jumpnull = op->d.agg_strict_input_check.jumpnull;
|
jumpnull = op->d.agg_strict_input_check.jumpnull;
|
||||||
v_nullp = l_ptr_const(nulls, l_ptr(TypeStorageBool));
|
v_argsp = l_ptr_const(args, l_ptr(StructNullableDatum));
|
||||||
|
v_nullsp = l_ptr_const(nulls, l_ptr(TypeStorageBool));
|
||||||
|
|
||||||
/* create blocks for checking args */
|
/* create blocks for checking args */
|
||||||
b_checknulls = palloc(sizeof(LLVMBasicBlockRef *) * nargs);
|
b_checknulls = palloc(sizeof(LLVMBasicBlockRef *) * nargs);
|
||||||
@ -2120,7 +2059,18 @@ llvm_compile_expr(ExprState *state)
|
|||||||
else
|
else
|
||||||
b_argnotnull = b_checknulls[argno + 1];
|
b_argnotnull = b_checknulls[argno + 1];
|
||||||
|
|
||||||
v_argisnull = l_load_gep1(b, v_nullp, v_argno, "");
|
if (opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
|
||||||
|
v_argisnull = l_load_gep1(b, v_nullsp, v_argno, "");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLVMValueRef v_argn;
|
||||||
|
|
||||||
|
v_argn = LLVMBuildGEP(b, v_argsp, &v_argno, 1, "");
|
||||||
|
v_argisnull =
|
||||||
|
l_load_struct_gep(b, v_argn,
|
||||||
|
FIELDNO_NULLABLE_DATUM_ISNULL,
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
LLVMBuildCondBr(b,
|
LLVMBuildCondBr(b,
|
||||||
LLVMBuildICmp(b,
|
LLVMBuildICmp(b,
|
||||||
@ -2291,8 +2241,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMValueRef v_aggstatep;
|
LLVMValueRef v_aggstatep;
|
||||||
LLVMValueRef v_fcinfo;
|
LLVMValueRef v_fcinfo;
|
||||||
LLVMValueRef v_fcinfo_isnull;
|
LLVMValueRef v_fcinfo_isnull;
|
||||||
LLVMValueRef v_argp,
|
|
||||||
v_argnullp;
|
|
||||||
|
|
||||||
LLVMValueRef v_transvaluep;
|
LLVMValueRef v_transvaluep;
|
||||||
LLVMValueRef v_transnullp;
|
LLVMValueRef v_transnullp;
|
||||||
@ -2319,7 +2267,7 @@ llvm_compile_expr(ExprState *state)
|
|||||||
aggstate = op->d.agg_trans.aggstate;
|
aggstate = op->d.agg_trans.aggstate;
|
||||||
pertrans = op->d.agg_trans.pertrans;
|
pertrans = op->d.agg_trans.pertrans;
|
||||||
|
|
||||||
fcinfo = &pertrans->transfn_fcinfo;
|
fcinfo = pertrans->transfn_fcinfo;
|
||||||
|
|
||||||
v_aggstatep = l_ptr_const(aggstate,
|
v_aggstatep = l_ptr_const(aggstate,
|
||||||
l_ptr(StructAggState));
|
l_ptr(StructAggState));
|
||||||
@ -2344,18 +2292,6 @@ llvm_compile_expr(ExprState *state)
|
|||||||
|
|
||||||
v_fcinfo = l_ptr_const(fcinfo,
|
v_fcinfo = l_ptr_const(fcinfo,
|
||||||
l_ptr(StructFunctionCallInfoData));
|
l_ptr(StructFunctionCallInfoData));
|
||||||
|
|
||||||
v_argnullp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
|
|
||||||
"v_argnullp");
|
|
||||||
v_argp =
|
|
||||||
LLVMBuildStructGEP(b,
|
|
||||||
v_fcinfo,
|
|
||||||
FIELDNO_FUNCTIONCALLINFODATA_ARG,
|
|
||||||
"v_argp");
|
|
||||||
|
|
||||||
v_aggcontext = l_ptr_const(op->d.agg_trans.aggcontext,
|
v_aggcontext = l_ptr_const(op->d.agg_trans.aggcontext,
|
||||||
l_ptr(StructExprContext));
|
l_ptr(StructExprContext));
|
||||||
|
|
||||||
@ -2387,7 +2323,7 @@ llvm_compile_expr(ExprState *state)
|
|||||||
l_ptr(StructMemoryContextData));
|
l_ptr(StructMemoryContextData));
|
||||||
v_oldcontext = l_mcxt_switch(mod, b, v_tmpcontext);
|
v_oldcontext = l_mcxt_switch(mod, b, v_tmpcontext);
|
||||||
|
|
||||||
/* store transvalue in fcinfo->arg/argnull[0] */
|
/* store transvalue in fcinfo->args[0] */
|
||||||
v_transvaluep =
|
v_transvaluep =
|
||||||
LLVMBuildStructGEP(b, v_pergroupp,
|
LLVMBuildStructGEP(b, v_pergroupp,
|
||||||
FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE,
|
FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE,
|
||||||
@ -2399,10 +2335,10 @@ llvm_compile_expr(ExprState *state)
|
|||||||
LLVMBuildStore(b,
|
LLVMBuildStore(b,
|
||||||
LLVMBuildLoad(b, v_transvaluep,
|
LLVMBuildLoad(b, v_transvaluep,
|
||||||
"transvalue"),
|
"transvalue"),
|
||||||
LLVMBuildStructGEP(b, v_argp, 0, ""));
|
l_funcvaluep(b, v_fcinfo, 0));
|
||||||
LLVMBuildStore(b,
|
LLVMBuildStore(b,
|
||||||
LLVMBuildLoad(b, v_transnullp, "transnull"),
|
LLVMBuildLoad(b, v_transnullp, "transnull"),
|
||||||
LLVMBuildStructGEP(b, v_argnullp, 0, ""));
|
l_funcnullp(b, v_fcinfo, 0));
|
||||||
|
|
||||||
/* and invoke transition function */
|
/* and invoke transition function */
|
||||||
v_retval = BuildV1Call(context, b, mod, fcinfo,
|
v_retval = BuildV1Call(context, b, mod, fcinfo,
|
||||||
@ -2589,12 +2525,8 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
|
|||||||
LLVMValueRef v_lifetime = create_LifetimeEnd(mod);
|
LLVMValueRef v_lifetime = create_LifetimeEnd(mod);
|
||||||
LLVMValueRef params[2];
|
LLVMValueRef params[2];
|
||||||
|
|
||||||
params[0] = l_int64_const(sizeof(fcinfo->arg));
|
params[0] = l_int64_const(sizeof(NullableDatum) * fcinfo->nargs);
|
||||||
params[1] = l_ptr_const(fcinfo->arg, l_ptr(LLVMInt8Type()));
|
params[1] = l_ptr_const(fcinfo->args, l_ptr(LLVMInt8Type()));
|
||||||
LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
|
|
||||||
|
|
||||||
params[0] = l_int64_const(sizeof(fcinfo->argnull));
|
|
||||||
params[1] = l_ptr_const(fcinfo->argnull, l_ptr(LLVMInt8Type()));
|
|
||||||
LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
|
LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
|
||||||
|
|
||||||
params[0] = l_int64_const(sizeof(fcinfo->isnull));
|
params[0] = l_int64_const(sizeof(fcinfo->isnull));
|
||||||
|
@ -49,13 +49,14 @@ PGFunction TypePGFunction;
|
|||||||
size_t TypeSizeT;
|
size_t TypeSizeT;
|
||||||
bool TypeStorageBool;
|
bool TypeStorageBool;
|
||||||
|
|
||||||
|
NullableDatum StructNullableDatum;
|
||||||
AggState StructAggState;
|
AggState StructAggState;
|
||||||
AggStatePerGroupData StructAggStatePerGroupData;
|
AggStatePerGroupData StructAggStatePerGroupData;
|
||||||
AggStatePerTransData StructAggStatePerTransData;
|
AggStatePerTransData StructAggStatePerTransData;
|
||||||
ExprContext StructExprContext;
|
ExprContext StructExprContext;
|
||||||
ExprEvalStep StructExprEvalStep;
|
ExprEvalStep StructExprEvalStep;
|
||||||
ExprState StructExprState;
|
ExprState StructExprState;
|
||||||
FunctionCallInfoData StructFunctionCallInfoData;
|
FunctionCallInfoBaseData StructFunctionCallInfoData;
|
||||||
HeapTupleData StructHeapTupleData;
|
HeapTupleData StructHeapTupleData;
|
||||||
MemoryContextData StructMemoryContextData;
|
MemoryContextData StructMemoryContextData;
|
||||||
TupleTableSlot StructTupleTableSlot;
|
TupleTableSlot StructTupleTableSlot;
|
||||||
|
@ -1581,7 +1581,7 @@ pgstat_send_inquiry(TimestampTz clock_time, TimestampTz cutoff_time, Oid databas
|
|||||||
* Called by the executor before invoking a function.
|
* Called by the executor before invoking a function.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pgstat_init_function_usage(FunctionCallInfoData *fcinfo,
|
pgstat_init_function_usage(FunctionCallInfo fcinfo,
|
||||||
PgStat_FunctionCallUsage *fcu)
|
PgStat_FunctionCallUsage *fcu)
|
||||||
{
|
{
|
||||||
PgStat_BackendFunctionEntry *htabent;
|
PgStat_BackendFunctionEntry *htabent;
|
||||||
|
@ -258,9 +258,9 @@ fetch_fp_info(Oid func_id, struct fp_info *fip)
|
|||||||
void
|
void
|
||||||
HandleFunctionRequest(StringInfo msgBuf)
|
HandleFunctionRequest(StringInfo msgBuf)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
|
||||||
Oid fid;
|
Oid fid;
|
||||||
AclResult aclresult;
|
AclResult aclresult;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
int16 rformat;
|
int16 rformat;
|
||||||
Datum retval;
|
Datum retval;
|
||||||
struct fp_info my_fp;
|
struct fp_info my_fp;
|
||||||
@ -332,12 +332,12 @@ HandleFunctionRequest(StringInfo msgBuf)
|
|||||||
* functions can't be called this way. Perhaps we should pass
|
* functions can't be called this way. Perhaps we should pass
|
||||||
* DEFAULT_COLLATION_OID, instead?
|
* DEFAULT_COLLATION_OID, instead?
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
|
InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
|
||||||
|
|
||||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
|
||||||
rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
|
rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
|
||||||
else
|
else
|
||||||
rformat = parse_fcall_arguments_20(msgBuf, fip, &fcinfo);
|
rformat = parse_fcall_arguments_20(msgBuf, fip, fcinfo);
|
||||||
|
|
||||||
/* Verify we reached the end of the message where expected. */
|
/* Verify we reached the end of the message where expected. */
|
||||||
pq_getmsgend(msgBuf);
|
pq_getmsgend(msgBuf);
|
||||||
@ -350,9 +350,9 @@ HandleFunctionRequest(StringInfo msgBuf)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < fcinfo.nargs; i++)
|
for (i = 0; i < fcinfo->nargs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo.argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
{
|
{
|
||||||
callit = false;
|
callit = false;
|
||||||
break;
|
break;
|
||||||
@ -363,18 +363,18 @@ HandleFunctionRequest(StringInfo msgBuf)
|
|||||||
if (callit)
|
if (callit)
|
||||||
{
|
{
|
||||||
/* Okay, do it ... */
|
/* Okay, do it ... */
|
||||||
retval = FunctionCallInvoke(&fcinfo);
|
retval = FunctionCallInvoke(fcinfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fcinfo.isnull = true;
|
fcinfo->isnull = true;
|
||||||
retval = (Datum) 0;
|
retval = (Datum) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
|
/* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
|
||||||
CHECK_FOR_INTERRUPTS();
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
|
SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat);
|
||||||
|
|
||||||
/* We no longer need the snapshot */
|
/* We no longer need the snapshot */
|
||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
@ -450,11 +450,11 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
|
|||||||
argsize = pq_getmsgint(msgBuf, 4);
|
argsize = pq_getmsgint(msgBuf, 4);
|
||||||
if (argsize == -1)
|
if (argsize == -1)
|
||||||
{
|
{
|
||||||
fcinfo->argnull[i] = true;
|
fcinfo->args[i].isnull = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fcinfo->argnull[i] = false;
|
fcinfo->args[i].isnull = false;
|
||||||
if (argsize < 0)
|
if (argsize < 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
||||||
@ -494,7 +494,7 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
|
|||||||
else
|
else
|
||||||
pstring = pg_client_to_server(abuf.data, argsize);
|
pstring = pg_client_to_server(abuf.data, argsize);
|
||||||
|
|
||||||
fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
|
fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring,
|
||||||
typioparam, -1);
|
typioparam, -1);
|
||||||
/* Free result of encoding conversion, if any */
|
/* Free result of encoding conversion, if any */
|
||||||
if (pstring && pstring != abuf.data)
|
if (pstring && pstring != abuf.data)
|
||||||
@ -514,7 +514,7 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
|
|||||||
else
|
else
|
||||||
bufptr = &abuf;
|
bufptr = &abuf;
|
||||||
|
|
||||||
fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
|
fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr,
|
||||||
typioparam, -1);
|
typioparam, -1);
|
||||||
|
|
||||||
/* Trouble if it didn't eat the whole buffer */
|
/* Trouble if it didn't eat the whole buffer */
|
||||||
@ -579,12 +579,12 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
|
|||||||
argsize = pq_getmsgint(msgBuf, 4);
|
argsize = pq_getmsgint(msgBuf, 4);
|
||||||
if (argsize == -1)
|
if (argsize == -1)
|
||||||
{
|
{
|
||||||
fcinfo->argnull[i] = true;
|
fcinfo->args[i].isnull = true;
|
||||||
fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
|
fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL,
|
||||||
typioparam, -1);
|
typioparam, -1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fcinfo->argnull[i] = false;
|
fcinfo->args[i].isnull = false;
|
||||||
if (argsize < 0)
|
if (argsize < 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
(errcode(ERRCODE_PROTOCOL_VIOLATION),
|
||||||
@ -597,7 +597,7 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
|
|||||||
pq_getmsgbytes(msgBuf, argsize),
|
pq_getmsgbytes(msgBuf, argsize),
|
||||||
argsize);
|
argsize);
|
||||||
|
|
||||||
fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
|
fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf,
|
||||||
typioparam, -1);
|
typioparam, -1);
|
||||||
|
|
||||||
/* Trouble if it didn't eat the whole buffer */
|
/* Trouble if it didn't eat the whole buffer */
|
||||||
|
@ -3571,6 +3571,7 @@ array_contains_nulls(ArrayType *array)
|
|||||||
Datum
|
Datum
|
||||||
array_eq(PG_FUNCTION_ARGS)
|
array_eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
|
AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
|
||||||
AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
|
AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
|
||||||
Oid collation = PG_GET_COLLATION();
|
Oid collation = PG_GET_COLLATION();
|
||||||
@ -3590,7 +3591,6 @@ array_eq(PG_FUNCTION_ARGS)
|
|||||||
array_iter it1;
|
array_iter it1;
|
||||||
array_iter it2;
|
array_iter it2;
|
||||||
int i;
|
int i;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
if (element_type != AARR_ELEMTYPE(array2))
|
if (element_type != AARR_ELEMTYPE(array2))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -3630,7 +3630,7 @@ array_eq(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* apply the operator to each pair of array elements.
|
* apply the operator to each pair of array elements.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
@ -3666,12 +3666,12 @@ array_eq(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Apply the operator to the element pair
|
* Apply the operator to the element pair
|
||||||
*/
|
*/
|
||||||
locfcinfo.arg[0] = elt1;
|
locfcinfo->args[0].value = elt1;
|
||||||
locfcinfo.arg[1] = elt2;
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = elt2;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
|
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
|
||||||
if (!oprresult)
|
if (!oprresult)
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
@ -3742,6 +3742,7 @@ btarraycmp(PG_FUNCTION_ARGS)
|
|||||||
static int
|
static int
|
||||||
array_cmp(FunctionCallInfo fcinfo)
|
array_cmp(FunctionCallInfo fcinfo)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
|
AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
|
||||||
AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
|
AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
|
||||||
Oid collation = PG_GET_COLLATION();
|
Oid collation = PG_GET_COLLATION();
|
||||||
@ -3761,7 +3762,6 @@ array_cmp(FunctionCallInfo fcinfo)
|
|||||||
array_iter it1;
|
array_iter it1;
|
||||||
array_iter it2;
|
array_iter it2;
|
||||||
int i;
|
int i;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
if (element_type != AARR_ELEMTYPE(array2))
|
if (element_type != AARR_ELEMTYPE(array2))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -3794,7 +3794,7 @@ array_cmp(FunctionCallInfo fcinfo)
|
|||||||
/*
|
/*
|
||||||
* apply the operator to each pair of array elements.
|
* apply the operator to each pair of array elements.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
@ -3833,12 +3833,12 @@ array_cmp(FunctionCallInfo fcinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compare the pair of elements */
|
/* Compare the pair of elements */
|
||||||
locfcinfo.arg[0] = elt1;
|
locfcinfo->args[0].value = elt1;
|
||||||
locfcinfo.arg[1] = elt2;
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = elt2;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
|
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
|
||||||
|
|
||||||
if (cmpresult == 0)
|
if (cmpresult == 0)
|
||||||
continue; /* equal */
|
continue; /* equal */
|
||||||
@ -3913,6 +3913,7 @@ array_cmp(FunctionCallInfo fcinfo)
|
|||||||
Datum
|
Datum
|
||||||
hash_array(PG_FUNCTION_ARGS)
|
hash_array(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 1);
|
||||||
AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
|
AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
|
||||||
int ndims = AARR_NDIM(array);
|
int ndims = AARR_NDIM(array);
|
||||||
int *dims = AARR_DIMS(array);
|
int *dims = AARR_DIMS(array);
|
||||||
@ -3925,7 +3926,6 @@ hash_array(PG_FUNCTION_ARGS)
|
|||||||
char typalign;
|
char typalign;
|
||||||
int i;
|
int i;
|
||||||
array_iter iter;
|
array_iter iter;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We arrange to look up the hash function only once per series of calls,
|
* We arrange to look up the hash function only once per series of calls,
|
||||||
@ -3953,7 +3953,7 @@ hash_array(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* apply the hash function to each array element.
|
* apply the hash function to each array element.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->hash_proc_finfo, 1,
|
||||||
InvalidOid, NULL, NULL);
|
InvalidOid, NULL, NULL);
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
@ -3977,10 +3977,10 @@ hash_array(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Apply the hash function */
|
/* Apply the hash function */
|
||||||
locfcinfo.arg[0] = elt;
|
locfcinfo->args[0].value = elt;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
elthash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
|
elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4010,6 +4010,7 @@ hash_array(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
hash_array_extended(PG_FUNCTION_ARGS)
|
hash_array_extended(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
|
AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
|
||||||
uint64 seed = PG_GETARG_INT64(1);
|
uint64 seed = PG_GETARG_INT64(1);
|
||||||
int ndims = AARR_NDIM(array);
|
int ndims = AARR_NDIM(array);
|
||||||
@ -4023,7 +4024,6 @@ hash_array_extended(PG_FUNCTION_ARGS)
|
|||||||
char typalign;
|
char typalign;
|
||||||
int i;
|
int i;
|
||||||
array_iter iter;
|
array_iter iter;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
||||||
if (typentry == NULL ||
|
if (typentry == NULL ||
|
||||||
@ -4042,7 +4042,7 @@ hash_array_extended(PG_FUNCTION_ARGS)
|
|||||||
typbyval = typentry->typbyval;
|
typbyval = typentry->typbyval;
|
||||||
typalign = typentry->typalign;
|
typalign = typentry->typalign;
|
||||||
|
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->hash_extended_proc_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
|
||||||
InvalidOid, NULL, NULL);
|
InvalidOid, NULL, NULL);
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
@ -4065,12 +4065,11 @@ hash_array_extended(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Apply the hash function */
|
/* Apply the hash function */
|
||||||
locfcinfo.arg[0] = elt;
|
locfcinfo->args[0].value = elt;
|
||||||
locfcinfo.arg[1] = Int64GetDatum(seed);
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = Int64GetDatum(seed);
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
|
||||||
elthash = DatumGetUInt64(FunctionCallInvoke(&locfcinfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (result << 5) - result + elthash;
|
result = (result << 5) - result + elthash;
|
||||||
@ -4100,6 +4099,7 @@ static bool
|
|||||||
array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
|
array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
|
||||||
bool matchall, void **fn_extra)
|
bool matchall, void **fn_extra)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
bool result = matchall;
|
bool result = matchall;
|
||||||
Oid element_type = AARR_ELEMTYPE(array1);
|
Oid element_type = AARR_ELEMTYPE(array1);
|
||||||
TypeCacheEntry *typentry;
|
TypeCacheEntry *typentry;
|
||||||
@ -4113,7 +4113,6 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
|
|||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
array_iter it1;
|
array_iter it1;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
if (element_type != AARR_ELEMTYPE(array2))
|
if (element_type != AARR_ELEMTYPE(array2))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -4164,7 +4163,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
|
|||||||
/*
|
/*
|
||||||
* Apply the comparison operator to each pair of array elements.
|
* Apply the comparison operator to each pair of array elements.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Loop over source data */
|
/* Loop over source data */
|
||||||
@ -4206,12 +4205,12 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
|
|||||||
/*
|
/*
|
||||||
* Apply the operator to the element pair
|
* Apply the operator to the element pair
|
||||||
*/
|
*/
|
||||||
locfcinfo.arg[0] = elt1;
|
locfcinfo->args[0].value = elt1;
|
||||||
locfcinfo.arg[1] = elt2;
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = elt2;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
|
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
|
||||||
if (oprresult)
|
if (oprresult)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6042,6 +6041,7 @@ array_replace_internal(ArrayType *array,
|
|||||||
bool remove, Oid collation,
|
bool remove, Oid collation,
|
||||||
FunctionCallInfo fcinfo)
|
FunctionCallInfo fcinfo)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
ArrayType *result;
|
ArrayType *result;
|
||||||
Oid element_type;
|
Oid element_type;
|
||||||
Datum *values;
|
Datum *values;
|
||||||
@ -6062,7 +6062,6 @@ array_replace_internal(ArrayType *array,
|
|||||||
int bitmask;
|
int bitmask;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
TypeCacheEntry *typentry;
|
TypeCacheEntry *typentry;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
element_type = ARR_ELEMTYPE(array);
|
element_type = ARR_ELEMTYPE(array);
|
||||||
ndim = ARR_NDIM(array);
|
ndim = ARR_NDIM(array);
|
||||||
@ -6117,7 +6116,7 @@ array_replace_internal(ArrayType *array,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare to apply the comparison operator */
|
/* Prepare to apply the comparison operator */
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Allocate temporary arrays for new values */
|
/* Allocate temporary arrays for new values */
|
||||||
@ -6175,12 +6174,12 @@ array_replace_internal(ArrayType *array,
|
|||||||
/*
|
/*
|
||||||
* Apply the operator to the element pair
|
* Apply the operator to the element pair
|
||||||
*/
|
*/
|
||||||
locfcinfo.arg[0] = elt;
|
locfcinfo->args[0].value = elt;
|
||||||
locfcinfo.arg[1] = search;
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = search;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
|
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
|
||||||
if (!oprresult)
|
if (!oprresult)
|
||||||
{
|
{
|
||||||
/* no match, keep element */
|
/* no match, keep element */
|
||||||
@ -6457,10 +6456,10 @@ width_bucket_array_fixed(Datum operand,
|
|||||||
Oid collation,
|
Oid collation,
|
||||||
TypeCacheEntry *typentry)
|
TypeCacheEntry *typentry)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
char *thresholds_data;
|
char *thresholds_data;
|
||||||
int typlen = typentry->typlen;
|
int typlen = typentry->typlen;
|
||||||
bool typbyval = typentry->typbyval;
|
bool typbyval = typentry->typbyval;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
|
||||||
@ -6470,7 +6469,7 @@ width_bucket_array_fixed(Datum operand,
|
|||||||
*/
|
*/
|
||||||
thresholds_data = (char *) ARR_DATA_PTR(thresholds);
|
thresholds_data = (char *) ARR_DATA_PTR(thresholds);
|
||||||
|
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Find the bucket */
|
/* Find the bucket */
|
||||||
@ -6484,13 +6483,13 @@ width_bucket_array_fixed(Datum operand,
|
|||||||
|
|
||||||
ptr = thresholds_data + mid * typlen;
|
ptr = thresholds_data + mid * typlen;
|
||||||
|
|
||||||
locfcinfo.arg[0] = operand;
|
locfcinfo->args[0].value = operand;
|
||||||
locfcinfo.arg[1] = fetch_att(ptr, typbyval, typlen);
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
|
|
||||||
cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
|
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
|
||||||
|
|
||||||
if (cmpresult < 0)
|
if (cmpresult < 0)
|
||||||
right = mid;
|
right = mid;
|
||||||
@ -6510,17 +6509,17 @@ width_bucket_array_variable(Datum operand,
|
|||||||
Oid collation,
|
Oid collation,
|
||||||
TypeCacheEntry *typentry)
|
TypeCacheEntry *typentry)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
char *thresholds_data;
|
char *thresholds_data;
|
||||||
int typlen = typentry->typlen;
|
int typlen = typentry->typlen;
|
||||||
bool typbyval = typentry->typbyval;
|
bool typbyval = typentry->typbyval;
|
||||||
char typalign = typentry->typalign;
|
char typalign = typentry->typalign;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
|
|
||||||
thresholds_data = (char *) ARR_DATA_PTR(thresholds);
|
thresholds_data = (char *) ARR_DATA_PTR(thresholds);
|
||||||
|
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
|
|
||||||
/* Find the bucket */
|
/* Find the bucket */
|
||||||
@ -6541,13 +6540,12 @@ width_bucket_array_variable(Datum operand,
|
|||||||
ptr = (char *) att_align_nominal(ptr, typalign);
|
ptr = (char *) att_align_nominal(ptr, typalign);
|
||||||
}
|
}
|
||||||
|
|
||||||
locfcinfo.arg[0] = operand;
|
locfcinfo->args[0].value = operand;
|
||||||
locfcinfo.arg[1] = fetch_att(ptr, typbyval, typlen);
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
|
||||||
|
|
||||||
cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
|
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
|
||||||
|
|
||||||
if (cmpresult < 0)
|
if (cmpresult < 0)
|
||||||
right = mid;
|
right = mid;
|
||||||
|
@ -201,8 +201,8 @@ int2vectorout(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
int2vectorrecv(PG_FUNCTION_ARGS)
|
int2vectorrecv(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 3);
|
||||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
int2vector *result;
|
int2vector *result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -211,19 +211,19 @@ int2vectorrecv(PG_FUNCTION_ARGS)
|
|||||||
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
|
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
|
||||||
* parameter.
|
* parameter.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
|
InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
|
||||||
InvalidOid, NULL, NULL);
|
InvalidOid, NULL, NULL);
|
||||||
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(buf);
|
locfcinfo->args[0].value = PointerGetDatum(buf);
|
||||||
locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.arg[2] = Int32GetDatum(-1);
|
locfcinfo->args[1].value = ObjectIdGetDatum(INT2OID);
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[2].value = Int32GetDatum(-1);
|
||||||
locfcinfo.argnull[2] = false;
|
locfcinfo->args[2].isnull = false;
|
||||||
|
|
||||||
result = (int2vector *) DatumGetPointer(array_recv(&locfcinfo));
|
result = (int2vector *) DatumGetPointer(array_recv(locfcinfo));
|
||||||
|
|
||||||
Assert(!locfcinfo.isnull);
|
Assert(!locfcinfo->isnull);
|
||||||
|
|
||||||
/* sanity checks: int2vector must be 1-D, 0-based, no nulls */
|
/* sanity checks: int2vector must be 1-D, 0-based, no nulls */
|
||||||
if (ARR_NDIM(result) != 1 ||
|
if (ARR_NDIM(result) != 1 ||
|
||||||
|
@ -256,8 +256,8 @@ oidvectorout(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
oidvectorrecv(PG_FUNCTION_ARGS)
|
oidvectorrecv(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 3);
|
||||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
oidvector *result;
|
oidvector *result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -266,19 +266,19 @@ oidvectorrecv(PG_FUNCTION_ARGS)
|
|||||||
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
|
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
|
||||||
* parameter.
|
* parameter.
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
|
InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
|
||||||
InvalidOid, NULL, NULL);
|
InvalidOid, NULL, NULL);
|
||||||
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(buf);
|
locfcinfo->args[0].value = PointerGetDatum(buf);
|
||||||
locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.arg[2] = Int32GetDatum(-1);
|
locfcinfo->args[1].value = ObjectIdGetDatum(OIDOID);
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[2].value = Int32GetDatum(-1);
|
||||||
locfcinfo.argnull[2] = false;
|
locfcinfo->args[2].isnull = false;
|
||||||
|
|
||||||
result = (oidvector *) DatumGetPointer(array_recv(&locfcinfo));
|
result = (oidvector *) DatumGetPointer(array_recv(locfcinfo));
|
||||||
|
|
||||||
Assert(!locfcinfo.isnull);
|
Assert(!locfcinfo->isnull);
|
||||||
|
|
||||||
/* sanity checks: oidvector must be 1-D, 0-based, no nulls */
|
/* sanity checks: oidvector must be 1-D, 0-based, no nulls */
|
||||||
if (ARR_NDIM(result) != 1 ||
|
if (ARR_NDIM(result) != 1 ||
|
||||||
|
@ -942,7 +942,7 @@ record_cmp(FunctionCallInfo fcinfo)
|
|||||||
*/
|
*/
|
||||||
if (!nulls1[i1] || !nulls2[i2])
|
if (!nulls1[i1] || !nulls2[i2])
|
||||||
{
|
{
|
||||||
FunctionCallInfoData locfcinfo;
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
int32 cmpresult;
|
int32 cmpresult;
|
||||||
|
|
||||||
if (nulls1[i1])
|
if (nulls1[i1])
|
||||||
@ -959,14 +959,14 @@ record_cmp(FunctionCallInfo fcinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compare the pair of elements */
|
/* Compare the pair of elements */
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
locfcinfo.arg[0] = values1[i1];
|
locfcinfo->args[0].value = values1[i1];
|
||||||
locfcinfo.arg[1] = values2[i2];
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = values2[i2];
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
|
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
|
||||||
|
|
||||||
if (cmpresult < 0)
|
if (cmpresult < 0)
|
||||||
{
|
{
|
||||||
@ -1119,11 +1119,11 @@ record_eq(PG_FUNCTION_ARGS)
|
|||||||
i1 = i2 = j = 0;
|
i1 = i2 = j = 0;
|
||||||
while (i1 < ncolumns1 || i2 < ncolumns2)
|
while (i1 < ncolumns1 || i2 < ncolumns2)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(locfcinfo, 2);
|
||||||
Form_pg_attribute att1;
|
Form_pg_attribute att1;
|
||||||
Form_pg_attribute att2;
|
Form_pg_attribute att2;
|
||||||
TypeCacheEntry *typentry;
|
TypeCacheEntry *typentry;
|
||||||
Oid collation;
|
Oid collation;
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
bool oprresult;
|
bool oprresult;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1193,14 +1193,14 @@ record_eq(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compare the pair of elements */
|
/* Compare the pair of elements */
|
||||||
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
|
InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
|
||||||
collation, NULL, NULL);
|
collation, NULL, NULL);
|
||||||
locfcinfo.arg[0] = values1[i1];
|
locfcinfo->args[0].value = values1[i1];
|
||||||
locfcinfo.arg[1] = values2[i2];
|
locfcinfo->args[0].isnull = false;
|
||||||
locfcinfo.argnull[0] = false;
|
locfcinfo->args[1].value = values2[i2];
|
||||||
locfcinfo.argnull[1] = false;
|
locfcinfo->args[1].isnull = false;
|
||||||
locfcinfo.isnull = false;
|
locfcinfo->isnull = false;
|
||||||
oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
|
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
|
||||||
if (!oprresult)
|
if (!oprresult)
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
@ -53,7 +53,7 @@ point to the expression parse tree for the function call; this can be used
|
|||||||
to extract parse-time knowledge about the actual arguments. Note that this
|
to extract parse-time knowledge about the actual arguments. Note that this
|
||||||
field really is information about the arguments rather than information
|
field really is information about the arguments rather than information
|
||||||
about the function, but it's proven to be more convenient to keep it in
|
about the function, but it's proven to be more convenient to keep it in
|
||||||
FmgrInfo than in FunctionCallInfoData where it might more logically go.
|
FmgrInfo than in FunctionCallInfoBaseData where it might more logically go.
|
||||||
|
|
||||||
|
|
||||||
During a call of a function, the following data structure is created
|
During a call of a function, the following data structure is created
|
||||||
@ -67,10 +67,9 @@ typedef struct
|
|||||||
Oid fncollation; /* collation for function to use */
|
Oid fncollation; /* collation for function to use */
|
||||||
bool isnull; /* function must set true if result is NULL */
|
bool isnull; /* function must set true if result is NULL */
|
||||||
short nargs; /* # arguments actually passed */
|
short nargs; /* # arguments actually passed */
|
||||||
Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
|
NullableDatum args[]; /* Arguments passed to function */
|
||||||
bool argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */
|
} FunctionCallInfoBaseData;
|
||||||
} FunctionCallInfoData;
|
typedef FunctionCallInfoBaseData* FunctionCallInfo;
|
||||||
typedef FunctionCallInfoData* FunctionCallInfo;
|
|
||||||
|
|
||||||
flinfo points to the lookup info used to make the call. Ordinary functions
|
flinfo points to the lookup info used to make the call. Ordinary functions
|
||||||
will probably ignore this field, but function class handlers will need it
|
will probably ignore this field, but function class handlers will need it
|
||||||
@ -97,24 +96,24 @@ when there are no inputs of collatable types or they don't share a common
|
|||||||
collation. This is effectively a hidden additional argument, which
|
collation. This is effectively a hidden additional argument, which
|
||||||
collation-sensitive functions can use to determine their behavior.
|
collation-sensitive functions can use to determine their behavior.
|
||||||
|
|
||||||
nargs, arg[], and argnull[] hold the arguments being passed to the function.
|
nargs and args[] hold the arguments being passed to the function.
|
||||||
Notice that all the arguments passed to a function (as well as its result
|
Notice that all the arguments passed to a function (as well as its result
|
||||||
value) will now uniformly be of type Datum. As discussed below, callers
|
value) will now uniformly be of type Datum. As discussed below, callers
|
||||||
and callees should apply the standard Datum-to-and-from-whatever macros
|
and callees should apply the standard Datum-to-and-from-whatever macros
|
||||||
to convert to the actual argument types of a particular function. The
|
to convert to the actual argument types of a particular function. The
|
||||||
value in arg[i] is unspecified when argnull[i] is true.
|
value in args[i].value is unspecified when args[i].isnull is true.
|
||||||
|
|
||||||
It is generally the responsibility of the caller to ensure that the
|
It is generally the responsibility of the caller to ensure that the
|
||||||
number of arguments passed matches what the callee is expecting; except
|
number of arguments passed matches what the callee is expecting; except
|
||||||
for callees that take a variable number of arguments, the callee will
|
for callees that take a variable number of arguments, the callee will
|
||||||
typically ignore the nargs field and just grab values from arg[].
|
typically ignore the nargs field and just grab values from args[].
|
||||||
|
|
||||||
The isnull field will be initialized to "false" before the call. On
|
The isnull field will be initialized to "false" before the call. On
|
||||||
return from the function, isnull is the null flag for the function result:
|
return from the function, isnull is the null flag for the function result:
|
||||||
if it is true the function's result is NULL, regardless of the actual
|
if it is true the function's result is NULL, regardless of the actual
|
||||||
function return value. Note that simple "strict" functions can ignore
|
function return value. Note that simple "strict" functions can ignore
|
||||||
both isnull and argnull[], since they won't even get called when there
|
both isnull and args[i].isnull, since they won't even get called when there
|
||||||
are any TRUE values in argnull[].
|
are any TRUE values in args[].isnull.
|
||||||
|
|
||||||
FunctionCallInfo replaces FmgrValues plus a bunch of ad-hoc parameter
|
FunctionCallInfo replaces FmgrValues plus a bunch of ad-hoc parameter
|
||||||
conventions, global variables (fmgr_pl_finfo and CurrentTriggerData at
|
conventions, global variables (fmgr_pl_finfo and CurrentTriggerData at
|
||||||
@ -157,7 +156,7 @@ again, it might come in handy to have this macro in place.
|
|||||||
|
|
||||||
A nonstrict function is responsible for checking whether each individual
|
A nonstrict function is responsible for checking whether each individual
|
||||||
argument is null or not, which it can do with PG_ARGISNULL(n) (which is
|
argument is null or not, which it can do with PG_ARGISNULL(n) (which is
|
||||||
just "fcinfo->argnull[n]"). It should avoid trying to fetch the value
|
just "fcinfo->args[n].isnull"). It should avoid trying to fetch the value
|
||||||
of any argument that is null.
|
of any argument that is null.
|
||||||
|
|
||||||
Both strict and nonstrict functions can return NULL, if needed, with
|
Both strict and nonstrict functions can return NULL, if needed, with
|
||||||
@ -171,7 +170,7 @@ Argument values are ordinarily fetched using code like
|
|||||||
For float4, float8, and int8, the PG_GETARG macros will hide whether the
|
For float4, float8, and int8, the PG_GETARG macros will hide whether the
|
||||||
types are pass-by-value or pass-by-reference. For example, if float8 is
|
types are pass-by-value or pass-by-reference. For example, if float8 is
|
||||||
pass-by-reference then PG_GETARG_FLOAT8 expands to
|
pass-by-reference then PG_GETARG_FLOAT8 expands to
|
||||||
(* (float8 *) DatumGetPointer(fcinfo->arg[number]))
|
(* (float8 *) DatumGetPointer(fcinfo->args[number].value))
|
||||||
and would typically be called like this:
|
and would typically be called like this:
|
||||||
float8 arg = PG_GETARG_FLOAT8(0);
|
float8 arg = PG_GETARG_FLOAT8(0);
|
||||||
For what are now historical reasons, the float-related typedefs and macros
|
For what are now historical reasons, the float-related typedefs and macros
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,16 +26,17 @@
|
|||||||
/* Info needed to use an old-style comparison function as a sort comparator */
|
/* Info needed to use an old-style comparison function as a sort comparator */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fcinfo; /* reusable callinfo structure */
|
|
||||||
FmgrInfo flinfo; /* lookup data for comparison function */
|
FmgrInfo flinfo; /* lookup data for comparison function */
|
||||||
|
FunctionCallInfoBaseData fcinfo; /* reusable callinfo structure */
|
||||||
} SortShimExtra;
|
} SortShimExtra;
|
||||||
|
|
||||||
|
#define SizeForSortShimExtra(nargs) (offsetof(SortShimExtra, fcinfo) + SizeForFunctionCallInfo(nargs))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shim function for calling an old-style comparator
|
* Shim function for calling an old-style comparator
|
||||||
*
|
*
|
||||||
* This is essentially an inlined version of FunctionCall2Coll(), except
|
* This is essentially an inlined version of FunctionCall2Coll(), except
|
||||||
* we assume that the FunctionCallInfoData was already mostly set up by
|
* we assume that the FunctionCallInfoBaseData was already mostly set up by
|
||||||
* PrepareSortSupportComparisonShim.
|
* PrepareSortSupportComparisonShim.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@ -44,8 +45,8 @@ comparison_shim(Datum x, Datum y, SortSupport ssup)
|
|||||||
SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
|
SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
extra->fcinfo.arg[0] = x;
|
extra->fcinfo.args[0].value = x;
|
||||||
extra->fcinfo.arg[1] = y;
|
extra->fcinfo.args[1].value = y;
|
||||||
|
|
||||||
/* just for paranoia's sake, we reset isnull each time */
|
/* just for paranoia's sake, we reset isnull each time */
|
||||||
extra->fcinfo.isnull = false;
|
extra->fcinfo.isnull = false;
|
||||||
@ -69,7 +70,7 @@ PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
|
|||||||
SortShimExtra *extra;
|
SortShimExtra *extra;
|
||||||
|
|
||||||
extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
|
extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
|
||||||
sizeof(SortShimExtra));
|
SizeForSortShimExtra(2));
|
||||||
|
|
||||||
/* Lookup the comparison function */
|
/* Lookup the comparison function */
|
||||||
fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
|
fmgr_info_cxt(cmpFunc, &extra->flinfo, ssup->ssup_cxt);
|
||||||
@ -77,8 +78,8 @@ PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
|
|||||||
/* We can initialize the callinfo just once and re-use it */
|
/* We can initialize the callinfo just once and re-use it */
|
||||||
InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
|
InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
|
||||||
ssup->ssup_collation, NULL, NULL);
|
ssup->ssup_collation, NULL, NULL);
|
||||||
extra->fcinfo.argnull[0] = false;
|
extra->fcinfo.args[0].isnull = false;
|
||||||
extra->fcinfo.argnull[1] = false;
|
extra->fcinfo.args[1].isnull = false;
|
||||||
|
|
||||||
ssup->ssup_extra = extra;
|
ssup->ssup_extra = extra;
|
||||||
ssup->comparator = comparison_shim;
|
ssup->comparator = comparison_shim;
|
||||||
|
@ -223,7 +223,8 @@ typedef enum ExprEvalOp
|
|||||||
/* aggregation related nodes */
|
/* aggregation related nodes */
|
||||||
EEOP_AGG_STRICT_DESERIALIZE,
|
EEOP_AGG_STRICT_DESERIALIZE,
|
||||||
EEOP_AGG_DESERIALIZE,
|
EEOP_AGG_DESERIALIZE,
|
||||||
EEOP_AGG_STRICT_INPUT_CHECK,
|
EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
|
||||||
|
EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
|
||||||
EEOP_AGG_INIT_TRANS,
|
EEOP_AGG_INIT_TRANS,
|
||||||
EEOP_AGG_STRICT_TRANS_CHECK,
|
EEOP_AGG_STRICT_TRANS_CHECK,
|
||||||
EEOP_AGG_PLAIN_TRANS_BYVAL,
|
EEOP_AGG_PLAIN_TRANS_BYVAL,
|
||||||
@ -601,9 +602,21 @@ typedef struct ExprEvalStep
|
|||||||
int jumpnull;
|
int jumpnull;
|
||||||
} agg_deserialize;
|
} agg_deserialize;
|
||||||
|
|
||||||
/* for EEOP_AGG_STRICT_INPUT_CHECK */
|
/* for EEOP_AGG_STRICT_INPUT_CHECK_NULLS / STRICT_INPUT_CHECK_ARGS */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* For EEOP_AGG_STRICT_INPUT_CHECK_ARGS args contains pointers to
|
||||||
|
* the NullableDatums that need to be checked for NULLs.
|
||||||
|
*
|
||||||
|
* For EEOP_AGG_STRICT_INPUT_CHECK_NULLS nulls contains pointers
|
||||||
|
* to booleans that need to be checked for NULLs.
|
||||||
|
*
|
||||||
|
* Both cases currently need to exist because sometimes the
|
||||||
|
* to-be-checked nulls are in TupleTableSlot.isnull array, and
|
||||||
|
* sometimes in FunctionCallInfoBaseData.args[i].isnull.
|
||||||
|
*/
|
||||||
|
NullableDatum *args;
|
||||||
bool *nulls;
|
bool *nulls;
|
||||||
int nargs;
|
int nargs;
|
||||||
int jumpnull;
|
int jumpnull;
|
||||||
|
@ -158,12 +158,12 @@ typedef struct AggStatePerTransData
|
|||||||
* re-initializing the unchanging fields; which isn't much, but it seems
|
* re-initializing the unchanging fields; which isn't much, but it seems
|
||||||
* worth the extra space consumption.
|
* worth the extra space consumption.
|
||||||
*/
|
*/
|
||||||
FunctionCallInfoData transfn_fcinfo;
|
FunctionCallInfo transfn_fcinfo;
|
||||||
|
|
||||||
/* Likewise for serialization and deserialization functions */
|
/* Likewise for serialization and deserialization functions */
|
||||||
FunctionCallInfoData serialfn_fcinfo;
|
FunctionCallInfo serialfn_fcinfo;
|
||||||
|
|
||||||
FunctionCallInfoData deserialfn_fcinfo;
|
FunctionCallInfo deserialfn_fcinfo;
|
||||||
} AggStatePerTransData;
|
} AggStatePerTransData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -35,7 +35,7 @@ typedef struct StringInfoData *fmStringInfo;
|
|||||||
* signature.)
|
* signature.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct FunctionCallInfoData *FunctionCallInfo;
|
typedef struct FunctionCallInfoBaseData *FunctionCallInfo;
|
||||||
|
|
||||||
typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
|
typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
|
||||||
|
|
||||||
@ -46,8 +46,8 @@ typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
|
|||||||
* info struct saved for re-use.
|
* info struct saved for re-use.
|
||||||
*
|
*
|
||||||
* Note that fn_expr really is parse-time-determined information about the
|
* Note that fn_expr really is parse-time-determined information about the
|
||||||
* arguments, rather than about the function itself. But it's convenient
|
* arguments, rather than about the function itself. But it's convenient to
|
||||||
* to store it here rather than in FunctionCallInfoData, where it might more
|
* store it here rather than in FunctionCallInfoBaseData, where it might more
|
||||||
* logically belong.
|
* logically belong.
|
||||||
*
|
*
|
||||||
* fn_extra is available for use by the called function; all other fields
|
* fn_extra is available for use by the called function; all other fields
|
||||||
@ -73,8 +73,16 @@ typedef struct FmgrInfo
|
|||||||
* fields in whatever resultinfo points to. It should not change any other
|
* fields in whatever resultinfo points to. It should not change any other
|
||||||
* fields. (In particular, scribbling on the argument arrays is a bad idea,
|
* fields. (In particular, scribbling on the argument arrays is a bad idea,
|
||||||
* since some callers assume they can re-call with the same arguments.)
|
* since some callers assume they can re-call with the same arguments.)
|
||||||
|
*
|
||||||
|
* Note that enough space for arguments needs to be provided, either by using
|
||||||
|
* SizeForFunctionCallInfo() in dynamic allocations, or by using
|
||||||
|
* LOCAL_FCINFO() for on-stack allocations.
|
||||||
|
*
|
||||||
|
* This struct is named *BaseData, rather than *Data, to break pre v12 code
|
||||||
|
* that allocated FunctionCallInfoData itself, as it'd often silently break
|
||||||
|
* old code due to no space for arguments being provided.
|
||||||
*/
|
*/
|
||||||
typedef struct FunctionCallInfoData
|
typedef struct FunctionCallInfoBaseData
|
||||||
{
|
{
|
||||||
FmgrInfo *flinfo; /* ptr to lookup info used for this call */
|
FmgrInfo *flinfo; /* ptr to lookup info used for this call */
|
||||||
fmNodePtr context; /* pass info about context of call */
|
fmNodePtr context; /* pass info about context of call */
|
||||||
@ -83,11 +91,31 @@ typedef struct FunctionCallInfoData
|
|||||||
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
|
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
|
||||||
bool isnull; /* function must set true if result is NULL */
|
bool isnull; /* function must set true if result is NULL */
|
||||||
short nargs; /* # arguments actually passed */
|
short nargs; /* # arguments actually passed */
|
||||||
#define FIELDNO_FUNCTIONCALLINFODATA_ARG 6
|
#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6
|
||||||
Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
|
NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
|
||||||
#define FIELDNO_FUNCTIONCALLINFODATA_ARGNULL 7
|
} FunctionCallInfoBaseData;
|
||||||
bool argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */
|
|
||||||
} FunctionCallInfoData;
|
/*
|
||||||
|
* Space needed for for a FunctionCallInfoBaseData struct with sufficient space
|
||||||
|
* for `nargs` arguments.
|
||||||
|
*/
|
||||||
|
#define SizeForFunctionCallInfo(nargs) \
|
||||||
|
(offsetof(FunctionCallInfoBaseData, args) + \
|
||||||
|
sizeof(NullableDatum) * (nargs))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This macro ensures that `name` points to a stack-allocated
|
||||||
|
* FunctionCallInfoBaseData struct with sufficient space for `nargs` arguments.
|
||||||
|
*/
|
||||||
|
#define LOCAL_FCINFO(name, nargs) \
|
||||||
|
/* use union with FunctionCallInfoBaseData to guarantee alignment */ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
FunctionCallInfoBaseData fcinfo; \
|
||||||
|
/* ensure enough space for nargs args is available */ \
|
||||||
|
char fcinfo_data[SizeForFunctionCallInfo(nargs)]; \
|
||||||
|
} name##data; \
|
||||||
|
FunctionCallInfo name = &name##data.fcinfo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine fills a FmgrInfo struct, given the OID
|
* This routine fills a FmgrInfo struct, given the OID
|
||||||
@ -116,11 +144,8 @@ extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
|
|||||||
extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
|
extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This macro initializes all the fields of a FunctionCallInfoData except
|
* This macro initializes all the fields of a FunctionCallInfoBaseData except
|
||||||
* for the arg[] and argnull[] arrays. Performance testing has shown that
|
* for the args[] array.
|
||||||
* the fastest way to set up argnull[] for small numbers of arguments is to
|
|
||||||
* explicitly set each required element to false, so we don't try to zero
|
|
||||||
* out the argnull[] array in the macro.
|
|
||||||
*/
|
*/
|
||||||
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
|
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
|
||||||
do { \
|
do { \
|
||||||
@ -133,7 +158,7 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This macro invokes a function given a filled-in FunctionCallInfoData
|
* This macro invokes a function given a filled-in FunctionCallInfoBaseData
|
||||||
* struct. The macro result is the returned Datum --- but note that
|
* struct. The macro result is the returned Datum --- but note that
|
||||||
* caller must still check fcinfo->isnull! Also, if function is strict,
|
* caller must still check fcinfo->isnull! Also, if function is strict,
|
||||||
* it is caller's responsibility to verify that no null arguments are present
|
* it is caller's responsibility to verify that no null arguments are present
|
||||||
@ -176,7 +201,7 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
|
|||||||
* If function is not marked "proisstrict" in pg_proc, it must check for
|
* If function is not marked "proisstrict" in pg_proc, it must check for
|
||||||
* null arguments using this macro. Do not try to GETARG a null argument!
|
* null arguments using this macro. Do not try to GETARG a null argument!
|
||||||
*/
|
*/
|
||||||
#define PG_ARGISNULL(n) (fcinfo->argnull[n])
|
#define PG_ARGISNULL(n) (fcinfo->args[n].isnull)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support for fetching detoasted copies of toastable datatypes (all of
|
* Support for fetching detoasted copies of toastable datatypes (all of
|
||||||
@ -235,7 +260,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
|
|||||||
|
|
||||||
/* Macros for fetching arguments of standard types */
|
/* Macros for fetching arguments of standard types */
|
||||||
|
|
||||||
#define PG_GETARG_DATUM(n) (fcinfo->arg[n])
|
#define PG_GETARG_DATUM(n) (fcinfo->args[n].value)
|
||||||
#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n))
|
#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n))
|
||||||
#define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n))
|
#define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n))
|
||||||
#define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n))
|
#define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n))
|
||||||
@ -514,6 +539,7 @@ extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo,
|
|||||||
* directly-computed parameter list. Note that neither arguments nor result
|
* directly-computed parameter list. Note that neither arguments nor result
|
||||||
* are allowed to be NULL.
|
* are allowed to be NULL.
|
||||||
*/
|
*/
|
||||||
|
extern Datum FunctionCall0Coll(FmgrInfo *flinfo, Oid collation);
|
||||||
extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation,
|
extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation,
|
||||||
Datum arg1);
|
Datum arg1);
|
||||||
extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation,
|
extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation,
|
||||||
|
@ -62,6 +62,7 @@ extern LLVMTypeRef TypePGFunction;
|
|||||||
extern LLVMTypeRef TypeSizeT;
|
extern LLVMTypeRef TypeSizeT;
|
||||||
extern LLVMTypeRef TypeStorageBool;
|
extern LLVMTypeRef TypeStorageBool;
|
||||||
|
|
||||||
|
extern LLVMTypeRef StructNullableDatum;
|
||||||
extern LLVMTypeRef StructTupleDescData;
|
extern LLVMTypeRef StructTupleDescData;
|
||||||
extern LLVMTypeRef StructHeapTupleData;
|
extern LLVMTypeRef StructHeapTupleData;
|
||||||
extern LLVMTypeRef StructTupleTableSlot;
|
extern LLVMTypeRef StructTupleTableSlot;
|
||||||
|
@ -208,4 +208,59 @@ l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return pointer to the the argno'th argument nullness.
|
||||||
|
*/
|
||||||
|
static inline LLVMValueRef
|
||||||
|
l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
||||||
|
{
|
||||||
|
LLVMValueRef v_args;
|
||||||
|
LLVMValueRef v_argn;
|
||||||
|
|
||||||
|
v_args = LLVMBuildStructGEP(b,
|
||||||
|
v_fcinfo,
|
||||||
|
FIELDNO_FUNCTIONCALLINFODATA_ARGS,
|
||||||
|
"");
|
||||||
|
v_argn = LLVMBuildStructGEP(b, v_args, argno, "");
|
||||||
|
|
||||||
|
return LLVMBuildStructGEP(b, v_argn, FIELDNO_NULLABLE_DATUM_ISNULL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return pointer to the the argno'th argument datum.
|
||||||
|
*/
|
||||||
|
static inline LLVMValueRef
|
||||||
|
l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
||||||
|
{
|
||||||
|
LLVMValueRef v_args;
|
||||||
|
LLVMValueRef v_argn;
|
||||||
|
|
||||||
|
v_args = LLVMBuildStructGEP(b,
|
||||||
|
v_fcinfo,
|
||||||
|
FIELDNO_FUNCTIONCALLINFODATA_ARGS,
|
||||||
|
"");
|
||||||
|
v_argn = LLVMBuildStructGEP(b, v_args, argno, "");
|
||||||
|
|
||||||
|
return LLVMBuildStructGEP(b, v_argn, FIELDNO_NULLABLE_DATUM_DATUM, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return argno'th argument nullness.
|
||||||
|
*/
|
||||||
|
static inline LLVMValueRef
|
||||||
|
l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
||||||
|
{
|
||||||
|
return LLVMBuildLoad(b, l_funcnullp(b, v_fcinfo, argno), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return argno'th argument datum.
|
||||||
|
*/
|
||||||
|
static inline LLVMValueRef
|
||||||
|
l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
||||||
|
{
|
||||||
|
return LLVMBuildLoad(b, l_funcvaluep(b, v_fcinfo, argno), "");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -826,7 +826,7 @@ typedef struct SetExprState
|
|||||||
* (by InitFunctionCallInfoData) if func.fn_oid is valid. It also saves
|
* (by InitFunctionCallInfoData) if func.fn_oid is valid. It also saves
|
||||||
* argument values between calls, when setArgsValid is true.
|
* argument values between calls, when setArgsValid is true.
|
||||||
*/
|
*/
|
||||||
FunctionCallInfoData fcinfo_data;
|
FunctionCallInfo fcinfo;
|
||||||
} SetExprState;
|
} SetExprState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -1321,7 +1321,7 @@ extern void pgstat_count_heap_delete(Relation rel);
|
|||||||
extern void pgstat_count_truncate(Relation rel);
|
extern void pgstat_count_truncate(Relation rel);
|
||||||
extern void pgstat_update_heap_dead_tuples(Relation rel, int delta);
|
extern void pgstat_update_heap_dead_tuples(Relation rel, int delta);
|
||||||
|
|
||||||
extern void pgstat_init_function_usage(FunctionCallInfoData *fcinfo,
|
extern void pgstat_init_function_usage(FunctionCallInfo fcinfo,
|
||||||
PgStat_FunctionCallUsage *fcu);
|
PgStat_FunctionCallUsage *fcu);
|
||||||
extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu,
|
extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu,
|
||||||
bool finalize);
|
bool finalize);
|
||||||
|
@ -366,6 +366,21 @@ typedef struct
|
|||||||
|
|
||||||
typedef uintptr_t Datum;
|
typedef uintptr_t Datum;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A NullableDatum is used in places where both a Datum and its nullness needs
|
||||||
|
* to be stored. This can be more efficient than storing datums and nullness
|
||||||
|
* in separate arrays, due to better spatial locality, even if more space may
|
||||||
|
* be wasted due to padding.
|
||||||
|
*/
|
||||||
|
typedef struct NullableDatum
|
||||||
|
{
|
||||||
|
#define FIELDNO_NULLABLE_DATUM_DATUM 0
|
||||||
|
Datum value;
|
||||||
|
#define FIELDNO_NULLABLE_DATUM_ISNULL 1
|
||||||
|
bool isnull;
|
||||||
|
/* due to alignment padding this could be used for flags for free */
|
||||||
|
} NullableDatum;
|
||||||
|
|
||||||
#define SIZEOF_DATUM SIZEOF_VOID_P
|
#define SIZEOF_DATUM SIZEOF_VOID_P
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1876,8 +1876,8 @@ PG_FUNCTION_INFO_V1(plperl_inline_handler);
|
|||||||
Datum
|
Datum
|
||||||
plperl_inline_handler(PG_FUNCTION_ARGS)
|
plperl_inline_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fake_fcinfo, 0);
|
||||||
InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
|
InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
|
||||||
FunctionCallInfoData fake_fcinfo;
|
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
plperl_proc_desc desc;
|
plperl_proc_desc desc;
|
||||||
plperl_call_data *volatile save_call_data = current_call_data;
|
plperl_call_data *volatile save_call_data = current_call_data;
|
||||||
@ -1899,10 +1899,10 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
* plperl_call_perl_func(). In particular note that this sets things up
|
* plperl_call_perl_func(). In particular note that this sets things up
|
||||||
* with no arguments passed, and a result type of VOID.
|
* with no arguments passed, and a result type of VOID.
|
||||||
*/
|
*/
|
||||||
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
|
MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
|
||||||
MemSet(&flinfo, 0, sizeof(flinfo));
|
MemSet(&flinfo, 0, sizeof(flinfo));
|
||||||
MemSet(&desc, 0, sizeof(desc));
|
MemSet(&desc, 0, sizeof(desc));
|
||||||
fake_fcinfo.flinfo = &flinfo;
|
fake_fcinfo->flinfo = &flinfo;
|
||||||
flinfo.fn_oid = InvalidOid;
|
flinfo.fn_oid = InvalidOid;
|
||||||
flinfo.fn_mcxt = CurrentMemoryContext;
|
flinfo.fn_mcxt = CurrentMemoryContext;
|
||||||
|
|
||||||
@ -1920,7 +1920,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
desc.nargs = 0;
|
desc.nargs = 0;
|
||||||
desc.reference = NULL;
|
desc.reference = NULL;
|
||||||
|
|
||||||
this_call_data.fcinfo = &fake_fcinfo;
|
this_call_data.fcinfo = fake_fcinfo;
|
||||||
this_call_data.prodesc = &desc;
|
this_call_data.prodesc = &desc;
|
||||||
/* we do not bother with refcounting the fake prodesc */
|
/* we do not bother with refcounting the fake prodesc */
|
||||||
|
|
||||||
@ -1940,7 +1940,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
if (!desc.reference) /* can this happen? */
|
if (!desc.reference) /* can this happen? */
|
||||||
elog(ERROR, "could not create internal procedure for anonymous code block");
|
elog(ERROR, "could not create internal procedure for anonymous code block");
|
||||||
|
|
||||||
perlret = plperl_call_perl_func(&desc, &fake_fcinfo);
|
perlret = plperl_call_perl_func(&desc, fake_fcinfo);
|
||||||
|
|
||||||
SvREFCNT_dec_current(perlret);
|
SvREFCNT_dec_current(perlret);
|
||||||
|
|
||||||
@ -2194,11 +2194,11 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
|
|||||||
|
|
||||||
for (i = 0; i < desc->nargs; i++)
|
for (i = 0; i < desc->nargs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
PUSHs(&PL_sv_undef);
|
PUSHs(&PL_sv_undef);
|
||||||
else if (desc->arg_is_rowtype[i])
|
else if (desc->arg_is_rowtype[i])
|
||||||
{
|
{
|
||||||
SV *sv = plperl_hash_from_datum(fcinfo->arg[i]);
|
SV *sv = plperl_hash_from_datum(fcinfo->args[i].value);
|
||||||
|
|
||||||
PUSHs(sv_2mortal(sv));
|
PUSHs(sv_2mortal(sv));
|
||||||
}
|
}
|
||||||
@ -2208,15 +2208,15 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
|
|||||||
Oid funcid;
|
Oid funcid;
|
||||||
|
|
||||||
if (OidIsValid(desc->arg_arraytype[i]))
|
if (OidIsValid(desc->arg_arraytype[i]))
|
||||||
sv = plperl_ref_from_pg_array(fcinfo->arg[i], desc->arg_arraytype[i]);
|
sv = plperl_ref_from_pg_array(fcinfo->args[i].value, desc->arg_arraytype[i]);
|
||||||
else if ((funcid = get_transform_fromsql(argtypes[i], current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
|
else if ((funcid = get_transform_fromsql(argtypes[i], current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
|
||||||
sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, fcinfo->arg[i]));
|
sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, fcinfo->args[i].value));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
|
tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
|
||||||
fcinfo->arg[i]);
|
fcinfo->args[i].value);
|
||||||
sv = cstr2sv(tmp);
|
sv = cstr2sv(tmp);
|
||||||
pfree(tmp);
|
pfree(tmp);
|
||||||
}
|
}
|
||||||
|
@ -491,8 +491,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
|
|||||||
PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
|
PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
|
||||||
|
|
||||||
assign_simple_var(&estate, var,
|
assign_simple_var(&estate, var,
|
||||||
fcinfo->arg[i],
|
fcinfo->args[i].value,
|
||||||
fcinfo->argnull[i],
|
fcinfo->args[i].isnull,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -543,12 +543,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
|
|||||||
{
|
{
|
||||||
PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
|
||||||
|
|
||||||
if (!fcinfo->argnull[i])
|
if (!fcinfo->args[i].isnull)
|
||||||
{
|
{
|
||||||
/* Assign row value from composite datum */
|
/* Assign row value from composite datum */
|
||||||
exec_move_row_from_datum(&estate,
|
exec_move_row_from_datum(&estate,
|
||||||
(PLpgSQL_variable *) rec,
|
(PLpgSQL_variable *) rec,
|
||||||
fcinfo->arg[i]);
|
fcinfo->args[i].value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -299,9 +299,9 @@ PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
|
|||||||
Datum
|
Datum
|
||||||
plpgsql_inline_handler(PG_FUNCTION_ARGS)
|
plpgsql_inline_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fake_fcinfo, 0);
|
||||||
InlineCodeBlock *codeblock = castNode(InlineCodeBlock, DatumGetPointer(PG_GETARG_DATUM(0)));
|
InlineCodeBlock *codeblock = castNode(InlineCodeBlock, DatumGetPointer(PG_GETARG_DATUM(0)));
|
||||||
PLpgSQL_function *func;
|
PLpgSQL_function *func;
|
||||||
FunctionCallInfoData fake_fcinfo;
|
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
EState *simple_eval_estate;
|
EState *simple_eval_estate;
|
||||||
Datum retval;
|
Datum retval;
|
||||||
@ -324,9 +324,9 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
* plpgsql_exec_function(). In particular note that this sets things up
|
* plpgsql_exec_function(). In particular note that this sets things up
|
||||||
* with no arguments passed.
|
* with no arguments passed.
|
||||||
*/
|
*/
|
||||||
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
|
MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
|
||||||
MemSet(&flinfo, 0, sizeof(flinfo));
|
MemSet(&flinfo, 0, sizeof(flinfo));
|
||||||
fake_fcinfo.flinfo = &flinfo;
|
fake_fcinfo->flinfo = &flinfo;
|
||||||
flinfo.fn_oid = InvalidOid;
|
flinfo.fn_oid = InvalidOid;
|
||||||
flinfo.fn_mcxt = CurrentMemoryContext;
|
flinfo.fn_mcxt = CurrentMemoryContext;
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
/* And run the function */
|
/* And run the function */
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
retval = plpgsql_exec_function(func, &fake_fcinfo, simple_eval_estate, codeblock->atomic);
|
retval = plpgsql_exec_function(func, fake_fcinfo, simple_eval_estate, codeblock->atomic);
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
@ -466,7 +466,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
|
|||||||
/* Postpone body checks if !check_function_bodies */
|
/* Postpone body checks if !check_function_bodies */
|
||||||
if (check_function_bodies)
|
if (check_function_bodies)
|
||||||
{
|
{
|
||||||
FunctionCallInfoData fake_fcinfo;
|
LOCAL_FCINFO(fake_fcinfo, 0);
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
int rc;
|
int rc;
|
||||||
TriggerData trigdata;
|
TriggerData trigdata;
|
||||||
@ -482,26 +482,26 @@ plpgsql_validator(PG_FUNCTION_ARGS)
|
|||||||
* Set up a fake fcinfo with just enough info to satisfy
|
* Set up a fake fcinfo with just enough info to satisfy
|
||||||
* plpgsql_compile().
|
* plpgsql_compile().
|
||||||
*/
|
*/
|
||||||
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
|
MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
|
||||||
MemSet(&flinfo, 0, sizeof(flinfo));
|
MemSet(&flinfo, 0, sizeof(flinfo));
|
||||||
fake_fcinfo.flinfo = &flinfo;
|
fake_fcinfo->flinfo = &flinfo;
|
||||||
flinfo.fn_oid = funcoid;
|
flinfo.fn_oid = funcoid;
|
||||||
flinfo.fn_mcxt = CurrentMemoryContext;
|
flinfo.fn_mcxt = CurrentMemoryContext;
|
||||||
if (is_dml_trigger)
|
if (is_dml_trigger)
|
||||||
{
|
{
|
||||||
MemSet(&trigdata, 0, sizeof(trigdata));
|
MemSet(&trigdata, 0, sizeof(trigdata));
|
||||||
trigdata.type = T_TriggerData;
|
trigdata.type = T_TriggerData;
|
||||||
fake_fcinfo.context = (Node *) &trigdata;
|
fake_fcinfo->context = (Node *) &trigdata;
|
||||||
}
|
}
|
||||||
else if (is_event_trigger)
|
else if (is_event_trigger)
|
||||||
{
|
{
|
||||||
MemSet(&etrigdata, 0, sizeof(etrigdata));
|
MemSet(&etrigdata, 0, sizeof(etrigdata));
|
||||||
etrigdata.type = T_EventTriggerData;
|
etrigdata.type = T_EventTriggerData;
|
||||||
fake_fcinfo.context = (Node *) &etrigdata;
|
fake_fcinfo->context = (Node *) &etrigdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test-compile the function */
|
/* Test-compile the function */
|
||||||
plpgsql_compile(&fake_fcinfo, true);
|
plpgsql_compile(fake_fcinfo, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disconnect from SPI manager
|
* Disconnect from SPI manager
|
||||||
|
@ -436,10 +436,10 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
|
|||||||
{
|
{
|
||||||
PLyDatumToOb *arginfo = &proc->args[i];
|
PLyDatumToOb *arginfo = &proc->args[i];
|
||||||
|
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
arg = NULL;
|
arg = NULL;
|
||||||
else
|
else
|
||||||
arg = PLy_input_convert(arginfo, fcinfo->arg[i]);
|
arg = PLy_input_convert(arginfo, fcinfo->args[i].value);
|
||||||
|
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
{
|
{
|
||||||
|
@ -299,8 +299,8 @@ plpython2_call_handler(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
plpython_inline_handler(PG_FUNCTION_ARGS)
|
plpython_inline_handler(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fake_fcinfo, 0);
|
||||||
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
|
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
|
||||||
FunctionCallInfoData fake_fcinfo;
|
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo;
|
||||||
PLyProcedure proc;
|
PLyProcedure proc;
|
||||||
PLyExecutionContext *exec_ctx;
|
PLyExecutionContext *exec_ctx;
|
||||||
@ -312,9 +312,9 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
|
if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "SPI_connect failed");
|
elog(ERROR, "SPI_connect failed");
|
||||||
|
|
||||||
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
|
MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
|
||||||
MemSet(&flinfo, 0, sizeof(flinfo));
|
MemSet(&flinfo, 0, sizeof(flinfo));
|
||||||
fake_fcinfo.flinfo = &flinfo;
|
fake_fcinfo->flinfo = &flinfo;
|
||||||
flinfo.fn_oid = InvalidOid;
|
flinfo.fn_oid = InvalidOid;
|
||||||
flinfo.fn_mcxt = CurrentMemoryContext;
|
flinfo.fn_mcxt = CurrentMemoryContext;
|
||||||
|
|
||||||
@ -352,7 +352,7 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PLy_procedure_compile(&proc, codeblock->source_text);
|
PLy_procedure_compile(&proc, codeblock->source_text);
|
||||||
exec_ctx->curr_proc = &proc;
|
exec_ctx->curr_proc = &proc;
|
||||||
PLy_exec_function(&fake_fcinfo, &proc);
|
PLy_exec_function(fake_fcinfo, &proc);
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
|
@ -587,6 +587,7 @@ pltcl_fetch_interp(Oid prolang, bool pltrusted)
|
|||||||
static void
|
static void
|
||||||
call_pltcl_start_proc(Oid prolang, bool pltrusted)
|
call_pltcl_start_proc(Oid prolang, bool pltrusted)
|
||||||
{
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
char *start_proc;
|
char *start_proc;
|
||||||
const char *gucname;
|
const char *gucname;
|
||||||
ErrorContextCallback errcallback;
|
ErrorContextCallback errcallback;
|
||||||
@ -597,7 +598,6 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
|
|||||||
Form_pg_proc procStruct;
|
Form_pg_proc procStruct;
|
||||||
AclResult aclresult;
|
AclResult aclresult;
|
||||||
FmgrInfo finfo;
|
FmgrInfo finfo;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
PgStat_FunctionCallUsage fcusage;
|
PgStat_FunctionCallUsage fcusage;
|
||||||
|
|
||||||
/* select appropriate GUC */
|
/* select appropriate GUC */
|
||||||
@ -658,11 +658,11 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
|
|||||||
*/
|
*/
|
||||||
InvokeFunctionExecuteHook(procOid);
|
InvokeFunctionExecuteHook(procOid);
|
||||||
fmgr_info(procOid, &finfo);
|
fmgr_info(procOid, &finfo);
|
||||||
InitFunctionCallInfoData(fcinfo, &finfo,
|
InitFunctionCallInfoData(*fcinfo, &finfo,
|
||||||
0,
|
0,
|
||||||
InvalidOid, NULL, NULL);
|
InvalidOid, NULL, NULL);
|
||||||
pgstat_init_function_usage(&fcinfo, &fcusage);
|
pgstat_init_function_usage(fcinfo, &fcusage);
|
||||||
(void) FunctionCallInvoke(&fcinfo);
|
(void) FunctionCallInvoke(fcinfo);
|
||||||
pgstat_end_function_usage(&fcusage, true);
|
pgstat_end_function_usage(&fcusage, true);
|
||||||
|
|
||||||
/* Pop the error context stack */
|
/* Pop the error context stack */
|
||||||
@ -869,7 +869,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
/**************************************************
|
/**************************************************
|
||||||
* For tuple values, add a list for 'array set ...'
|
* For tuple values, add a list for 'array set ...'
|
||||||
**************************************************/
|
**************************************************/
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
|
Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -880,7 +880,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
HeapTupleData tmptup;
|
HeapTupleData tmptup;
|
||||||
Tcl_Obj *list_tmp;
|
Tcl_Obj *list_tmp;
|
||||||
|
|
||||||
td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
|
td = DatumGetHeapTupleHeader(fcinfo->args[i].value);
|
||||||
/* Extract rowtype info and find a tupdesc */
|
/* Extract rowtype info and find a tupdesc */
|
||||||
tupType = HeapTupleHeaderGetTypeId(td);
|
tupType = HeapTupleHeaderGetTypeId(td);
|
||||||
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
||||||
@ -901,14 +901,14 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
|
|||||||
* Single values are added as string element
|
* Single values are added as string element
|
||||||
* of their external representation
|
* of their external representation
|
||||||
**************************************************/
|
**************************************************/
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->args[i].isnull)
|
||||||
Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
|
Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
tmp = OutputFunctionCall(&prodesc->arg_out_func[i],
|
tmp = OutputFunctionCall(&prodesc->arg_out_func[i],
|
||||||
fcinfo->arg[i]);
|
fcinfo->args[i].value);
|
||||||
UTF_BEGIN;
|
UTF_BEGIN;
|
||||||
Tcl_ListObjAppendElement(NULL, tcl_cmd,
|
Tcl_ListObjAppendElement(NULL, tcl_cmd,
|
||||||
Tcl_NewStringObj(UTF_E2U(tmp), -1));
|
Tcl_NewStringObj(UTF_E2U(tmp), -1));
|
||||||
|
@ -804,7 +804,7 @@ FuncExpr
|
|||||||
FuncInfo
|
FuncInfo
|
||||||
Function
|
Function
|
||||||
FunctionCallInfo
|
FunctionCallInfo
|
||||||
FunctionCallInfoData
|
FunctionCallInfoBaseData
|
||||||
FunctionParameter
|
FunctionParameter
|
||||||
FunctionParameterMode
|
FunctionParameterMode
|
||||||
FunctionScan
|
FunctionScan
|
||||||
@ -1328,6 +1328,7 @@ NonEmptyRange
|
|||||||
Notification
|
Notification
|
||||||
NotifyStmt
|
NotifyStmt
|
||||||
Nsrt
|
Nsrt
|
||||||
|
NullableDatum
|
||||||
NullIfExpr
|
NullIfExpr
|
||||||
NullTest
|
NullTest
|
||||||
NullTestType
|
NullTestType
|
||||||
|
Loading…
x
Reference in New Issue
Block a user