]> granicus.if.org Git - postgresql/commitdiff
Change function call information to be variable length.
authorAndres Freund <andres@anarazel.de>
Sat, 26 Jan 2019 22:17:52 +0000 (14:17 -0800)
committerAndres Freund <andres@anarazel.de>
Sat, 26 Jan 2019 22:17:52 +0000 (14:17 -0800)
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

40 files changed:
contrib/hstore/hstore_op.c
doc/src/sgml/plhandler.sgml
src/backend/commands/event_trigger.c
src/backend/commands/functioncmds.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/executor/README
src/backend/executor/execExpr.c
src/backend/executor/execExprInterp.c
src/backend/executor/execSRF.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeWindowAgg.c
src/backend/jit/llvm/llvmjit.c
src/backend/jit/llvm/llvmjit_expr.c
src/backend/jit/llvm/llvmjit_types.c
src/backend/postmaster/pgstat.c
src/backend/tcop/fastpath.c
src/backend/utils/adt/arrayfuncs.c
src/backend/utils/adt/int.c
src/backend/utils/adt/oid.c
src/backend/utils/adt/rowtypes.c
src/backend/utils/fmgr/README
src/backend/utils/fmgr/fmgr.c
src/backend/utils/sort/sortsupport.c
src/include/executor/execExpr.h
src/include/executor/nodeAgg.h
src/include/fmgr.h
src/include/jit/llvmjit.h
src/include/jit/llvmjit_emit.h
src/include/nodes/execnodes.h
src/include/pgstat.h
src/include/postgres.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_handler.c
src/pl/plpython/plpy_exec.c
src/pl/plpython/plpy_main.c
src/pl/tcl/pltcl.c
src/tools/pgindent/typedefs.list

index a915215fb6fc00f90ee0bd423b59089be605f93e..b852fb5a8ac4e19ebb5af27dd799655dceb41c45 100644 (file)
@@ -854,7 +854,7 @@ hstore_to_matrix(PG_FUNCTION_ARGS)
 
 static void
 setup_firstcall(FuncCallContext *funcctx, HStore *hs,
-                               FunctionCallInfoData *fcinfo)
+                               FunctionCallInfo fcinfo)
 {
        MemoryContext oldcontext;
        HStore     *st;
index 73cd7d13875f383b4acde1f5a38619c9b9ca22a3..14ad15aab8f46e6b6055d1411f4f21ca5e198ebc 100644 (file)
    <para>
     The call handler is called in the same way as any other function:
     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
     is expected to return a <type>Datum</type> result (and possibly
     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
     handler and an ordinary callee function is that the
     <structfield>flinfo-&gt;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
     handler itself.  The call handler must use this field to determine
     which function to execute.  Also, the passed argument list has
@@ -87,7 +87,7 @@
    <para>
     When a procedural-language function is invoked as a trigger, no arguments
     are passed in the usual way, but the
-    <structname>FunctionCallInfoData</structname>'s
+    <structname>FunctionCallInfoBaseData</structname>'s
     <structfield>context</structfield> field points at a
     <structname>TriggerData</structname> structure, rather than being <symbol>NULL</symbol>
     as it is in a plain function call.  A language handler should
index 8adc2cadaf4034847d924e7916f1c2c98bcb2c61..adb77d8f6925b47f45c11d8ea38c1dba40ee3726 100644 (file)
@@ -1055,9 +1055,9 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
        /* Call each event trigger. */
        foreach(lc, fn_oid_list)
        {
+               LOCAL_FCINFO(fcinfo, 0);
                Oid                     fnoid = lfirst_oid(lc);
                FmgrInfo        flinfo;
-               FunctionCallInfoData fcinfo;
                PgStat_FunctionCallUsage fcusage;
 
                elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
@@ -1077,10 +1077,10 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
                fmgr_info(fnoid, &flinfo);
 
                /* Call the function, passing no arguments but setting a context. */
-               InitFunctionCallInfoData(fcinfo, &flinfo, 0,
+               InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
                                                                 InvalidOid, (Node *) trigdata, NULL);
-               pgstat_init_function_usage(&fcinfo, &fcusage);
-               FunctionCallInvoke(&fcinfo);
+               pgstat_init_function_usage(fcinfo, &fcusage);
+               FunctionCallInvoke(fcinfo);
                pgstat_end_function_usage(&fcusage, true);
 
                /* Reclaim memory. */
index eae2b09830b5e2b625bb5bdf9247248d567e938f..ac401689c82f940b6de34639020b2ff9ae8e74a9 100644 (file)
@@ -2216,13 +2216,13 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
 void
 ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
 {
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        ListCell   *lc;
        FuncExpr   *fexpr;
        int                     nargs;
        int                     i;
        AclResult       aclresult;
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
        CallContext *callcontext;
        EState     *estate;
        ExprContext *econtext;
@@ -2297,7 +2297,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
        InvokeFunctionExecuteHook(fexpr->funcid);
        fmgr_info(fexpr->funcid, &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
@@ -2318,14 +2319,14 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
 
                val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
 
-               fcinfo.arg[i] = val;
-               fcinfo.argnull[i] = isnull;
+               fcinfo->args[i].value = val;
+               fcinfo->args[i].isnull = isnull;
 
                i++;
        }
 
-       pgstat_init_function_usage(&fcinfo, &fcusage);
-       retval = FunctionCallInvoke(&fcinfo);
+       pgstat_init_function_usage(fcinfo, &fcusage);
+       retval = FunctionCallInvoke(fcinfo);
        pgstat_end_function_usage(&fcusage, true);
 
        if (fexpr->funcresulttype == VOIDOID)
@@ -2346,7 +2347,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
                TupOutputState *tstate;
                TupleTableSlot *slot;
 
-               if (fcinfo.isnull)
+               if (fcinfo->isnull)
                        elog(ERROR, "procedure returned null record");
 
                td = DatumGetHeapTupleHeader(retval);
index 9daf3e6588fb355fd8bceb5f9466a483351e133b..ff76499137979255ab4f2091fd273fdfd13b37dc 100644 (file)
@@ -8879,7 +8879,7 @@ validateForeignKeyConstraint(char *conname,
 
        while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
        {
-               FunctionCallInfoData fcinfo;
+               LOCAL_FCINFO(fcinfo, 0);
                TriggerData trigdata;
 
                /*
@@ -8887,7 +8887,7 @@ validateForeignKeyConstraint(char *conname,
                 *
                 * 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...
@@ -8901,9 +8901,9 @@ validateForeignKeyConstraint(char *conname,
                trigdata.tg_trigtuplebuf = scan->rs_cbuf;
                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);
index 7ffaeaffc6740e8507c90b73a7b3e57d951f6eb0..499030c4455372f69cf9ae9894e55f3462f943f4 100644 (file)
@@ -2357,7 +2357,7 @@ ExecCallTriggerFunc(TriggerData *trigdata,
                                        Instrumentation *instr,
                                        MemoryContext per_tuple_context)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 0);
        PgStat_FunctionCallUsage fcusage;
        Datum           result;
        MemoryContext oldContext;
@@ -2402,15 +2402,15 @@ ExecCallTriggerFunc(TriggerData *trigdata,
        /*
         * Call the function, passing no arguments but setting a context.
         */
-       InitFunctionCallInfoData(fcinfo, finfo, 0,
+       InitFunctionCallInfoData(*fcinfo, finfo, 0,
                                                         InvalidOid, (Node *) trigdata, NULL);
 
-       pgstat_init_function_usage(&fcinfo, &fcusage);
+       pgstat_init_function_usage(fcinfo, &fcusage);
 
        MyTriggerDepth++;
        PG_TRY();
        {
-               result = FunctionCallInvoke(&fcinfo);
+               result = FunctionCallInvoke(fcinfo);
        }
        PG_CATCH();
        {
@@ -2428,11 +2428,11 @@ ExecCallTriggerFunc(TriggerData *trigdata,
         * Trigger protocol allows function to return a null pointer, but NOT to
         * set the isnull result flag.
         */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                ereport(ERROR,
                                (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
                                 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
index ddbd62b4dbae15b54f9c68e06c4a1f676f0a48f8..05f197bc75b692c2571ce9fb971ad19525e9b85c 100644 (file)
@@ -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
 evaluation of the function underlying the + operator.  The steps for the
 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
 the result values around.
 
@@ -145,7 +145,7 @@ sub-expressions.
 Each ExecInitExprRec() call has to specify where that subexpression's
 results are to be stored (via the resv/resnull parameters).  This allows
 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
 results are only needed by steps executing before further usages of those
 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
 resv/resnull for a subexpression usually point to some storage that is
 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
 of a complete expression is typically returned into the resvalue/resnull
 fields of the ExprState node itself.
index 4047d24b03ef7d6425e9447ba196b30a0277fbf1..2e061a5ee36f0010d8167f701035ac3ffa832e6b 100644 (file)
@@ -966,7 +966,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                /* Set up the primary fmgr lookup information */
                                finfo = palloc0(sizeof(FmgrInfo));
-                               fcinfo = palloc0(sizeof(FunctionCallInfoData));
+                               fcinfo = palloc0(SizeForFunctionCallInfo(2));
                                fmgr_info(opexpr->opfuncid, finfo);
                                fmgr_info_set_expr((Node *) node, finfo);
                                InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -974,7 +974,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                /* Evaluate scalar directly into left function argument */
                                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
@@ -1263,7 +1263,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                /* lookup the source type's output function */
                                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),
                                                                  &iofunc, &typisvarlena);
@@ -1275,7 +1275,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                /* lookup the result type's input function */
                                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,
                                                                 &iofunc, &typioparam);
@@ -1290,10 +1290,10 @@ ExecInitExprRec(Expr *node, ExprState *state,
                                 * function, since they're constants.
                                 */
                                fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
-                               fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam);
-                               fcinfo_in->argnull[1] = false;
-                               fcinfo_in->arg[2] = Int32GetDatum(-1);
-                               fcinfo_in->argnull[2] = false;
+                               fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
+                               fcinfo_in->args[1].isnull = false;
+                               fcinfo_in->args[2].value = Int32GetDatum(-1);
+                               fcinfo_in->args[2].isnull = false;
 
                                ExprEvalPushStep(state, &scratch);
                                break;
@@ -1735,7 +1735,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                        /* Set up the primary fmgr lookup information */
                                        finfo = palloc0(sizeof(FmgrInfo));
-                                       fcinfo = palloc0(sizeof(FunctionCallInfoData));
+                                       fcinfo = palloc0(SizeForFunctionCallInfo(2));
                                        fmgr_info(proc, finfo);
                                        fmgr_info_set_expr((Node *) node, finfo);
                                        InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -1750,9 +1750,9 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                        /* evaluate left and right args directly into fcinfo */
                                        ExecInitExprRec(left_expr, state,
-                                                                       &fcinfo->arg[0], &fcinfo->argnull[0]);
+                                                                       &fcinfo->args[0].value, &fcinfo->args[0].isnull);
                                        ExecInitExprRec(right_expr, state,
-                                                                       &fcinfo->arg[1], &fcinfo->argnull[1]);
+                                                                       &fcinfo->args[1].value, &fcinfo->args[1].isnull);
 
                                        scratch.opcode = EEOP_ROWCOMPARE_STEP;
                                        scratch.d.rowcompare_step.finfo = finfo;
@@ -1878,7 +1878,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
                                /* Perform function lookup */
                                finfo = palloc0(sizeof(FmgrInfo));
-                               fcinfo = palloc0(sizeof(FunctionCallInfoData));
+                               fcinfo = palloc0(SizeForFunctionCallInfo(2));
                                fmgr_info(typentry->cmp_proc, finfo);
                                fmgr_info_set_expr((Node *) node, finfo);
                                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 */
        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;
        fcinfo = scratch->d.func.fcinfo_data;
 
@@ -2226,13 +2226,14 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
                         */
                        Const      *con = (Const *) arg;
 
-                       fcinfo->arg[argno] = con->constvalue;
-                       fcinfo->argnull[argno] = con->constisnull;
+                       fcinfo->args[argno].value = con->constvalue;
+                       fcinfo->args[argno].isnull = con->constisnull;
                }
                else
                {
                        ExecInitExprRec(arg, state,
-                                                       &fcinfo->arg[argno], &fcinfo->argnull[argno]);
+                                                       &fcinfo->args[argno].value,
+                                                       &fcinfo->args[argno].isnull);
                }
                argno++;
        }
@@ -2961,10 +2962,11 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                AggStatePerTrans pertrans = &aggstate->pertrans[transno];
                int                     argno;
                int                     setno;
-               FunctionCallInfo trans_fcinfo = &pertrans->transfn_fcinfo;
+               FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
                ListCell   *arg;
                ListCell   *bail;
                List       *adjust_bailout = NIL;
+               NullableDatum *strictargs = NULL;
                bool       *strictnulls = NULL;
 
                /*
@@ -3002,7 +3004,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                        Assert(pertrans->numSortCols == 0);
                        Assert(list_length(pertrans->aggref->args) == 1);
 
-                       strictnulls = trans_fcinfo->argnull + 1;
+                       strictargs = trans_fcinfo->args + 1;
                        source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
 
                        /*
@@ -3016,21 +3018,21 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                                 * value
                                 */
                                ExecInitExprRec(source_tle->expr, state,
-                                                               &trans_fcinfo->arg[argno + 1],
-                                                               &trans_fcinfo->argnull[argno + 1]);
+                                                               &trans_fcinfo->args[argno + 1].value,
+                                                               &trans_fcinfo->args[argno + 1].isnull);
                        }
                        else
                        {
-                               FunctionCallInfo ds_fcinfo = &pertrans->deserialfn_fcinfo;
+                               FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
 
                                /* evaluate argument */
                                ExecInitExprRec(source_tle->expr, state,
-                                                               &ds_fcinfo->arg[0],
-                                                               &ds_fcinfo->argnull[0]);
+                                                               &ds_fcinfo->args[0].value,
+                                                               &ds_fcinfo->args[0].isnull);
 
                                /* Dummy second argument for type-safety reasons */
-                               ds_fcinfo->arg[1] = PointerGetDatum(NULL);
-                               ds_fcinfo->argnull[1] = false;
+                               ds_fcinfo->args[1].value = PointerGetDatum(NULL);
+                               ds_fcinfo->args[1].isnull = false;
 
                                /*
                                 * 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.fcinfo_data = ds_fcinfo;
                                scratch.d.agg_deserialize.jumpnull = -1;        /* adjust later */
-                               scratch.resvalue = &trans_fcinfo->arg[argno + 1];
-                               scratch.resnull = &trans_fcinfo->argnull[argno + 1];
+                               scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
+                               scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
 
                                ExprEvalPushStep(state, &scratch);
                                adjust_bailout = lappend_int(adjust_bailout,
@@ -3062,7 +3064,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                        /*
                         * Normal transition function without ORDER BY / DISTINCT.
                         */
-                       strictnulls = trans_fcinfo->argnull + 1;
+                       strictargs = trans_fcinfo->args + 1;
 
                        foreach(arg, pertrans->aggref->args)
                        {
@@ -3073,8 +3075,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                                 * value
                                 */
                                ExecInitExprRec(source_tle->expr, state,
-                                                               &trans_fcinfo->arg[argno + 1],
-                                                               &trans_fcinfo->argnull[argno + 1]);
+                                                               &trans_fcinfo->args[argno + 1].value,
+                                                               &trans_fcinfo->args[argno + 1].isnull);
                                argno++;
                        }
                }
@@ -3122,8 +3124,12 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                 */
                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.args = strictargs;
                        scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
                        scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
                        ExprEvalPushStep(state, &scratch);
@@ -3177,7 +3183,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
                                Assert(as->d.jump.jumpdone == -1);
                                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);
                                as->d.agg_strict_input_check.jumpnull = state->steps_len;
@@ -3312,7 +3319,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
  */
 ExprState *
 ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
-                                          const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
+                                          const TupleTableSlotOps * lops, const TupleTableSlotOps * rops,
                                           int numCols,
                                           const AttrNumber *keyColIdx,
                                           const Oid *eqfunctions,
@@ -3389,7 +3396,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
 
                /* Set up the primary fmgr lookup information */
                finfo = palloc0(sizeof(FmgrInfo));
-               fcinfo = palloc0(sizeof(FunctionCallInfoData));
+               fcinfo = palloc0(SizeForFunctionCallInfo(2));
                fmgr_info(foid, finfo);
                fmgr_info_set_expr(NULL, finfo);
                InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -3399,16 +3406,16 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
                scratch.opcode = EEOP_INNER_VAR;
                scratch.d.var.attnum = attno - 1;
                scratch.d.var.vartype = latt->atttypid;
-               scratch.resvalue = &fcinfo->arg[0];
-               scratch.resnull = &fcinfo->argnull[0];
+               scratch.resvalue = &fcinfo->args[0].value;
+               scratch.resnull = &fcinfo->args[0].isnull;
                ExprEvalPushStep(state, &scratch);
 
                /* right arg */
                scratch.opcode = EEOP_OUTER_VAR;
                scratch.d.var.attnum = attno - 1;
                scratch.d.var.vartype = ratt->atttypid;
-               scratch.resvalue = &fcinfo->arg[1];
-               scratch.resnull = &fcinfo->argnull[1];
+               scratch.resvalue = &fcinfo->args[1].value;
+               scratch.resnull = &fcinfo->args[1].isnull;
                ExprEvalPushStep(state, &scratch);
 
                /* evaluate distinctness */
index 5a7206f5882da80380a35f474c072f5369f611fb..5c5f655645d5da23a3812b930e8aca2bcd6e63ac 100644 (file)
@@ -387,7 +387,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                &&CASE_EEOP_ALTERNATIVE_SUBPLAN,
                &&CASE_EEOP_AGG_STRICT_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_STRICT_TRANS_CHECK,
                &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
@@ -631,14 +632,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                EEO_CASE(EEOP_FUNCEXPR_STRICT)
                {
                        FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
-                       bool       *argnull = fcinfo->argnull;
+                       NullableDatum *args = fcinfo->args;
                        int                     argno;
                        Datum           d;
 
                        /* strict function, so check for NULL args */
                        for (argno = 0; argno < op->d.func.nargs; argno++)
                        {
-                               if (argnull[argno])
+                               if (args[argno].isnull)
                                {
                                        *op->resnull = true;
                                        goto strictfail;
@@ -1054,8 +1055,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                                FunctionCallInfo fcinfo_out;
 
                                fcinfo_out = op->d.iocoerce.fcinfo_data_out;
-                               fcinfo_out->arg[0] = *op->resvalue;
-                               fcinfo_out->argnull[0] = false;
+                               fcinfo_out->args[0].value = *op->resvalue;
+                               fcinfo_out->args[0].isnull = false;
 
                                fcinfo_out->isnull = false;
                                str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
@@ -1071,8 +1072,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                                Datum           d;
 
                                fcinfo_in = op->d.iocoerce.fcinfo_data_in;
-                               fcinfo_in->arg[0] = PointerGetDatum(str);
-                               fcinfo_in->argnull[0] = *op->resnull;
+                               fcinfo_in->args[0].value = PointerGetDatum(str);
+                               fcinfo_in->args[0].isnull = *op->resnull;
                                /* second and third arguments are already set up */
 
                                fcinfo_in->isnull = false;
@@ -1099,23 +1100,23 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                {
                        /*
                         * IS DISTINCT FROM must evaluate arguments (already done into
-                        * fcinfo->arg/argnull) to determine whether they are NULL; if
-                        * either is NULL then the result is determined.  If neither is
-                        * NULL, then proceed to evaluate the comparison function, which
-                        * is just the type's standard equality operator.  We need not
-                        * care whether that function is strict.  Because the handling of
-                        * nulls is different, we can't just reuse EEOP_FUNCEXPR.
+                        * fcinfo->args) to determine whether they are NULL; if either is
+                        * NULL then the result is determined.  If neither is NULL, then
+                        * proceed to evaluate the comparison function, which is just the
+                        * type's standard equality operator.  We need not care whether
+                        * that function is strict.  Because the handling of nulls is
+                        * different, we can't just reuse EEOP_FUNCEXPR.
                         */
                        FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
 
                        /* 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... */
                                *op->resvalue = BoolGetDatum(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... */
                                *op->resvalue = BoolGetDatum(true);
@@ -1141,12 +1142,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                {
                        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->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->resnull = false;
@@ -1167,12 +1168,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                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;
 
                        /* 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;
 
@@ -1190,8 +1191,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                        }
 
                        /* Arguments aren't equal, so return the first one */
-                       *op->resvalue = fcinfo->arg[0];
-                       *op->resnull = fcinfo->argnull[0];
+                       *op->resvalue = fcinfo->args[0].value;
+                       *op->resnull = fcinfo->args[0].isnull;
 
                        EEO_NEXT();
                }
@@ -1257,7 +1258,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 
                        /* force NULL result if strict fn and NULL input */
                        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;
                                EEO_JUMP(op->d.rowcompare_step.jumpnull);
@@ -1496,10 +1497,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                /* evaluate a strict aggregate deserialization function */
                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 */
-                       if (argnull[0])
+                       if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
                                EEO_JUMP(op->d.agg_deserialize.jumpnull);
 
                        /* fallthrough */
@@ -1529,7 +1528,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                 * Check that a strict aggregate transition / combination function's
                 * input is not NULL.
                 */
-               EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK)
+               EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
                {
                        int                     argno;
                        bool       *nulls = op->d.agg_strict_input_check.nulls;
@@ -1543,6 +1542,20 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
                        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.
                 */
@@ -1613,7 +1626,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 
                        Assert(pertrans->transtypeByVal);
 
-                       fcinfo = &pertrans->transfn_fcinfo;
+                       fcinfo = pertrans->transfn_fcinfo;
 
                        /* cf. select_current_set() */
                        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 */
                        oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
 
-                       fcinfo->arg[0] = pergroup->transValue;
-                       fcinfo->argnull[0] = pergroup->transValueIsNull;
+                       fcinfo->args[0].value = pergroup->transValue;
+                       fcinfo->args[0].isnull = pergroup->transValueIsNull;
                        fcinfo->isnull = false; /* just in case transfn doesn't set it */
 
                        newVal = FunctionCallInvoke(fcinfo);
@@ -1664,7 +1677,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 
                        Assert(!pertrans->transtypeByVal);
 
-                       fcinfo = &pertrans->transfn_fcinfo;
+                       fcinfo = pertrans->transfn_fcinfo;
 
                        /* cf. select_current_set() */
                        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 */
                        oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
 
-                       fcinfo->arg[0] = pergroup->transValue;
-                       fcinfo->argnull[0] = pergroup->transValueIsNull;
+                       fcinfo->args[0].value = pergroup->transValue;
+                       fcinfo->args[0].isnull = pergroup->transValueIsNull;
                        fcinfo->isnull = false; /* just in case transfn doesn't set it */
 
                        newVal = FunctionCallInvoke(fcinfo);
@@ -2075,7 +2088,7 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
 {
        ExprEvalStep *op = &state->steps[0];
        FunctionCallInfo fcinfo;
-       bool       *argnull;
+       NullableDatum *args;
        int                     argno;
        Datum           d;
 
@@ -2089,12 +2102,12 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
        op++;
 
        fcinfo = op->d.func.fcinfo_data;
-       argnull = fcinfo->argnull;
+       args = fcinfo->args;
 
        /* strict function, so check for NULL args */
        for (argno = 0; argno < op->d.func.nargs; argno++)
        {
-               if (argnull[argno])
+               if (args[argno].isnull)
                {
                        *isnull = true;
                        return (Datum) 0;
@@ -2220,14 +2233,14 @@ ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
 
        FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
        PgStat_FunctionCallUsage fcusage;
-       bool       *argnull = fcinfo->argnull;
+       NullableDatum *args = fcinfo->args;
        int                     argno;
        Datum           d;
 
        /* strict function, so check for NULL args */
        for (argno = 0; argno < op->d.func.nargs; argno++)
        {
-               if (argnull[argno])
+               if (args[argno].isnull)
                {
                        *op->resnull = true;
                        return;
@@ -2317,8 +2330,8 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 void
 ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
 {
+       LOCAL_FCINFO(fcinfo, 0);
        SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-       FunctionCallInfoData fcinfo;
 
        *op->resnull = false;
 
@@ -2350,24 +2363,24 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
                case SVFOP_CURRENT_ROLE:
                case SVFOP_CURRENT_USER:
                case SVFOP_USER:
-                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
-                       *op->resvalue = current_user(&fcinfo);
-                       *op->resnull = fcinfo.isnull;
+                       InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       *op->resvalue = current_user(fcinfo);
+                       *op->resnull = fcinfo->isnull;
                        break;
                case SVFOP_SESSION_USER:
-                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
-                       *op->resvalue = session_user(&fcinfo);
-                       *op->resnull = fcinfo.isnull;
+                       InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       *op->resvalue = session_user(fcinfo);
+                       *op->resnull = fcinfo->isnull;
                        break;
                case SVFOP_CURRENT_CATALOG:
-                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
-                       *op->resvalue = current_database(&fcinfo);
-                       *op->resnull = fcinfo.isnull;
+                       InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       *op->resvalue = current_database(fcinfo);
+                       *op->resnull = fcinfo->isnull;
                        break;
                case SVFOP_CURRENT_SCHEMA:
-                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
-                       *op->resvalue = current_schema(&fcinfo);
-                       *op->resnull = fcinfo.isnull;
+                       InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       *op->resvalue = current_schema(fcinfo);
+                       *op->resnull = fcinfo->isnull;
                        break;
        }
 }
@@ -2800,8 +2813,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
        int                     off;
 
        /* set at initialization */
-       Assert(fcinfo->argnull[0] == false);
-       Assert(fcinfo->argnull[1] == false);
+       Assert(fcinfo->args[0].isnull == false);
+       Assert(fcinfo->args[1].isnull == false);
 
        /* default to null result */
        *op->resnull = true;
@@ -2823,8 +2836,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
                        int                     cmpresult;
 
                        /* apply comparison function */
-                       fcinfo->arg[0] = *op->resvalue;
-                       fcinfo->arg[1] = values[off];
+                       fcinfo->args[0].value = *op->resvalue;
+                       fcinfo->args[1].value = values[off];
 
                        fcinfo->isnull = false;
                        cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
@@ -3324,7 +3337,7 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
  * Evaluate "scalar op ANY/ALL (array)".
  *
  * 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
  * 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
         * point in iterating the loop.
         */
-       if (fcinfo->argnull[0] && strictfunc)
+       if (fcinfo->args[0].isnull && strictfunc)
        {
                *op->resnull = true;
                return;
@@ -3416,20 +3429,20 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
                /* Get array element, checking for NULL */
                if (bitmap && (*bitmap & bitmask) == 0)
                {
-                       fcinfo->arg[1] = (Datum) 0;
-                       fcinfo->argnull[1] = true;
+                       fcinfo->args[1].value = (Datum) 0;
+                       fcinfo->args[1].isnull = true;
                }
                else
                {
                        elt = fetch_att(s, typbyval, typlen);
                        s = att_addlength_pointer(s, typlen, s);
                        s = (char *) att_align_nominal(s, typalign);
-                       fcinfo->arg[1] = elt;
-                       fcinfo->argnull[1] = false;
+                       fcinfo->args[1].value = elt;
+                       fcinfo->args[1].isnull = false;
                }
 
                /* Call comparison function */
-               if (fcinfo->argnull[1] && strictfunc)
+               if (fcinfo->args[1].isnull && strictfunc)
                {
                        fcinfo->isnull = true;
                        thisresult = (Datum) 0;
@@ -4044,7 +4057,7 @@ ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
 void
 ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup)
 {
-       FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
+       FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
        MemoryContext oldContext;
 
        /*
@@ -4055,7 +4068,7 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup
         */
        oldContext = MemoryContextSwitchTo(
                                                                           aggstate->curaggcontext->ecxt_per_tuple_memory);
-       pergroup->transValue = datumCopy(fcinfo->arg[1],
+       pergroup->transValue = datumCopy(fcinfo->args[1].value,
                                                                         pertrans->transtypeByVal,
                                                                         pertrans->transtypeLen);
        pergroup->transValueIsNull = false;
index 0c086c529043c376f961e1ad1d09fefaad6c8641..265250186a14d4ac78a159388cd5e76c45078f10 100644 (file)
@@ -109,7 +109,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
        Oid                     funcrettype;
        bool            returnsTuple;
        bool            returnsSet = false;
-       FunctionCallInfoData fcinfo;
+       FunctionCallInfo fcinfo;
        PgStat_FunctionCallUsage fcusage;
        ReturnSetInfo rsinfo;
        HeapTupleData tmptup;
@@ -141,6 +141,8 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
        rsinfo.setResult = NULL;
        rsinfo.setDesc = NULL;
 
+       fcinfo = palloc(SizeForFunctionCallInfo(list_length(setexpr->args)));
+
        /*
         * Normally the passed expression tree will be a SetExprState, since the
         * 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.
                 */
                returnsSet = setexpr->funcReturnsSet;
-               InitFunctionCallInfoData(fcinfo, &(setexpr->func),
+               InitFunctionCallInfoData(*fcinfo, &(setexpr->func),
                                                                 list_length(setexpr->args),
-                                                                setexpr->fcinfo_data.fncollation,
+                                                                setexpr->fcinfo->fncollation,
                                                                 NULL, (Node *) &rsinfo);
 
                /*
@@ -174,7 +176,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                 */
                MemoryContextReset(argContext);
                oldcontext = MemoryContextSwitchTo(argContext);
-               ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext);
+               ExecEvalFuncArgs(fcinfo, setexpr->args, econtext);
                MemoryContextSwitchTo(oldcontext);
 
                /*
@@ -186,9 +188,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                {
                        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;
                        }
                }
@@ -196,7 +198,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
        else
        {
                /* 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 */
                if (!setexpr->elidedFuncState)
                {
-                       pgstat_init_function_usage(&fcinfo, &fcusage);
+                       pgstat_init_function_usage(fcinfo, &fcusage);
 
-                       fcinfo.isnull = false;
+                       fcinfo->isnull = false;
                        rsinfo.isDone = ExprSingleResult;
-                       result = FunctionCallInvoke(&fcinfo);
+                       result = FunctionCallInvoke(fcinfo);
 
                        pgstat_end_function_usage(&fcusage,
                                                                          rsinfo.isDone != ExprMultipleResult);
@@ -236,7 +238,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                else
                {
                        result =
-                               ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull);
+                               ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
                        rsinfo.isDone = ExprSingleResult;
                }
 
@@ -277,7 +279,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                         */
                        if (returnsTuple)
                        {
-                               if (!fcinfo.isnull)
+                               if (!fcinfo->isnull)
                                {
                                        HeapTupleHeader td = DatumGetHeapTupleHeader(result);
 
@@ -338,7 +340,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
                        else
                        {
                                /* 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
         * would reference freed memory after the first returned row.
         */
-       fcinfo = &fcache->fcinfo_data;
+       fcinfo = fcache->fcinfo;
        arguments = fcache->args;
        if (!fcache->setArgsValid)
        {
@@ -587,7 +589,7 @@ restart:
        {
                for (i = 0; i < fcinfo->nargs; i++)
                {
-                       if (fcinfo->argnull[i])
+                       if (fcinfo->args[i].isnull)
                        {
                                callit = false;
                                break;
@@ -678,6 +680,7 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node,
                   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
 {
        AclResult       aclresult;
+       size_t          numargs = list_length(sexpr->args);
 
        /* Check permission to call function */
        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));
 
        /* Initialize the function call parameter struct as well */
-       InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func),
-                                                        list_length(sexpr->args),
+       sexpr->fcinfo =
+               (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
+       InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func),
+                                                        numargs,
                                                         input_collation, NULL, NULL);
 
        /* If function returns set, check if that's allowed by caller */
@@ -820,9 +825,9 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
        {
                ExprState  *argstate = (ExprState *) lfirst(arg);
 
-               fcinfo->arg[i] = ExecEvalExpr(argstate,
-                                                                         econtext,
-                                                                         &fcinfo->argnull[i]);
+               fcinfo->args[i].value = ExecEvalExpr(argstate,
+                                                                                        econtext,
+                                                                                        &fcinfo->args[i].isnull);
                i++;
        }
 
index de41588105e111578110c45ed75625d43a9f0637..c6b7203f81390e8167206c308793218d2ec920a3 100644 (file)
@@ -933,8 +933,8 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
                {
                        ParamExternData *prm = &paramLI->params[i];
 
-                       prm->value = fcinfo->arg[i];
-                       prm->isnull = fcinfo->argnull[i];
+                       prm->value = fcinfo->args[i].value;
+                       prm->isnull = fcinfo->args[i].isnull;
                        prm->pflags = 0;
                        prm->ptype = fcache->pinfo->argtypes[i];
                }
index 508c9195743aafb8482fc1c30da19ff3a4adc292..2a260a71f241329408077137e91e902b65b67e81 100644 (file)
@@ -553,7 +553,7 @@ advance_transition_function(AggState *aggstate,
                                                        AggStatePerTrans pertrans,
                                                        AggStatePerGroup pergroupstate)
 {
-       FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
+       FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
        MemoryContext oldContext;
        Datum           newVal;
 
@@ -568,7 +568,7 @@ advance_transition_function(AggState *aggstate,
 
                for (i = 1; i <= numTransInputs; i++)
                {
-                       if (fcinfo->argnull[i])
+                       if (fcinfo->args[i].isnull)
                                return;
                }
                if (pergroupstate->noTransValue)
@@ -584,7 +584,7 @@ advance_transition_function(AggState *aggstate,
                         */
                        oldContext = MemoryContextSwitchTo(
                                                                                           aggstate->curaggcontext->ecxt_per_tuple_memory);
-                       pergroupstate->transValue = datumCopy(fcinfo->arg[1],
+                       pergroupstate->transValue = datumCopy(fcinfo->args[1].value,
                                                                                                  pertrans->transtypeByVal,
                                                                                                  pertrans->transtypeLen);
                        pergroupstate->transValueIsNull = false;
@@ -613,8 +613,8 @@ advance_transition_function(AggState *aggstate,
        /*
         * OK to call the transition function
         */
-       fcinfo->arg[0] = pergroupstate->transValue;
-       fcinfo->argnull[0] = pergroupstate->transValueIsNull;
+       fcinfo->args[0].value = pergroupstate->transValue;
+       fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
        fcinfo->isnull = false;         /* just in case transfn doesn't set it */
 
        newVal = FunctionCallInvoke(fcinfo);
@@ -717,7 +717,7 @@ process_ordered_aggregate_single(AggState *aggstate,
        bool            isDistinct = (pertrans->numDistinctCols > 0);
        Datum           newAbbrevVal = (Datum) 0;
        Datum           oldAbbrevVal = (Datum) 0;
-       FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
+       FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
        Datum      *newVal;
        bool       *isNull;
 
@@ -726,8 +726,8 @@ process_ordered_aggregate_single(AggState *aggstate,
        tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
 
        /* Load the column into argument 1 (arg 0 will be transition value) */
-       newVal = fcinfo->arg + 1;
-       isNull = fcinfo->argnull + 1;
+       newVal = &fcinfo->args[1].value;
+       isNull = &fcinfo->args[1].isnull;
 
        /*
         * 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)
 {
        ExprContext *tmpcontext = aggstate->tmpcontext;
-       FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
+       FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
        TupleTableSlot *slot1 = pertrans->sortslot;
        TupleTableSlot *slot2 = pertrans->uniqslot;
        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 */
                        for (i = 0; i < numTransInputs; i++)
                        {
-                               fcinfo->arg[i + 1] = slot1->tts_values[i];
-                               fcinfo->argnull[i + 1] = slot1->tts_isnull[i];
+                               fcinfo->args[i + 1].value = slot1->tts_values[i];
+                               fcinfo->args[i + 1].isnull = slot1->tts_isnull[i];
                        }
 
                        advance_transition_function(aggstate, pertrans, pergroupstate);
@@ -897,7 +897,7 @@ finalize_aggregate(AggState *aggstate,
                                   AggStatePerGroup pergroupstate,
                                   Datum *resultVal, bool *resultIsNull)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        bool            anynull = false;
        MemoryContext oldContext;
        int                     i;
@@ -917,10 +917,10 @@ finalize_aggregate(AggState *aggstate,
        {
                ExprState  *expr = (ExprState *) lfirst(lc);
 
-               fcinfo.arg[i] = ExecEvalExpr(expr,
-                                                                        aggstate->ss.ps.ps_ExprContext,
-                                                                        &fcinfo.argnull[i]);
-               anynull |= fcinfo.argnull[i];
+               fcinfo->args[i].value = ExecEvalExpr(expr,
+                                                                                        aggstate->ss.ps.ps_ExprContext,
+                                                                                        &fcinfo->args[i].isnull);
+               anynull |= fcinfo->args[i].isnull;
                i++;
        }
 
@@ -934,27 +934,28 @@ finalize_aggregate(AggState *aggstate,
                /* set up aggstate->curperagg for AggGetAggref() */
                aggstate->curperagg = peragg;
 
-               InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
+               InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
                                                                 numFinalArgs,
                                                                 pertrans->aggCollation,
                                                                 (void *) aggstate, NULL);
 
                /* Fill in the transition state value */
-               fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
-                                                                                                  pergroupstate->transValueIsNull,
-                                                                                                  pertrans->transtypeLen);
-               fcinfo.argnull[0] = pergroupstate->transValueIsNull;
+               fcinfo->args[0].value =
+                       MakeExpandedObjectReadOnly(pergroupstate->transValue,
+                                                                          pergroupstate->transValueIsNull,
+                                                                          pertrans->transtypeLen);
+               fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
                anynull |= pergroupstate->transValueIsNull;
 
                /* Fill any remaining argument positions with nulls */
                for (; i < numFinalArgs; i++)
                {
-                       fcinfo.arg[i] = (Datum) 0;
-                       fcinfo.argnull[i] = true;
+                       fcinfo->args[i].value = (Datum) 0;
+                       fcinfo->args[i].isnull = true;
                        anynull = true;
                }
 
-               if (fcinfo.flinfo->fn_strict && anynull)
+               if (fcinfo->flinfo->fn_strict && anynull)
                {
                        /* don't call a strict function with NULL inputs */
                        *resultVal = (Datum) 0;
@@ -962,8 +963,8 @@ finalize_aggregate(AggState *aggstate,
                }
                else
                {
-                       *resultVal = FunctionCallInvoke(&fcinfo);
-                       *resultIsNull = fcinfo.isnull;
+                       *resultVal = FunctionCallInvoke(fcinfo);
+                       *resultIsNull = fcinfo->isnull;
                }
                aggstate->curperagg = NULL;
        }
@@ -1018,12 +1019,13 @@ finalize_partialaggregate(AggState *aggstate,
                }
                else
                {
-                       FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
+                       FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
 
-                       fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
-                                                                                                               pergroupstate->transValueIsNull,
-                                                                                                               pertrans->transtypeLen);
-                       fcinfo->argnull[0] = pergroupstate->transValueIsNull;
+                       fcinfo->args[0].value =
+                               MakeExpandedObjectReadOnly(pergroupstate->transValue,
+                                                                                  pergroupstate->transValueIsNull,
+                                                                                  pertrans->transtypeLen);
+                       fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
 
                        *resultVal = FunctionCallInvoke(fcinfo);
                        *resultIsNull = fcinfo->isnull;
@@ -2927,7 +2929,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
                fmgr_info(aggtransfn, &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,
                                                                 2,
                                                                 pertrans->aggCollation,
@@ -2947,6 +2951,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
        else
        {
                Expr       *transfnexpr;
+               size_t          numInputs = pertrans->numTransInputs + 1;
 
                /*
                 * 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_set_expr((Node *) transfnexpr, &pertrans->transfn);
 
-               InitFunctionCallInfoData(pertrans->transfn_fcinfo,
+               pertrans->transfn_fcinfo =
+                       (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numInputs));
+               InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
                                                                 &pertrans->transfn,
-                                                                pertrans->numTransInputs + 1,
+                                                                numInputs,
                                                                 pertrans->aggCollation,
                                                                 (void *) aggstate, NULL);
 
@@ -3003,7 +3010,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
                fmgr_info(aggserialfn, &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,
                                                                 1,
                                                                 InvalidOid,
@@ -3017,7 +3026,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans,
                fmgr_info(aggdeserialfn, &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,
                                                                 2,
                                                                 InvalidOid,
index 7ae56074ca8845394d974a3a46d269551c138acf..731391f1907b30b127c6030e83e97b5afde74106 100644 (file)
@@ -241,10 +241,9 @@ advance_windowaggregate(WindowAggState *winstate,
                                                WindowStatePerFunc perfuncstate,
                                                WindowStatePerAgg peraggstate)
 {
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
        int                     numArguments = perfuncstate->numArguments;
-       FunctionCallInfoData fcinfodata;
-       FunctionCallInfo fcinfo = &fcinfodata;
        Datum           newVal;
        ListCell   *arg;
        int                     i;
@@ -273,8 +272,8 @@ advance_windowaggregate(WindowAggState *winstate,
        {
                ExprState  *argstate = (ExprState *) lfirst(arg);
 
-               fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
-                                                                         &fcinfo->argnull[i]);
+               fcinfo->args[i].value = ExecEvalExpr(argstate, econtext,
+                                                                                        &fcinfo->args[i].isnull);
                i++;
        }
 
@@ -287,7 +286,7 @@ advance_windowaggregate(WindowAggState *winstate,
                 */
                for (i = 1; i <= numArguments; i++)
                {
-                       if (fcinfo->argnull[i])
+                       if (fcinfo->args[i].isnull)
                        {
                                MemoryContextSwitchTo(oldContext);
                                return;
@@ -306,7 +305,7 @@ advance_windowaggregate(WindowAggState *winstate,
                if (peraggstate->transValueCount == 0 && peraggstate->transValueIsNull)
                {
                        MemoryContextSwitchTo(peraggstate->aggcontext);
-                       peraggstate->transValue = datumCopy(fcinfo->arg[1],
+                       peraggstate->transValue = datumCopy(fcinfo->args[1].value,
                                                                                                peraggstate->transtypeByVal,
                                                                                                peraggstate->transtypeLen);
                        peraggstate->transValueIsNull = false;
@@ -339,8 +338,8 @@ advance_windowaggregate(WindowAggState *winstate,
                                                         numArguments + 1,
                                                         perfuncstate->winCollation,
                                                         (void *) winstate, NULL);
-       fcinfo->arg[0] = peraggstate->transValue;
-       fcinfo->argnull[0] = peraggstate->transValueIsNull;
+       fcinfo->args[0].value = peraggstate->transValue;
+       fcinfo->args[0].isnull = peraggstate->transValueIsNull;
        winstate->curaggcontext = peraggstate->aggcontext;
        newVal = FunctionCallInvoke(fcinfo);
        winstate->curaggcontext = NULL;
@@ -418,10 +417,9 @@ advance_windowaggregate_base(WindowAggState *winstate,
                                                         WindowStatePerFunc perfuncstate,
                                                         WindowStatePerAgg peraggstate)
 {
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
        int                     numArguments = perfuncstate->numArguments;
-       FunctionCallInfoData fcinfodata;
-       FunctionCallInfo fcinfo = &fcinfodata;
        Datum           newVal;
        ListCell   *arg;
        int                     i;
@@ -450,8 +448,8 @@ advance_windowaggregate_base(WindowAggState *winstate,
        {
                ExprState  *argstate = (ExprState *) lfirst(arg);
 
-               fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
-                                                                         &fcinfo->argnull[i]);
+               fcinfo->args[i].value = ExecEvalExpr(argstate, econtext,
+                                                                                        &fcinfo->args[i].isnull);
                i++;
        }
 
@@ -464,7 +462,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
                 */
                for (i = 1; i <= numArguments; i++)
                {
-                       if (fcinfo->argnull[i])
+                       if (fcinfo->args[i].isnull)
                        {
                                MemoryContextSwitchTo(oldContext);
                                return true;
@@ -510,8 +508,8 @@ advance_windowaggregate_base(WindowAggState *winstate,
                                                         numArguments + 1,
                                                         perfuncstate->winCollation,
                                                         (void *) winstate, NULL);
-       fcinfo->arg[0] = peraggstate->transValue;
-       fcinfo->argnull[0] = peraggstate->transValueIsNull;
+       fcinfo->args[0].value = peraggstate->transValue;
+       fcinfo->args[0].isnull = peraggstate->transValueIsNull;
        winstate->curaggcontext = peraggstate->aggcontext;
        newVal = FunctionCallInvoke(fcinfo);
        winstate->curaggcontext = NULL;
@@ -591,30 +589,31 @@ finalize_windowaggregate(WindowAggState *winstate,
         */
        if (OidIsValid(peraggstate->finalfn_oid))
        {
+               LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
                int                     numFinalArgs = peraggstate->numFinalArgs;
-               FunctionCallInfoData fcinfo;
                bool            anynull;
                int                     i;
 
-               InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn),
+               InitFunctionCallInfoData(fcinfodata.fcinfo, &(peraggstate->finalfn),
                                                                 numFinalArgs,
                                                                 perfuncstate->winCollation,
                                                                 (void *) winstate, NULL);
-               fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue,
-                                                                                                  peraggstate->transValueIsNull,
-                                                                                                  peraggstate->transtypeLen);
-               fcinfo.argnull[0] = peraggstate->transValueIsNull;
+               fcinfo->args[0].value =
+                       MakeExpandedObjectReadOnly(peraggstate->transValue,
+                                                                          peraggstate->transValueIsNull,
+                                                                          peraggstate->transtypeLen);
+               fcinfo->args[0].isnull = peraggstate->transValueIsNull;
                anynull = peraggstate->transValueIsNull;
 
                /* Fill any remaining argument positions with nulls */
                for (i = 1; i < numFinalArgs; i++)
                {
-                       fcinfo.arg[i] = (Datum) 0;
-                       fcinfo.argnull[i] = true;
+                       fcinfo->args[i].value = (Datum) 0;
+                       fcinfo->args[i].isnull = true;
                        anynull = true;
                }
 
-               if (fcinfo.flinfo->fn_strict && anynull)
+               if (fcinfo->flinfo->fn_strict && anynull)
                {
                        /* don't call a strict function with NULL inputs */
                        *result = (Datum) 0;
@@ -623,9 +622,9 @@ finalize_windowaggregate(WindowAggState *winstate,
                else
                {
                        winstate->curaggcontext = peraggstate->aggcontext;
-                       *result = FunctionCallInvoke(&fcinfo);
+                       *result = FunctionCallInvoke(fcinfo);
                        winstate->curaggcontext = NULL;
-                       *isnull = fcinfo.isnull;
+                       *isnull = fcinfo->isnull;
                }
        }
        else
@@ -1032,7 +1031,7 @@ static void
 eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
                                        Datum *result, bool *isnull)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        MemoryContext oldContext;
 
        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
         * goes through the WindowObject, which is passed via fcinfo->context.
         */
-       InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo),
+       InitFunctionCallInfoData(*fcinfo, &(perfuncstate->flinfo),
                                                         perfuncstate->numArguments,
                                                         perfuncstate->winCollation,
                                                         (void *) perfuncstate->winobj, 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 */
        winstate->curaggcontext = NULL;
 
-       *result = FunctionCallInvoke(&fcinfo);
-       *isnull = fcinfo.isnull;
+       *result = FunctionCallInvoke(fcinfo);
+       *isnull = fcinfo->isnull;
 
        /*
         * 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
         * tuple, as is entirely possible.)
         */
-       if (!perfuncstate->resulttypeByVal && !fcinfo.isnull &&
+       if (!perfuncstate->resulttypeByVal && !fcinfo->isnull &&
                !MemoryContextContains(CurrentMemoryContext,
                                                           DatumGetPointer(*result)))
                *result = datumCopy(*result,
index 6b9aaf49c68fc91eddde848db0e7f333c30b325e..c4d38a64a44be052a8018894595d5d4053d98519 100644 (file)
@@ -53,6 +53,7 @@ LLVMTypeRef TypeSizeT;
 LLVMTypeRef TypeParamBool;
 LLVMTypeRef TypeStorageBool;
 LLVMTypeRef TypePGFunction;
+LLVMTypeRef StructNullableDatum;
 LLVMTypeRef StructHeapTupleFieldsField3;
 LLVMTypeRef StructHeapTupleFields;
 LLVMTypeRef StructHeapTupleHeaderData;
@@ -807,6 +808,7 @@ llvm_create_types(void)
        TypeParamBool = load_return_type(mod, "FunctionReturningBool");
        TypeStorageBool = load_type(mod, "TypeStorageBool");
        TypePGFunction = load_type(mod, "TypePGFunction");
+       StructNullableDatum = load_type(mod, "StructNullableDatum");
        StructExprContext = load_type(mod, "StructExprContext");
        StructExprEvalStep = load_type(mod, "StructExprEvalStep");
        StructExprState = load_type(mod, "StructExprState");
index 70b55dd202e5449305404c33bd78c097f2e3300b..351f6ec7e1a61c1a37ec4d28082240fa8d23cb6a 100644 (file)
@@ -570,7 +570,6 @@ llvm_compile_expr(ExprState *state)
                                        LLVMBasicBlockRef b_nonull;
                                        int                     argno;
                                        LLVMValueRef v_fcinfo;
-                                       LLVMValueRef v_argnullp;
                                        LLVMBasicBlockRef *b_checkargnulls;
 
                                        /*
@@ -587,12 +586,6 @@ llvm_compile_expr(ExprState *state)
                                        v_fcinfo =
                                                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
                                         * called, it'll be reset
@@ -624,8 +617,7 @@ llvm_compile_expr(ExprState *state)
                                                        b_argnotnull = b_checkargnulls[argno + 1];
 
                                                /* and finally load & check NULLness of arg */
-                                               v_argisnull = l_load_struct_gep(b, v_argnullp,
-                                                                                                               argno, "");
+                                               v_argisnull = l_funcnull(b, v_fcinfo, argno);
                                                LLVMBuildCondBr(b,
                                                                                LLVMBuildICmp(b, LLVMIntEQ,
                                                                                                          v_argisnull,
@@ -1276,10 +1268,6 @@ llvm_compile_expr(ExprState *state)
                                        LLVMValueRef v_fn_addr_out,
                                                                v_fn_addr_in;
                                        LLVMValueRef v_fcinfo_in_isnullp;
-                                       LLVMValueRef v_in_argp,
-                                                               v_out_argp;
-                                       LLVMValueRef v_in_argnullp,
-                                                               v_out_argnullp;
                                        LLVMValueRef v_retval;
                                        LLVMValueRef v_resvalue;
                                        LLVMValueRef v_resnull;
@@ -1313,22 +1301,6 @@ llvm_compile_expr(ExprState *state)
                                                LLVMBuildStructGEP(b, v_fcinfo_in,
                                                                                   FIELDNO_FUNCTIONCALLINFODATA_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 */
                                        v_resnull = LLVMBuildLoad(b, v_resnullp, "");
@@ -1348,11 +1320,10 @@ llvm_compile_expr(ExprState *state)
                                        /* set arg[0] */
                                        LLVMBuildStore(b,
                                                                   v_resvalue,
-                                                                  LLVMBuildStructGEP(b, v_out_argp, 0, ""));
+                                                                  l_funcvaluep(b, v_fcinfo_out, 0));
                                        LLVMBuildStore(b,
                                                                   l_sbool_const(0),
-                                                                  LLVMBuildStructGEP(b, v_out_argnullp,
-                                                                                                         0, ""));
+                                                                  l_funcnullp(b, v_fcinfo_out, 0));
                                        /* and call output function (can never return NULL) */
                                        v_output = LLVMBuildCall(b, v_fn_addr_out, &v_fcinfo_out,
                                                                                         1, "funccall_coerce_out");
@@ -1399,9 +1370,9 @@ llvm_compile_expr(ExprState *state)
                                        /* set arguments */
                                        /* arg0: output */
                                        LLVMBuildStore(b, v_output,
-                                                                  LLVMBuildStructGEP(b, v_in_argp, 0, ""));
+                                                                  l_funcvaluep(b, v_fcinfo_in, 0));
                                        LLVMBuildStore(b, v_resnull,
-                                                                  LLVMBuildStructGEP(b, v_in_argnullp, 0, ""));
+                                                                  l_funcnullp(b, v_fcinfo_in, 0));
 
                                        /* arg1: ioparam: 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_isnull;
 
-                                       LLVMValueRef v_argnullp;
                                        LLVMValueRef v_argnull0,
                                                                v_argisnull0;
                                        LLVMValueRef v_argnull1,
@@ -1449,18 +1419,11 @@ llvm_compile_expr(ExprState *state)
 
                                        v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
 
-                                       v_argnullp =
-                                               LLVMBuildStructGEP(b,
-                                                                                  v_fcinfo,
-                                                                                  FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
-                                                                                  "v_argnullp");
-
-                                       /* load argnull[0|1] for both arguments */
-                                       v_argnull0 = l_load_struct_gep(b, v_argnullp, 0, "");
+                                       /* load args[0|1].isnull for both arguments */
+                                       v_argnull0 = l_funcnull(b, v_fcinfo, 0);
                                        v_argisnull0 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull0,
                                                                                                 l_sbool_const(1), "");
-
-                                       v_argnull1 = l_load_struct_gep(b, v_argnullp, 1, "");
+                                       v_argnull1 = l_funcnull(b, v_fcinfo, 1);
                                        v_argisnull1 = LLVMBuildICmp(b, LLVMIntEQ, v_argnull1,
                                                                                                 l_sbool_const(1), "");
 
@@ -1532,11 +1495,9 @@ llvm_compile_expr(ExprState *state)
 
                                        LLVMValueRef v_fcinfo;
                                        LLVMValueRef v_fcinfo_isnull;
-                                       LLVMValueRef v_argnullp;
                                        LLVMValueRef v_argnull0;
                                        LLVMValueRef v_argnull1;
                                        LLVMValueRef v_anyargisnull;
-                                       LLVMValueRef v_argp;
                                        LLVMValueRef v_arg0;
                                        LLVMBasicBlockRef b_hasnull;
                                        LLVMBasicBlockRef b_nonull;
@@ -1553,21 +1514,9 @@ llvm_compile_expr(ExprState *state)
 
                                        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 */
-                                       v_argnull0 = l_load_struct_gep(b, v_argnullp, 0, "");
-                                       v_argnull1 = l_load_struct_gep(b, v_argnullp, 1, "");
+                                       v_argnull0 = l_funcnull(b, v_fcinfo, 0);
+                                       v_argnull1 = l_funcnull(b, v_fcinfo, 1);
 
                                        v_anyargisnull =
                                                LLVMBuildOr(b,
@@ -1581,7 +1530,7 @@ llvm_compile_expr(ExprState *state)
 
                                        /* one (or both) of the arguments are null, return arg[0] */
                                        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_arg0, v_resvaluep);
                                        LLVMBuildBr(b, opblocks[i + 1]);
@@ -1680,7 +1629,6 @@ llvm_compile_expr(ExprState *state)
                                        if (op->d.rowcompare_step.finfo->fn_strict)
                                        {
                                                LLVMValueRef v_fcinfo;
-                                               LLVMValueRef v_argnullp;
                                                LLVMValueRef v_argnull0;
                                                LLVMValueRef v_argnull1;
                                                LLVMValueRef v_anyargisnull;
@@ -1688,13 +1636,8 @@ llvm_compile_expr(ExprState *state)
                                                v_fcinfo = l_ptr_const(fcinfo,
                                                                                           l_ptr(StructFunctionCallInfoData));
 
-                                               v_argnullp =
-                                                       LLVMBuildStructGEP(b, v_fcinfo,
-                                                                                          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_argnull0 = l_funcnull(b, v_fcinfo, 0);
+                                               v_argnull1 = l_funcnull(b, v_fcinfo, 1);
 
                                                v_anyargisnull =
                                                        LLVMBuildOr(b,
@@ -2021,7 +1964,6 @@ llvm_compile_expr(ExprState *state)
                                {
                                        FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
                                        LLVMValueRef v_fcinfo;
-                                       LLVMValueRef v_argnullp;
                                        LLVMValueRef v_argnull0;
                                        LLVMBasicBlockRef b_deserialize;
 
@@ -2030,14 +1972,7 @@ llvm_compile_expr(ExprState *state)
 
                                        v_fcinfo = l_ptr_const(fcinfo,
                                                                                   l_ptr(StructFunctionCallInfoData));
-
-                                       v_argnullp =
-                                               LLVMBuildStructGEP(b,
-                                                                                  v_fcinfo,
-                                                                                  FIELDNO_FUNCTIONCALLINFODATA_ARGNULL,
-                                                                                  "v_argnullp");
-                                       v_argnull0 =
-                                               l_load_struct_gep(b, v_argnullp, 0, "v_argnull0");
+                                       v_argnull0 = l_funcnull(b, v_fcinfo, 0);
 
                                        LLVMBuildCondBr(b,
                                                                        LLVMBuildICmp(b,
@@ -2079,20 +2014,24 @@ llvm_compile_expr(ExprState *state)
                                        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;
+                                       NullableDatum *args = op->d.agg_strict_input_check.args;
                                        bool       *nulls = op->d.agg_strict_input_check.nulls;
                                        int                     jumpnull;
                                        int                     argno;
 
-                                       LLVMValueRef v_nullp;
+                                       LLVMValueRef v_argsp;
+                                       LLVMValueRef v_nullsp;
                                        LLVMBasicBlockRef *b_checknulls;
 
                                        Assert(nargs > 0);
 
                                        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 */
                                        b_checknulls = palloc(sizeof(LLVMBasicBlockRef *) * nargs);
@@ -2120,7 +2059,18 @@ llvm_compile_expr(ExprState *state)
                                                else
                                                        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,
                                                                                LLVMBuildICmp(b,
@@ -2291,8 +2241,6 @@ llvm_compile_expr(ExprState *state)
                                        LLVMValueRef v_aggstatep;
                                        LLVMValueRef v_fcinfo;
                                        LLVMValueRef v_fcinfo_isnull;
-                                       LLVMValueRef v_argp,
-                                                               v_argnullp;
 
                                        LLVMValueRef v_transvaluep;
                                        LLVMValueRef v_transnullp;
@@ -2319,7 +2267,7 @@ llvm_compile_expr(ExprState *state)
                                        aggstate = op->d.agg_trans.aggstate;
                                        pertrans = op->d.agg_trans.pertrans;
 
-                                       fcinfo = &pertrans->transfn_fcinfo;
+                                       fcinfo = pertrans->transfn_fcinfo;
 
                                        v_aggstatep = l_ptr_const(aggstate,
                                                                                          l_ptr(StructAggState));
@@ -2344,18 +2292,6 @@ llvm_compile_expr(ExprState *state)
 
                                        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");
-
                                        v_aggcontext = l_ptr_const(op->d.agg_trans.aggcontext,
                                                                                           l_ptr(StructExprContext));
 
@@ -2387,7 +2323,7 @@ llvm_compile_expr(ExprState *state)
                                                                        l_ptr(StructMemoryContextData));
                                        v_oldcontext = l_mcxt_switch(mod, b, v_tmpcontext);
 
-                                       /* store transvalue in fcinfo->arg/argnull[0] */
+                                       /* store transvalue in fcinfo->args[0] */
                                        v_transvaluep =
                                                LLVMBuildStructGEP(b, v_pergroupp,
                                                                                   FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE,
@@ -2399,10 +2335,10 @@ llvm_compile_expr(ExprState *state)
                                        LLVMBuildStore(b,
                                                                   LLVMBuildLoad(b, v_transvaluep,
                                                                                                 "transvalue"),
-                                                                  LLVMBuildStructGEP(b, v_argp, 0, ""));
+                                                                  l_funcvaluep(b, v_fcinfo, 0));
                                        LLVMBuildStore(b,
                                                                   LLVMBuildLoad(b, v_transnullp, "transnull"),
-                                                                  LLVMBuildStructGEP(b, v_argnullp, 0, ""));
+                                                                  l_funcnullp(b, v_fcinfo, 0));
 
                                        /* and invoke transition function */
                                        v_retval = BuildV1Call(context, b, mod, fcinfo,
@@ -2589,12 +2525,8 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
                LLVMValueRef v_lifetime = create_LifetimeEnd(mod);
                LLVMValueRef params[2];
 
-               params[0] = l_int64_const(sizeof(fcinfo->arg));
-               params[1] = l_ptr_const(fcinfo->arg, 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()));
+               params[0] = l_int64_const(sizeof(NullableDatum) * fcinfo->nargs);
+               params[1] = l_ptr_const(fcinfo->args, l_ptr(LLVMInt8Type()));
                LLVMBuildCall(b, v_lifetime, params, lengthof(params), "");
 
                params[0] = l_int64_const(sizeof(fcinfo->isnull));
index 7994982972180c854ddacbd9f19e3be1ca78867e..c814bc7b3ee4645ad1f968d03847e4984ee41dae 100644 (file)
@@ -49,13 +49,14 @@ PGFunction  TypePGFunction;
 size_t         TypeSizeT;
 bool           TypeStorageBool;
 
+NullableDatum StructNullableDatum;
 AggState       StructAggState;
 AggStatePerGroupData StructAggStatePerGroupData;
 AggStatePerTransData StructAggStatePerTransData;
 ExprContext StructExprContext;
 ExprEvalStep StructExprEvalStep;
 ExprState      StructExprState;
-FunctionCallInfoData StructFunctionCallInfoData;
+FunctionCallInfoBaseData StructFunctionCallInfoData;
 HeapTupleData StructHeapTupleData;
 MemoryContextData StructMemoryContextData;
 TupleTableSlot StructTupleTableSlot;
index 1d3268b4abecc79833fc33b8643b14fd90ac6328..3b9e86f7702abea41f4320ed3fa0d8fb9d39919a 100644 (file)
@@ -1581,7 +1581,7 @@ pgstat_send_inquiry(TimestampTz clock_time, TimestampTz cutoff_time, Oid databas
  * Called by the executor before invoking a function.
  */
 void
-pgstat_init_function_usage(FunctionCallInfoData *fcinfo,
+pgstat_init_function_usage(FunctionCallInfo fcinfo,
                                                   PgStat_FunctionCallUsage *fcu)
 {
        PgStat_BackendFunctionEntry *htabent;
index 4a243b0777ad212cd9b56cabdbfe60ffdeb1384b..b6d2e2ac1128d11adf11a992a3e2dfb91bb9171c 100644 (file)
@@ -258,9 +258,9 @@ fetch_fp_info(Oid func_id, struct fp_info *fip)
 void
 HandleFunctionRequest(StringInfo msgBuf)
 {
+       LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
        Oid                     fid;
        AclResult       aclresult;
-       FunctionCallInfoData fcinfo;
        int16           rformat;
        Datum           retval;
        struct fp_info my_fp;
@@ -332,12 +332,12 @@ HandleFunctionRequest(StringInfo msgBuf)
         * functions can't be called this way.  Perhaps we should pass
         * 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)
-               rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
+               rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
        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. */
        pq_getmsgend(msgBuf);
@@ -350,9 +350,9 @@ HandleFunctionRequest(StringInfo msgBuf)
        {
                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;
                                break;
@@ -363,18 +363,18 @@ HandleFunctionRequest(StringInfo msgBuf)
        if (callit)
        {
                /* Okay, do it ... */
-               retval = FunctionCallInvoke(&fcinfo);
+               retval = FunctionCallInvoke(fcinfo);
        }
        else
        {
-               fcinfo.isnull = true;
+               fcinfo->isnull = true;
                retval = (Datum) 0;
        }
 
        /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
        CHECK_FOR_INTERRUPTS();
 
-       SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
+       SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat);
 
        /* We no longer need the snapshot */
        PopActiveSnapshot();
@@ -450,11 +450,11 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
                argsize = pq_getmsgint(msgBuf, 4);
                if (argsize == -1)
                {
-                       fcinfo->argnull[i] = true;
+                       fcinfo->args[i].isnull = true;
                }
                else
                {
-                       fcinfo->argnull[i] = false;
+                       fcinfo->args[i].isnull = false;
                        if (argsize < 0)
                                ereport(ERROR,
                                                (errcode(ERRCODE_PROTOCOL_VIOLATION),
@@ -494,8 +494,8 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
                        else
                                pstring = pg_client_to_server(abuf.data, argsize);
 
-                       fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
-                                                                                                 typioparam, -1);
+                       fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring,
+                                                                                                                typioparam, -1);
                        /* Free result of encoding conversion, if any */
                        if (pstring && pstring != abuf.data)
                                pfree(pstring);
@@ -514,8 +514,8 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
                        else
                                bufptr = &abuf;
 
-                       fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
-                                                                                                       typioparam, -1);
+                       fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr,
+                                                                                                                  typioparam, -1);
 
                        /* Trouble if it didn't eat the whole buffer */
                        if (argsize != -1 && abuf.cursor != abuf.len)
@@ -579,12 +579,12 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
                argsize = pq_getmsgint(msgBuf, 4);
                if (argsize == -1)
                {
-                       fcinfo->argnull[i] = true;
-                       fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
-                                                                                                       typioparam, -1);
+                       fcinfo->args[i].isnull = true;
+                       fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL,
+                                                                                                                  typioparam, -1);
                        continue;
                }
-               fcinfo->argnull[i] = false;
+               fcinfo->args[i].isnull = false;
                if (argsize < 0)
                        ereport(ERROR,
                                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
@@ -597,8 +597,8 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
                                                           pq_getmsgbytes(msgBuf, argsize),
                                                           argsize);
 
-               fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
-                                                                                               typioparam, -1);
+               fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf,
+                                                                                                          typioparam, -1);
 
                /* Trouble if it didn't eat the whole buffer */
                if (abuf.cursor != abuf.len)
index e457d81f23c69e71bb7a9c12f42f94f109aac696..a785361fd07fa90f913b06c2f90531767d86c29e 100644 (file)
@@ -3571,6 +3571,7 @@ array_contains_nulls(ArrayType *array)
 Datum
 array_eq(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
        AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
        Oid                     collation = PG_GET_COLLATION();
@@ -3590,7 +3591,6 @@ array_eq(PG_FUNCTION_ARGS)
        array_iter      it1;
        array_iter      it2;
        int                     i;
-       FunctionCallInfoData locfcinfo;
 
        if (element_type != AARR_ELEMTYPE(array2))
                ereport(ERROR,
@@ -3630,7 +3630,7 @@ array_eq(PG_FUNCTION_ARGS)
                /*
                 * 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);
 
                /* Loop over source data */
@@ -3666,12 +3666,12 @@ array_eq(PG_FUNCTION_ARGS)
                        /*
                         * Apply the operator to the element pair
                         */
-                       locfcinfo.arg[0] = elt1;
-                       locfcinfo.arg[1] = elt2;
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.argnull[1] = false;
-                       locfcinfo.isnull = false;
-                       oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = elt1;
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->args[1].value = elt2;
+                       locfcinfo->args[1].isnull = false;
+                       locfcinfo->isnull = false;
+                       oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
                        if (!oprresult)
                        {
                                result = false;
@@ -3742,6 +3742,7 @@ btarraycmp(PG_FUNCTION_ARGS)
 static int
 array_cmp(FunctionCallInfo fcinfo)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
        AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
        Oid                     collation = PG_GET_COLLATION();
@@ -3761,7 +3762,6 @@ array_cmp(FunctionCallInfo fcinfo)
        array_iter      it1;
        array_iter      it2;
        int                     i;
-       FunctionCallInfoData locfcinfo;
 
        if (element_type != AARR_ELEMTYPE(array2))
                ereport(ERROR,
@@ -3794,7 +3794,7 @@ array_cmp(FunctionCallInfo fcinfo)
        /*
         * 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);
 
        /* Loop over source data */
@@ -3833,12 +3833,12 @@ array_cmp(FunctionCallInfo fcinfo)
                }
 
                /* Compare the pair of elements */
-               locfcinfo.arg[0] = elt1;
-               locfcinfo.arg[1] = elt2;
-               locfcinfo.argnull[0] = false;
-               locfcinfo.argnull[1] = false;
-               locfcinfo.isnull = false;
-               cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+               locfcinfo->args[0].value = elt1;
+               locfcinfo->args[0].isnull = false;
+               locfcinfo->args[1].value = elt2;
+               locfcinfo->args[1].isnull = false;
+               locfcinfo->isnull = false;
+               cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
                if (cmpresult == 0)
                        continue;                       /* equal */
@@ -3913,6 +3913,7 @@ array_cmp(FunctionCallInfo fcinfo)
 Datum
 hash_array(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(locfcinfo, 1);
        AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
        int                     ndims = AARR_NDIM(array);
        int                *dims = AARR_DIMS(array);
@@ -3925,7 +3926,6 @@ hash_array(PG_FUNCTION_ARGS)
        char            typalign;
        int                     i;
        array_iter      iter;
-       FunctionCallInfoData locfcinfo;
 
        /*
         * 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.
         */
-       InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->hash_proc_finfo, 1,
                                                         InvalidOid, NULL, NULL);
 
        /* Loop over source data */
@@ -3977,10 +3977,10 @@ hash_array(PG_FUNCTION_ARGS)
                else
                {
                        /* Apply the hash function */
-                       locfcinfo.arg[0] = elt;
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.isnull = false;
-                       elthash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = elt;
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->isnull = false;
+                       elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
                }
 
                /*
@@ -4010,6 +4010,7 @@ hash_array(PG_FUNCTION_ARGS)
 Datum
 hash_array_extended(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
        uint64          seed = PG_GETARG_INT64(1);
        int                     ndims = AARR_NDIM(array);
@@ -4023,7 +4024,6 @@ hash_array_extended(PG_FUNCTION_ARGS)
        char            typalign;
        int                     i;
        array_iter      iter;
-       FunctionCallInfoData locfcinfo;
 
        typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
        if (typentry == NULL ||
@@ -4042,7 +4042,7 @@ hash_array_extended(PG_FUNCTION_ARGS)
        typbyval = typentry->typbyval;
        typalign = typentry->typalign;
 
-       InitFunctionCallInfoData(locfcinfo, &typentry->hash_extended_proc_finfo, 2,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
                                                         InvalidOid, NULL, NULL);
 
        /* Loop over source data */
@@ -4065,12 +4065,11 @@ hash_array_extended(PG_FUNCTION_ARGS)
                else
                {
                        /* Apply the hash function */
-                       locfcinfo.arg[0] = elt;
-                       locfcinfo.arg[1] = Int64GetDatum(seed);
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.argnull[1] = false;
-                       locfcinfo.isnull = false;
-                       elthash = DatumGetUInt64(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = elt;
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->args[1].value = Int64GetDatum(seed);
+                       locfcinfo->args[1].isnull = false;
+                       elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
                }
 
                result = (result << 5) - result + elthash;
@@ -4100,6 +4099,7 @@ static bool
 array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
                                          bool matchall, void **fn_extra)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        bool            result = matchall;
        Oid                     element_type = AARR_ELEMTYPE(array1);
        TypeCacheEntry *typentry;
@@ -4113,7 +4113,6 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
        int                     i;
        int                     j;
        array_iter      it1;
-       FunctionCallInfoData locfcinfo;
 
        if (element_type != AARR_ELEMTYPE(array2))
                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.
         */
-       InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
                                                         collation, NULL, NULL);
 
        /* Loop over source data */
@@ -4206,12 +4205,12 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
                        /*
                         * Apply the operator to the element pair
                         */
-                       locfcinfo.arg[0] = elt1;
-                       locfcinfo.arg[1] = elt2;
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.argnull[1] = false;
-                       locfcinfo.isnull = false;
-                       oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = elt1;
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->args[1].value = elt2;
+                       locfcinfo->args[1].isnull = false;
+                       locfcinfo->isnull = false;
+                       oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
                        if (oprresult)
                                break;
                }
@@ -6042,6 +6041,7 @@ array_replace_internal(ArrayType *array,
                                           bool remove, Oid collation,
                                           FunctionCallInfo fcinfo)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        ArrayType  *result;
        Oid                     element_type;
        Datum      *values;
@@ -6062,7 +6062,6 @@ array_replace_internal(ArrayType *array,
        int                     bitmask;
        bool            changed = false;
        TypeCacheEntry *typentry;
-       FunctionCallInfoData locfcinfo;
 
        element_type = ARR_ELEMTYPE(array);
        ndim = ARR_NDIM(array);
@@ -6117,7 +6116,7 @@ array_replace_internal(ArrayType *array,
        }
 
        /* Prepare to apply the comparison operator */
-       InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
                                                         collation, NULL, NULL);
 
        /* Allocate temporary arrays for new values */
@@ -6175,12 +6174,12 @@ array_replace_internal(ArrayType *array,
                                /*
                                 * Apply the operator to the element pair
                                 */
-                               locfcinfo.arg[0] = elt;
-                               locfcinfo.arg[1] = search;
-                               locfcinfo.argnull[0] = false;
-                               locfcinfo.argnull[1] = false;
-                               locfcinfo.isnull = false;
-                               oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
+                               locfcinfo->args[0].value = elt;
+                               locfcinfo->args[0].isnull = false;
+                               locfcinfo->args[1].value = search;
+                               locfcinfo->args[1].isnull = false;
+                               locfcinfo->isnull = false;
+                               oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
                                if (!oprresult)
                                {
                                        /* no match, keep element */
@@ -6457,10 +6456,10 @@ width_bucket_array_fixed(Datum operand,
                                                 Oid collation,
                                                 TypeCacheEntry *typentry)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        char       *thresholds_data;
        int                     typlen = typentry->typlen;
        bool            typbyval = typentry->typbyval;
-       FunctionCallInfoData locfcinfo;
        int                     left;
        int                     right;
 
@@ -6470,7 +6469,7 @@ width_bucket_array_fixed(Datum operand,
         */
        thresholds_data = (char *) ARR_DATA_PTR(thresholds);
 
-       InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
                                                         collation, NULL, NULL);
 
        /* Find the bucket */
@@ -6484,13 +6483,13 @@ width_bucket_array_fixed(Datum operand,
 
                ptr = thresholds_data + mid * typlen;
 
-               locfcinfo.arg[0] = operand;
-               locfcinfo.arg[1] = fetch_att(ptr, typbyval, typlen);
-               locfcinfo.argnull[0] = false;
-               locfcinfo.argnull[1] = false;
-               locfcinfo.isnull = false;
+               locfcinfo->args[0].value = operand;
+               locfcinfo->args[0].isnull = false;
+               locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
+               locfcinfo->args[1].isnull = false;
+               locfcinfo->isnull = false;
 
-               cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+               cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
                if (cmpresult < 0)
                        right = mid;
@@ -6510,17 +6509,17 @@ width_bucket_array_variable(Datum operand,
                                                        Oid collation,
                                                        TypeCacheEntry *typentry)
 {
+       LOCAL_FCINFO(locfcinfo, 2);
        char       *thresholds_data;
        int                     typlen = typentry->typlen;
        bool            typbyval = typentry->typbyval;
        char            typalign = typentry->typalign;
-       FunctionCallInfoData locfcinfo;
        int                     left;
        int                     right;
 
        thresholds_data = (char *) ARR_DATA_PTR(thresholds);
 
-       InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
+       InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
                                                         collation, NULL, NULL);
 
        /* Find the bucket */
@@ -6541,13 +6540,12 @@ width_bucket_array_variable(Datum operand,
                        ptr = (char *) att_align_nominal(ptr, typalign);
                }
 
-               locfcinfo.arg[0] = operand;
-               locfcinfo.arg[1] = fetch_att(ptr, typbyval, typlen);
-               locfcinfo.argnull[0] = false;
-               locfcinfo.argnull[1] = false;
-               locfcinfo.isnull = false;
+               locfcinfo->args[0].value = operand;
+               locfcinfo->args[0].isnull = false;
+               locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
+               locfcinfo->args[1].isnull = false;
 
-               cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+               cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
                if (cmpresult < 0)
                        right = mid;
index fd82a83c47c03b6db908686d6360d7de5002f87a..ad8e6d02ee497eb84cdf759c19961b180026ea63 100644 (file)
@@ -201,8 +201,8 @@ int2vectorout(PG_FUNCTION_ARGS)
 Datum
 int2vectorrecv(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(locfcinfo, 3);
        StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
-       FunctionCallInfoData locfcinfo;
        int2vector *result;
 
        /*
@@ -211,19 +211,19 @@ int2vectorrecv(PG_FUNCTION_ARGS)
         * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
         * parameter.
         */
-       InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
+       InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
                                                         InvalidOid, NULL, NULL);
 
-       locfcinfo.arg[0] = PointerGetDatum(buf);
-       locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);
-       locfcinfo.arg[2] = Int32GetDatum(-1);
-       locfcinfo.argnull[0] = false;
-       locfcinfo.argnull[1] = false;
-       locfcinfo.argnull[2] = false;
+       locfcinfo->args[0].value = PointerGetDatum(buf);
+       locfcinfo->args[0].isnull = false;
+       locfcinfo->args[1].value = ObjectIdGetDatum(INT2OID);
+       locfcinfo->args[1].isnull = false;
+       locfcinfo->args[2].value = Int32GetDatum(-1);
+       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 */
        if (ARR_NDIM(result) != 1 ||
index eb21b078f40012208dfdf375ea47913869d8c227..bb67e0149968ed144a9c21d289decb8ce69cafde 100644 (file)
@@ -256,8 +256,8 @@ oidvectorout(PG_FUNCTION_ARGS)
 Datum
 oidvectorrecv(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(locfcinfo, 3);
        StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
-       FunctionCallInfoData locfcinfo;
        oidvector  *result;
 
        /*
@@ -266,19 +266,19 @@ oidvectorrecv(PG_FUNCTION_ARGS)
         * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
         * parameter.
         */
-       InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
+       InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
                                                         InvalidOid, NULL, NULL);
 
-       locfcinfo.arg[0] = PointerGetDatum(buf);
-       locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
-       locfcinfo.arg[2] = Int32GetDatum(-1);
-       locfcinfo.argnull[0] = false;
-       locfcinfo.argnull[1] = false;
-       locfcinfo.argnull[2] = false;
+       locfcinfo->args[0].value = PointerGetDatum(buf);
+       locfcinfo->args[0].isnull = false;
+       locfcinfo->args[1].value = ObjectIdGetDatum(OIDOID);
+       locfcinfo->args[1].isnull = false;
+       locfcinfo->args[2].value = Int32GetDatum(-1);
+       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 */
        if (ARR_NDIM(result) != 1 ||
index 0467f97dc3fa70aa93c82e78504abdaa07a4a3dc..5bbf56861031337ce75d8dde59c87683e7fcb124 100644 (file)
@@ -942,7 +942,7 @@ record_cmp(FunctionCallInfo fcinfo)
                 */
                if (!nulls1[i1] || !nulls2[i2])
                {
-                       FunctionCallInfoData locfcinfo;
+                       LOCAL_FCINFO(locfcinfo, 2);
                        int32           cmpresult;
 
                        if (nulls1[i1])
@@ -959,14 +959,14 @@ record_cmp(FunctionCallInfo fcinfo)
                        }
 
                        /* Compare the pair of elements */
-                       InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
+                       InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
                                                                         collation, NULL, NULL);
-                       locfcinfo.arg[0] = values1[i1];
-                       locfcinfo.arg[1] = values2[i2];
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.argnull[1] = false;
-                       locfcinfo.isnull = false;
-                       cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = values1[i1];
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->args[1].value = values2[i2];
+                       locfcinfo->args[1].isnull = false;
+                       locfcinfo->isnull = false;
+                       cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
                        if (cmpresult < 0)
                        {
@@ -1119,11 +1119,11 @@ record_eq(PG_FUNCTION_ARGS)
        i1 = i2 = j = 0;
        while (i1 < ncolumns1 || i2 < ncolumns2)
        {
+               LOCAL_FCINFO(locfcinfo, 2);
                Form_pg_attribute att1;
                Form_pg_attribute att2;
                TypeCacheEntry *typentry;
                Oid                     collation;
-               FunctionCallInfoData locfcinfo;
                bool            oprresult;
 
                /*
@@ -1193,14 +1193,14 @@ record_eq(PG_FUNCTION_ARGS)
                        }
 
                        /* Compare the pair of elements */
-                       InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+                       InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
                                                                         collation, NULL, NULL);
-                       locfcinfo.arg[0] = values1[i1];
-                       locfcinfo.arg[1] = values2[i2];
-                       locfcinfo.argnull[0] = false;
-                       locfcinfo.argnull[1] = false;
-                       locfcinfo.isnull = false;
-                       oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
+                       locfcinfo->args[0].value = values1[i1];
+                       locfcinfo->args[0].isnull = false;
+                       locfcinfo->args[1].value = values2[i2];
+                       locfcinfo->args[1].isnull = false;
+                       locfcinfo->isnull = false;
+                       oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
                        if (!oprresult)
                        {
                                result = false;
index 5a2331ff159844b55000ee7413efb13ec6e6f1fa..a4d6a07bddc6c77f05a4bd1a0098530b6a184f1d 100644 (file)
@@ -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
 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
-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
@@ -67,10 +67,9 @@ typedef struct
     Oid         fncollation;    /* collation for function to use */
     bool        isnull;         /* function must set true if result is NULL */
     short       nargs;          /* # arguments actually passed */
-    Datum       arg[FUNC_MAX_ARGS];  /* Arguments passed to function */
-    bool        argnull[FUNC_MAX_ARGS];  /* T if arg[i] is actually NULL */
-} FunctionCallInfoData;
-typedef FunctionCallInfoData* FunctionCallInfo;
+    NullableDatum args[];       /* Arguments passed to function */
+} FunctionCallInfoBaseData;
+typedef FunctionCallInfoBaseData* FunctionCallInfo;
 
 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
@@ -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-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
 value) will now uniformly be of type Datum.  As discussed below, callers
 and callees should apply the standard Datum-to-and-from-whatever macros
 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
 number of arguments passed matches what the callee is expecting; except
 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
 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
 function return value.  Note that simple "strict" functions can ignore
-both isnull and argnull[], since they won't even get called when there
-are any TRUE values in argnull[].
+both isnull and args[i].isnull, since they won't even get called when there
+are any TRUE values in args[].isnull.
 
 FunctionCallInfo replaces FmgrValues plus a bunch of ad-hoc parameter
 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
 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.
 
 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
 types are pass-by-value or pass-by-reference.  For example, if float8 is
 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:
        float8  arg = PG_GETARG_FLOAT8(0);
 For what are now historical reasons, the float-related typedefs and macros
index 506eeef01c305be3f5140daea05de4f717bfcee1..ead8b371a7399499aee6dfeb2357f87c6072dc2f 100644 (file)
@@ -792,18 +792,18 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
 Datum
 DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 1);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 1, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 1, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.argnull[0] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -812,20 +812,20 @@ DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
 Datum
 DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 2);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 2, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 2, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -835,22 +835,22 @@ Datum
 DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 3);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 3, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 3, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -860,24 +860,24 @@ Datum
 DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3, Datum arg4)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 4);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 4, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 4, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -887,26 +887,26 @@ Datum
 DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3, Datum arg4, Datum arg5)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 5);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 5, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 5, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -917,28 +917,28 @@ DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3, Datum arg4, Datum arg5,
                                                Datum arg6)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 6);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 6, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, NULL, 6, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -949,30 +949,30 @@ DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3, Datum arg4, Datum arg5,
                                                Datum arg6, Datum arg7)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 7);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 7, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-
-       result = (*func) (&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, NULL, 7, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -983,32 +983,32 @@ DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg3, Datum arg4, Datum arg5,
                                                Datum arg6, Datum arg7, Datum arg8)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 8);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 8, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-
-       result = (*func) (&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, NULL, 8, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+       fcinfo->args[7].value = arg8;
+       fcinfo->args[7].isnull = false;
+
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -1020,34 +1020,34 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
                                                Datum arg6, Datum arg7, Datum arg8,
                                                Datum arg9)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 9);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, NULL, 9, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.arg[8] = arg9;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-       fcinfo.argnull[8] = false;
-
-       result = (*func) (&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, NULL, 9, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+       fcinfo->args[7].value = arg8;
+       fcinfo->args[7].isnull = false;
+       fcinfo->args[8].value = arg9;
+       fcinfo->args[8].isnull = false;
+
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -1065,18 +1065,18 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 Datum
 CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 1);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 1, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 1, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.argnull[0] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -1085,20 +1085,20 @@ CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum
 Datum
 CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 2);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 2, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 2, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
 
-       result = (*func) (&fcinfo);
+       result = (*func) (fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
+       if (fcinfo->isnull)
                elog(ERROR, "function %p returned NULL", (void *) func);
 
        return result;
@@ -1109,22 +1109,39 @@ CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum
  * directly-computed parameter list.  Note that neither arguments nor result
  * are allowed to be NULL.
  */
+Datum
+FunctionCall0Coll(FmgrInfo *flinfo, Oid collation)
+{
+       LOCAL_FCINFO(fcinfo, 0);
+       Datum           result;
+
+       InitFunctionCallInfoData(*fcinfo, flinfo, 0, collation, NULL, NULL);
+
+       result = FunctionCallInvoke(fcinfo);
+
+       /* Check for null result, since caller is clearly not expecting one */
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
+
+       return result;
+}
+
 Datum
 FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 1);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 1, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 1, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.argnull[0] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1132,21 +1149,21 @@ FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
 Datum
 FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 2);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 2, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 2, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1155,23 +1172,23 @@ Datum
 FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 3);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 3, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 3, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1180,25 +1197,25 @@ Datum
 FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3, Datum arg4)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 4);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 4, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 4, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1207,27 +1224,27 @@ Datum
 FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3, Datum arg4, Datum arg5)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 5);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 5, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 5, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1237,29 +1254,29 @@ FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3, Datum arg4, Datum arg5,
                                  Datum arg6)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 6);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 6, collation, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 6, collation, NULL, NULL);
 
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1269,31 +1286,31 @@ FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3, Datum arg4, Datum arg5,
                                  Datum arg6, Datum arg7)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 7);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 7, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 7, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1303,33 +1320,33 @@ FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg3, Datum arg4, Datum arg5,
                                  Datum arg6, Datum arg7, Datum arg8)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 8);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 8, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 8, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+       fcinfo->args[7].value = arg8;
+       fcinfo->args[7].isnull = false;
+
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1340,35 +1357,35 @@ FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
                                  Datum arg6, Datum arg7, Datum arg8,
                                  Datum arg9)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 9);
        Datum           result;
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 9, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.arg[8] = arg9;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-       fcinfo.argnull[8] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 9, collation, NULL, NULL);
+
+       fcinfo->args[0].value = arg1;
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = arg2;
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = arg3;
+       fcinfo->args[2].isnull = false;
+       fcinfo->args[3].value = arg4;
+       fcinfo->args[3].isnull = false;
+       fcinfo->args[4].value = arg5;
+       fcinfo->args[4].isnull = false;
+       fcinfo->args[5].value = arg6;
+       fcinfo->args[5].isnull = false;
+       fcinfo->args[6].value = arg7;
+       fcinfo->args[6].isnull = false;
+       fcinfo->args[7].value = arg8;
+       fcinfo->args[7].isnull = false;
+       fcinfo->args[8].value = arg9;
+       fcinfo->args[8].isnull = false;
+
+       result = FunctionCallInvoke(fcinfo);
 
        /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", fcinfo.flinfo->fn_oid);
+       if (fcinfo->isnull)
+               elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
 
        return result;
 }
@@ -1385,68 +1402,30 @@ Datum
 OidFunctionCall0Coll(Oid functionId, Oid collation)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 0, collation, NULL, NULL);
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall0Coll(&flinfo, collation);
 }
 
 Datum
 OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 1, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.argnull[0] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall1Coll(&flinfo, collation, arg1);
 }
 
 Datum
 OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 2, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall2Coll(&flinfo, collation, arg1, arg2);
 }
 
 Datum
@@ -1454,27 +1433,10 @@ OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg3)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 3, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall3Coll(&flinfo, collation, arg1, arg2, arg3);
 }
 
 Datum
@@ -1482,29 +1444,10 @@ OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg3, Datum arg4)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 4, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall4Coll(&flinfo, collation, arg1, arg2, arg3, arg4);
 }
 
 Datum
@@ -1512,31 +1455,10 @@ OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg3, Datum arg4, Datum arg5)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 5, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall5Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5);
 }
 
 Datum
@@ -1545,33 +1467,11 @@ OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg6)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 6, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall6Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
+                                                        arg6);
 }
 
 Datum
@@ -1580,35 +1480,11 @@ OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg6, Datum arg7)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 7, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall7Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
+                                                        arg6, arg7);
 }
 
 Datum
@@ -1617,37 +1493,11 @@ OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg6, Datum arg7, Datum arg8)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 8, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall8Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
+                                                        arg6, arg7, arg8);
 }
 
 Datum
@@ -1657,39 +1507,11 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
                                         Datum arg9)
 {
        FmgrInfo        flinfo;
-       FunctionCallInfoData fcinfo;
-       Datum           result;
 
        fmgr_info(functionId, &flinfo);
 
-       InitFunctionCallInfoData(fcinfo, &flinfo, 9, collation, NULL, NULL);
-
-       fcinfo.arg[0] = arg1;
-       fcinfo.arg[1] = arg2;
-       fcinfo.arg[2] = arg3;
-       fcinfo.arg[3] = arg4;
-       fcinfo.arg[4] = arg5;
-       fcinfo.arg[5] = arg6;
-       fcinfo.arg[6] = arg7;
-       fcinfo.arg[7] = arg8;
-       fcinfo.arg[8] = arg9;
-       fcinfo.argnull[0] = false;
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
-       fcinfo.argnull[3] = false;
-       fcinfo.argnull[4] = false;
-       fcinfo.argnull[5] = false;
-       fcinfo.argnull[6] = false;
-       fcinfo.argnull[7] = false;
-       fcinfo.argnull[8] = false;
-
-       result = FunctionCallInvoke(&fcinfo);
-
-       /* Check for null result, since caller is clearly not expecting one */
-       if (fcinfo.isnull)
-               elog(ERROR, "function %u returned NULL", flinfo.fn_oid);
-
-       return result;
+       return FunctionCall9Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
+                                                        arg6, arg7, arg8, arg9);
 }
 
 
@@ -1708,35 +1530,35 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
 Datum
 InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 3);
        Datum           result;
 
        if (str == NULL && flinfo->fn_strict)
                return (Datum) 0;               /* just return null result */
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
 
-       fcinfo.arg[0] = CStringGetDatum(str);
-       fcinfo.arg[1] = ObjectIdGetDatum(typioparam);
-       fcinfo.arg[2] = Int32GetDatum(typmod);
-       fcinfo.argnull[0] = (str == NULL);
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
+       fcinfo->args[0].value = CStringGetDatum(str);
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = Int32GetDatum(typmod);
+       fcinfo->args[2].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Should get null result if and only if str is NULL */
        if (str == NULL)
        {
-               if (!fcinfo.isnull)
+               if (!fcinfo->isnull)
                        elog(ERROR, "input function %u returned non-NULL",
-                                fcinfo.flinfo->fn_oid);
+                                flinfo->fn_oid);
        }
        else
        {
-               if (fcinfo.isnull)
+               if (fcinfo->isnull)
                        elog(ERROR, "input function %u returned NULL",
-                                fcinfo.flinfo->fn_oid);
+                                flinfo->fn_oid);
        }
 
        return result;
@@ -1767,35 +1589,35 @@ Datum
 ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
                                        Oid typioparam, int32 typmod)
 {
-       FunctionCallInfoData fcinfo;
+       LOCAL_FCINFO(fcinfo, 3);
        Datum           result;
 
        if (buf == NULL && flinfo->fn_strict)
                return (Datum) 0;               /* just return null result */
 
-       InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
+       InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
 
-       fcinfo.arg[0] = PointerGetDatum(buf);
-       fcinfo.arg[1] = ObjectIdGetDatum(typioparam);
-       fcinfo.arg[2] = Int32GetDatum(typmod);
-       fcinfo.argnull[0] = (buf == NULL);
-       fcinfo.argnull[1] = false;
-       fcinfo.argnull[2] = false;
+       fcinfo->args[0].value = PointerGetDatum(buf);
+       fcinfo->args[0].isnull = false;
+       fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
+       fcinfo->args[1].isnull = false;
+       fcinfo->args[2].value = Int32GetDatum(typmod);
+       fcinfo->args[2].isnull = false;
 
-       result = FunctionCallInvoke(&fcinfo);
+       result = FunctionCallInvoke(fcinfo);
 
        /* Should get null result if and only if buf is NULL */
        if (buf == NULL)
        {
-               if (!fcinfo.isnull)
+               if (!fcinfo->isnull)
                        elog(ERROR, "receive function %u returned non-NULL",
-                                fcinfo.flinfo->fn_oid);
+                                flinfo->fn_oid);
        }
        else
        {
-               if (fcinfo.isnull)
+               if (fcinfo->isnull)
                        elog(ERROR, "receive function %u returned NULL",
-                                fcinfo.flinfo->fn_oid);
+                                flinfo->fn_oid);
        }
 
        return result;
index e2100da266aa2d63e1652814c9b263efc65160a5..9a771214dc2a603476aeb9047b620870a9e3676e 100644 (file)
 /* Info needed to use an old-style comparison function as a sort comparator */
 typedef struct
 {
-       FunctionCallInfoData fcinfo;    /* reusable callinfo structure */
        FmgrInfo        flinfo;                 /* lookup data for comparison function */
+       FunctionCallInfoBaseData fcinfo;        /* reusable callinfo structure */
 } SortShimExtra;
 
+#define SizeForSortShimExtra(nargs) (offsetof(SortShimExtra, fcinfo) + SizeForFunctionCallInfo(nargs))
 
 /*
  * Shim function for calling an old-style comparator
  *
  * 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.
  */
 static int
@@ -44,8 +45,8 @@ comparison_shim(Datum x, Datum y, SortSupport ssup)
        SortShimExtra *extra = (SortShimExtra *) ssup->ssup_extra;
        Datum           result;
 
-       extra->fcinfo.arg[0] = x;
-       extra->fcinfo.arg[1] = y;
+       extra->fcinfo.args[0].value = x;
+       extra->fcinfo.args[1].value = y;
 
        /* just for paranoia's sake, we reset isnull each time */
        extra->fcinfo.isnull = false;
@@ -69,7 +70,7 @@ PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup)
        SortShimExtra *extra;
 
        extra = (SortShimExtra *) MemoryContextAlloc(ssup->ssup_cxt,
-                                                                                                sizeof(SortShimExtra));
+                                                                                                SizeForSortShimExtra(2));
 
        /* Lookup the comparison function */
        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 */
        InitFunctionCallInfoData(extra->fcinfo, &extra->flinfo, 2,
                                                         ssup->ssup_collation, NULL, NULL);
-       extra->fcinfo.argnull[0] = false;
-       extra->fcinfo.argnull[1] = false;
+       extra->fcinfo.args[0].isnull = false;
+       extra->fcinfo.args[1].isnull = false;
 
        ssup->ssup_extra = extra;
        ssup->comparator = comparison_shim;
index b875bbad4fb0858d481990b307cdfb1cfa66beed..2c1697dd7663dbe8268552dddc2398be3c654000 100644 (file)
@@ -223,7 +223,8 @@ typedef enum ExprEvalOp
        /* aggregation related nodes */
        EEOP_AGG_STRICT_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_STRICT_TRANS_CHECK,
        EEOP_AGG_PLAIN_TRANS_BYVAL,
@@ -601,9 +602,21 @@ typedef struct ExprEvalStep
                        int                     jumpnull;
                }                       agg_deserialize;
 
-               /* for EEOP_AGG_STRICT_INPUT_CHECK */
-               struct
-               {
+               /* for EEOP_AGG_STRICT_INPUT_CHECK_NULLS / STRICT_INPUT_CHECK_ARGS */
+               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;
                        int                     nargs;
                        int                     jumpnull;
index 3d93439e5fc87e4cbdac6367a19474a72f2bab6a..30541361301efb8350bb194cfc0ae08509400767 100644 (file)
@@ -158,12 +158,12 @@ typedef struct AggStatePerTransData
         * re-initializing the unchanging fields; which isn't much, but it seems
         * worth the extra space consumption.
         */
-       FunctionCallInfoData transfn_fcinfo;
+       FunctionCallInfo transfn_fcinfo;
 
        /* Likewise for serialization and deserialization functions */
-       FunctionCallInfoData serialfn_fcinfo;
+       FunctionCallInfo serialfn_fcinfo;
 
-       FunctionCallInfoData deserialfn_fcinfo;
+       FunctionCallInfo deserialfn_fcinfo;
 }                      AggStatePerTransData;
 
 /*
index ead17f0e442b8794505cf9ca53421339af73c8aa..ce65284525332cad5f7517c946ba7ea1690841df 100644 (file)
@@ -35,7 +35,7 @@ typedef struct StringInfoData *fmStringInfo;
  * signature.)
  */
 
-typedef struct FunctionCallInfoData *FunctionCallInfo;
+typedef struct FunctionCallInfoBaseData *FunctionCallInfo;
 
 typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
 
@@ -46,8 +46,8 @@ typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
  * info struct saved for re-use.
  *
  * Note that fn_expr really is parse-time-determined information about the
- * arguments, rather than about the function itself.  But it's convenient
- * to store it here rather than in FunctionCallInfoData, where it might more
+ * arguments, rather than about the function itself.  But it's convenient to
+ * store it here rather than in FunctionCallInfoBaseData, where it might more
  * logically belong.
  *
  * 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 particular, scribbling on the argument arrays is a bad idea,
  * 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 */
        fmNodePtr       context;                /* pass info about context of call */
@@ -83,11 +91,31 @@ typedef struct FunctionCallInfoData
 #define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
        bool            isnull;                 /* function must set true if result is NULL */
        short           nargs;                  /* # arguments actually passed */
-#define FIELDNO_FUNCTIONCALLINFODATA_ARG 6
-       Datum           arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
-#define FIELDNO_FUNCTIONCALLINFODATA_ARGNULL 7
-       bool            argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */
-} FunctionCallInfoData;
+#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6
+       NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
+} FunctionCallInfoBaseData;
+
+/*
+ * 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
@@ -116,11 +144,8 @@ extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
 extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
 
 /*
- * This macro initializes all the fields of a FunctionCallInfoData except
- * for the arg[] and argnull[] arrays.  Performance testing has shown that
- * 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.
+ * This macro initializes all the fields of a FunctionCallInfoBaseData except
+ * for the args[] array.
  */
 #define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
        do { \
@@ -133,7 +158,7 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
        } 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
  * caller must still check fcinfo->isnull!     Also, if function is strict,
  * 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
  * 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
@@ -235,7 +260,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 
 /* 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_UINT32(n)  DatumGetUInt32(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
  * are allowed to be NULL.
  */
+extern Datum FunctionCall0Coll(FmgrInfo *flinfo, Oid collation);
 extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation,
                                  Datum arg1);
 extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation,
index 2545abeddd18176f99d0fc2e20da2d542b5054a9..6af5fe74388343613c94e3a9dc5a42dbe064e1c0 100644 (file)
@@ -62,6 +62,7 @@ extern LLVMTypeRef TypePGFunction;
 extern LLVMTypeRef TypeSizeT;
 extern LLVMTypeRef TypeStorageBool;
 
+extern LLVMTypeRef StructNullableDatum;
 extern LLVMTypeRef StructTupleDescData;
 extern LLVMTypeRef StructHeapTupleData;
 extern LLVMTypeRef StructTupleTableSlot;
index 48a5c0f86cd46213d1bd406e90438f960d49e935..41145fc517a0a88d0eb8e6b8a51b1e2d8e9fce29 100644 (file)
@@ -208,4 +208,59 @@ l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
 
        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
index 64e8ef37407f24aab2dc39a178711d54c4024bff..3b789ee7cf329a6e3dc06ee6c948d174ded66751 100644 (file)
@@ -826,7 +826,7 @@ typedef struct SetExprState
         * (by InitFunctionCallInfoData) if func.fn_oid is valid.  It also saves
         * argument values between calls, when setArgsValid is true.
         */
-       FunctionCallInfoData fcinfo_data;
+       FunctionCallInfo fcinfo;
 } SetExprState;
 
 /* ----------------
index 313ca5f3c34ff746a3fe5ce0266b9ac89d95469f..0ce79489dad3ae54e0139b4163af892a2aeda71b 100644 (file)
@@ -1321,7 +1321,7 @@ extern void pgstat_count_heap_delete(Relation rel);
 extern void pgstat_count_truncate(Relation rel);
 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);
 extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu,
                                                  bool finalize);
index 446bb44b71116d373ccbd52cff7219290026cd47..057a3413acd8a8ce44d75fbf0bf62cfeb9824bae 100644 (file)
@@ -366,6 +366,21 @@ typedef struct
 
 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
 
 /*
index fe54b20903574f111de27d1c7a9ff837fe6883f6..35d5d121a08423de59b4e8cb0c2ff86737ebac88 100644 (file)
@@ -1876,8 +1876,8 @@ PG_FUNCTION_INFO_V1(plperl_inline_handler);
 Datum
 plperl_inline_handler(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(fake_fcinfo, 0);
        InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
-       FunctionCallInfoData fake_fcinfo;
        FmgrInfo        flinfo;
        plperl_proc_desc desc;
        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
         * 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(&desc, 0, sizeof(desc));
-       fake_fcinfo.flinfo = &flinfo;
+       fake_fcinfo->flinfo = &flinfo;
        flinfo.fn_oid = InvalidOid;
        flinfo.fn_mcxt = CurrentMemoryContext;
 
@@ -1920,7 +1920,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
        desc.nargs = 0;
        desc.reference = NULL;
 
-       this_call_data.fcinfo = &fake_fcinfo;
+       this_call_data.fcinfo = fake_fcinfo;
        this_call_data.prodesc = &desc;
        /* 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? */
                        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);
 
@@ -2194,11 +2194,11 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
 
        for (i = 0; i < desc->nargs; i++)
        {
-               if (fcinfo->argnull[i])
+               if (fcinfo->args[i].isnull)
                        PUSHs(&PL_sv_undef);
                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));
                }
@@ -2208,15 +2208,15 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
                        Oid                     funcid;
 
                        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)))
-                               sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, fcinfo->arg[i]));
+                               sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, fcinfo->args[i].value));
                        else
                        {
                                char       *tmp;
 
                                tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
-                                                                                fcinfo->arg[i]);
+                                                                                fcinfo->args[i].value);
                                sv = cstr2sv(tmp);
                                pfree(tmp);
                        }
index 5c6dbe4c5faf0676567ff82f5dce46ff0f08e1ad..45f10f901b729c828ce90bb7b1a3869dc6324e35 100644 (file)
@@ -491,8 +491,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
                                        PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
 
                                        assign_simple_var(&estate, var,
-                                                                         fcinfo->arg[i],
-                                                                         fcinfo->argnull[i],
+                                                                         fcinfo->args[i].value,
+                                                                         fcinfo->args[i].isnull,
                                                                          false);
 
                                        /*
@@ -543,12 +543,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
                                {
                                        PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
 
-                                       if (!fcinfo->argnull[i])
+                                       if (!fcinfo->args[i].isnull)
                                        {
                                                /* Assign row value from composite datum */
                                                exec_move_row_from_datum(&estate,
                                                                                                 (PLpgSQL_variable *) rec,
-                                                                                                fcinfo->arg[i]);
+                                                                                                fcinfo->args[i].value);
                                        }
                                        else
                                        {
index 2a9af06ccccb5cfe34491fea6a1693c7805a8f75..ce03f1ef840d4814b1b72d1d70160c936fbc1eb2 100644 (file)
@@ -299,9 +299,9 @@ PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
 Datum
 plpgsql_inline_handler(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(fake_fcinfo, 0);
        InlineCodeBlock *codeblock = castNode(InlineCodeBlock, DatumGetPointer(PG_GETARG_DATUM(0)));
        PLpgSQL_function *func;
-       FunctionCallInfoData fake_fcinfo;
        FmgrInfo        flinfo;
        EState     *simple_eval_estate;
        Datum           retval;
@@ -324,9 +324,9 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
         * plpgsql_exec_function().  In particular note that this sets things up
         * with no arguments passed.
         */
-       MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
+       MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
        MemSet(&flinfo, 0, sizeof(flinfo));
-       fake_fcinfo.flinfo = &flinfo;
+       fake_fcinfo->flinfo = &flinfo;
        flinfo.fn_oid = InvalidOid;
        flinfo.fn_mcxt = CurrentMemoryContext;
 
@@ -336,7 +336,7 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
        /* And run the function */
        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();
        {
@@ -466,7 +466,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
        /* Postpone body checks if !check_function_bodies */
        if (check_function_bodies)
        {
-               FunctionCallInfoData fake_fcinfo;
+               LOCAL_FCINFO(fake_fcinfo, 0);
                FmgrInfo        flinfo;
                int                     rc;
                TriggerData trigdata;
@@ -482,26 +482,26 @@ plpgsql_validator(PG_FUNCTION_ARGS)
                 * Set up a fake fcinfo with just enough info to satisfy
                 * plpgsql_compile().
                 */
-               MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
+               MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
                MemSet(&flinfo, 0, sizeof(flinfo));
-               fake_fcinfo.flinfo = &flinfo;
+               fake_fcinfo->flinfo = &flinfo;
                flinfo.fn_oid = funcoid;
                flinfo.fn_mcxt = CurrentMemoryContext;
                if (is_dml_trigger)
                {
                        MemSet(&trigdata, 0, sizeof(trigdata));
                        trigdata.type = T_TriggerData;
-                       fake_fcinfo.context = (Node *) &trigdata;
+                       fake_fcinfo->context = (Node *) &trigdata;
                }
                else if (is_event_trigger)
                {
                        MemSet(&etrigdata, 0, sizeof(etrigdata));
                        etrigdata.type = T_EventTriggerData;
-                       fake_fcinfo.context = (Node *) &etrigdata;
+                       fake_fcinfo->context = (Node *) &etrigdata;
                }
 
                /* Test-compile the function */
-               plpgsql_compile(&fake_fcinfo, true);
+               plpgsql_compile(fake_fcinfo, true);
 
                /*
                 * Disconnect from SPI manager
index 47ed95dcc601b101f52f8683be9ed9a3266b2c03..213718624183ee42360c7c940b2184c7e57392be 100644 (file)
@@ -436,10 +436,10 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
                {
                        PLyDatumToOb *arginfo = &proc->args[i];
 
-                       if (fcinfo->argnull[i])
+                       if (fcinfo->args[i].isnull)
                                arg = NULL;
                        else
-                               arg = PLy_input_convert(arginfo, fcinfo->arg[i]);
+                               arg = PLy_input_convert(arginfo, fcinfo->args[i].value);
 
                        if (arg == NULL)
                        {
index 6a66eba1762b9db79dfce4eb387be40ed5bf0786..6edfcf207e547626e178a5ea5ec0f27c2abf6edc 100644 (file)
@@ -299,8 +299,8 @@ plpython2_call_handler(PG_FUNCTION_ARGS)
 Datum
 plpython_inline_handler(PG_FUNCTION_ARGS)
 {
+       LOCAL_FCINFO(fake_fcinfo, 0);
        InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
-       FunctionCallInfoData fake_fcinfo;
        FmgrInfo        flinfo;
        PLyProcedure proc;
        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)
                elog(ERROR, "SPI_connect failed");
 
-       MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
+       MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
        MemSet(&flinfo, 0, sizeof(flinfo));
-       fake_fcinfo.flinfo = &flinfo;
+       fake_fcinfo->flinfo = &flinfo;
        flinfo.fn_oid = InvalidOid;
        flinfo.fn_mcxt = CurrentMemoryContext;
 
@@ -352,7 +352,7 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
 
                PLy_procedure_compile(&proc, codeblock->source_text);
                exec_ctx->curr_proc = &proc;
-               PLy_exec_function(&fake_fcinfo, &proc);
+               PLy_exec_function(fake_fcinfo, &proc);
        }
        PG_CATCH();
        {
index 3b1454f83352b07ea3d72e8f99263bca0c789c4d..bfbf62305c30c55d48a172416204e90d237f0096 100644 (file)
@@ -587,6 +587,7 @@ pltcl_fetch_interp(Oid prolang, bool pltrusted)
 static void
 call_pltcl_start_proc(Oid prolang, bool pltrusted)
 {
+       LOCAL_FCINFO(fcinfo, 0);
        char       *start_proc;
        const char *gucname;
        ErrorContextCallback errcallback;
@@ -597,7 +598,6 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
        Form_pg_proc procStruct;
        AclResult       aclresult;
        FmgrInfo        finfo;
-       FunctionCallInfoData fcinfo;
        PgStat_FunctionCallUsage fcusage;
 
        /* select appropriate GUC */
@@ -658,11 +658,11 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
         */
        InvokeFunctionExecuteHook(procOid);
        fmgr_info(procOid, &finfo);
-       InitFunctionCallInfoData(fcinfo, &finfo,
+       InitFunctionCallInfoData(*fcinfo, &finfo,
                                                         0,
                                                         InvalidOid, NULL, NULL);
-       pgstat_init_function_usage(&fcinfo, &fcusage);
-       (void) FunctionCallInvoke(&fcinfo);
+       pgstat_init_function_usage(fcinfo, &fcusage);
+       (void) FunctionCallInvoke(fcinfo);
        pgstat_end_function_usage(&fcusage, true);
 
        /* 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 ...'
                                 **************************************************/
-                               if (fcinfo->argnull[i])
+                               if (fcinfo->args[i].isnull)
                                        Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
                                else
                                {
@@ -880,7 +880,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
                                        HeapTupleData tmptup;
                                        Tcl_Obj    *list_tmp;
 
-                                       td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
+                                       td = DatumGetHeapTupleHeader(fcinfo->args[i].value);
                                        /* Extract rowtype info and find a tupdesc */
                                        tupType = HeapTupleHeaderGetTypeId(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
                                 * of their external representation
                                 **************************************************/
-                               if (fcinfo->argnull[i])
+                               if (fcinfo->args[i].isnull)
                                        Tcl_ListObjAppendElement(NULL, tcl_cmd, Tcl_NewObj());
                                else
                                {
                                        char       *tmp;
 
                                        tmp = OutputFunctionCall(&prodesc->arg_out_func[i],
-                                                                                        fcinfo->arg[i]);
+                                                                                        fcinfo->args[i].value);
                                        UTF_BEGIN;
                                        Tcl_ListObjAppendElement(NULL, tcl_cmd,
                                                                                         Tcl_NewStringObj(UTF_E2U(tmp), -1));
index 84640c47a7da004bdffdea10f71dfbd64d4248f7..3d3c76d2518677d6a308e07e90a3d3c906887e92 100644 (file)
@@ -804,7 +804,7 @@ FuncExpr
 FuncInfo
 Function
 FunctionCallInfo
-FunctionCallInfoData
+FunctionCallInfoBaseData
 FunctionParameter
 FunctionParameterMode
 FunctionScan
@@ -1328,6 +1328,7 @@ NonEmptyRange
 Notification
 NotifyStmt
 Nsrt
+NullableDatum
 NullIfExpr
 NullTest
 NullTestType