From 2e0cd41ac8f2daa9f818fa60fe1b2d136c1d9359 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 5 Jun 2018 10:24:31 -0700
Subject: [PATCH v2 1/2] Variable length FunctionCallInfoData.

Author: Andres Freund
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/commands/event_trigger.c  |   8 +-
 src/backend/commands/functioncmds.c   |  14 +-
 src/backend/commands/tablecmds.c      |   8 +-
 src/backend/commands/trigger.c        |  12 +-
 src/backend/executor/execExpr.c       |  81 +--
 src/backend/executor/execExprInterp.c | 127 ++--
 src/backend/executor/execSRF.c        |  39 +-
 src/backend/executor/functions.c      |   4 +-
 src/backend/executor/nodeAgg.c        |  74 +--
 src/backend/executor/nodeWindowAgg.c  |  65 +-
 src/backend/jit/llvm/llvmjit_expr.c   |  20 +-
 src/backend/tcop/fastpath.c           |  43 +-
 src/backend/utils/adt/arrayfuncs.c    | 123 ++--
 src/backend/utils/adt/int.c           |  20 +-
 src/backend/utils/adt/oid.c           |  20 +-
 src/backend/utils/adt/rowtypes.c      |  32 +-
 src/backend/utils/fmgr/fmgr.c         | 848 ++++++++++----------------
 src/backend/utils/sort/sortsupport.c  |  13 +-
 src/include/executor/execExpr.h       |   6 +-
 src/include/executor/nodeAgg.h        |   6 +-
 src/include/fmgr.h                    |  30 +-
 src/include/nodes/execnodes.h         |   2 +-
 src/include/postgres.h                |   7 +
 src/pl/plperl/plperl.c                |  20 +-
 src/pl/plpgsql/src/pl_exec.c          |   8 +-
 src/pl/plpython/plpy_exec.c           |   4 +-
 src/pl/tcl/pltcl.c                    |  17 +-
 27 files changed, 764 insertions(+), 887 deletions(-)

diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 9a702e4097e..6564cd7fe11 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1050,7 +1050,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
 	{
 		Oid			fnoid = lfirst_oid(lc);
 		FmgrInfo	flinfo;
-		FunctionCallInfoData fcinfo;
+		STACK_FCINFO_FOR_ARGS(fcinfo, 0);
 		PgStat_FunctionCallUsage fcusage;
 
 		elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
@@ -1070,10 +1070,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. */
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 3fd73a69f04..1eaf8011a96 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -2215,7 +2215,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
 	int			i;
 	AclResult	aclresult;
 	FmgrInfo	flinfo;
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	CallContext *callcontext;
 	EState	   *estate;
 	ExprContext *econtext;
@@ -2277,7 +2277,7 @@ 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
@@ -2298,14 +2298,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].datum = 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)
@@ -2326,7 +2326,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);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e10d3dbf3dd..9a1a3895522 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8600,7 +8600,7 @@ validateForeignKeyConstraint(char *conname,
 
 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
-		FunctionCallInfoData fcinfo;
+		STACK_FCINFO_FOR_ARGS(fcinfo, 0);
 		TriggerData trigdata;
 
 		/*
@@ -8608,7 +8608,7 @@ validateForeignKeyConstraint(char *conname,
 		 *
 		 * No parameters are passed, but we do set a context
 		 */
-		MemSet(&fcinfo, 0, sizeof(fcinfo));
+		MemSet(&fcinfodata, 0, sizeof(fcinfodata));
 
 		/*
 		 * We assume RI_FKey_check_ins won't look at flinfo...
@@ -8622,9 +8622,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);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 240e85e3910..19fcd543caf 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2358,7 +2358,7 @@ ExecCallTriggerFunc(TriggerData *trigdata,
 					Instrumentation *instr,
 					MemoryContext per_tuple_context)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 0);
 	PgStat_FunctionCallUsage fcusage;
 	Datum		result;
 	MemoryContext oldContext;
@@ -2403,15 +2403,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();
 	{
@@ -2429,11 +2429,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
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index e284fd71d75..a39c3eabf35 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -965,7 +965,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
 				/* Set up the primary fmgr lookup information */
 				finfo = palloc0(sizeof(FmgrInfo));
-				fcinfo = palloc0(sizeof(FunctionCallInfoData));
+				fcinfo = palloc0(SizeForFunctionCallInfoData(2));
 				fmgr_info(opexpr->opfuncid, finfo);
 				fmgr_info_set_expr((Node *) node, finfo);
 				InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -973,7 +973,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].datum, &fcinfo->args[0].isnull);
 
 				/*
 				 * Evaluate array argument into our return value.  There's no
@@ -1262,7 +1262,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(SizeForFunctionCallInfoData(1));
 
 				getTypeOutputInfo(exprType((Node *) iocoerce->arg),
 								  &iofunc, &typisvarlena);
@@ -1274,7 +1274,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(SizeForFunctionCallInfoData(3));
 
 				getTypeInputInfo(iocoerce->resulttype,
 								 &iofunc, &typioparam);
@@ -1289,10 +1289,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].datum = ObjectIdGetDatum(typioparam);
+				fcinfo_in->args[1].isnull = false;
+				fcinfo_in->args[2].datum = Int32GetDatum(-1);
+				fcinfo_in->args[2].isnull = false;
 
 				ExprEvalPushStep(state, &scratch);
 				break;
@@ -1733,7 +1733,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
 					/* Set up the primary fmgr lookup information */
 					finfo = palloc0(sizeof(FmgrInfo));
-					fcinfo = palloc0(sizeof(FunctionCallInfoData));
+					fcinfo = palloc0(SizeForFunctionCallInfoData(2));
 					fmgr_info(proc, finfo);
 					fmgr_info_set_expr((Node *) node, finfo);
 					InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -1748,9 +1748,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].datum, &fcinfo->args[0].isnull);
 					ExecInitExprRec(right_expr, state,
-									&fcinfo->arg[1], &fcinfo->argnull[1]);
+									&fcinfo->args[1].datum, &fcinfo->args[1].isnull);
 
 					scratch.opcode = EEOP_ROWCOMPARE_STEP;
 					scratch.d.rowcompare_step.finfo = finfo;
@@ -1876,7 +1876,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 
 				/* Perform function lookup */
 				finfo = palloc0(sizeof(FmgrInfo));
-				fcinfo = palloc0(sizeof(FunctionCallInfoData));
+				fcinfo = palloc0(SizeForFunctionCallInfoData(2));
 				fmgr_info(typentry->cmp_proc, finfo);
 				fmgr_info_set_expr((Node *) node, finfo);
 				InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -2185,7 +2185,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(SizeForFunctionCallInfoData(nargs));
 	flinfo = scratch->d.func.finfo;
 	fcinfo = scratch->d.func.fcinfo_data;
 
@@ -2224,13 +2224,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].datum = con->constvalue;
+			fcinfo->args[argno].isnull = con->constisnull;
 		}
 		else
 		{
 			ExecInitExprRec(arg, state,
-							&fcinfo->arg[argno], &fcinfo->argnull[argno]);
+							&fcinfo->args[argno].datum,
+							&fcinfo->args[argno].isnull);
 		}
 		argno++;
 	}
@@ -2863,10 +2864,11 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
 		int			numInputs = pertrans->numInputs;
 		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;
 
 		/*
@@ -2904,7 +2906,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);
 
 			/*
@@ -2918,21 +2920,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].datum,
+								&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].datum,
+								&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].datum = PointerGetDatum(NULL);
+				ds_fcinfo->args[1].isnull = false;
 
 				/*
 				 * Don't call a strict deserialization function with NULL
@@ -2946,8 +2948,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].datum;
+				scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
 
 				ExprEvalPushStep(state, &scratch);
 				adjust_bailout = lappend_int(adjust_bailout,
@@ -2964,7 +2966,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)
 			{
@@ -2975,8 +2977,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].datum,
+								&trans_fcinfo->args[argno + 1].isnull);
 				argno++;
 			}
 		}
@@ -3024,8 +3026,12 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
 		 */
 		if (trans_fcinfo->flinfo->fn_strict && numInputs > 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 = numInputs;
 			ExprEvalPushStep(state, &scratch);
@@ -3079,7 +3085,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;
@@ -3284,7 +3291,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
 
 		/* Set up the primary fmgr lookup information */
 		finfo = palloc0(sizeof(FmgrInfo));
-		fcinfo = palloc0(sizeof(FunctionCallInfoData));
+		fcinfo = palloc0(SizeForFunctionCallInfoData(2));
 		fmgr_info(foid, finfo);
 		fmgr_info_set_expr(NULL, finfo);
 		InitFunctionCallInfoData(*fcinfo, finfo, 2,
@@ -3294,16 +3301,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].datum;
+		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].datum;
+		scratch.resnull = &fcinfo->args[1].isnull;
 		ExprEvalPushStep(state, &scratch);
 
 		/* evaluate distinctness */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 1b0946b02f2..3716585901e 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -386,7 +386,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,
@@ -661,14 +662,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;
@@ -1084,8 +1085,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].datum = *op->resvalue;
+				fcinfo_out->args[0].isnull = false;
 
 				fcinfo_out->isnull = false;
 				str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
@@ -1101,8 +1102,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].datum = PointerGetDatum(str);
+				fcinfo_in->args[0].isnull = *op->resnull;
 				/* second and third arguments are already set up */
 
 				fcinfo_in->isnull = false;
@@ -1139,13 +1140,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			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);
@@ -1171,12 +1172,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;
@@ -1202,7 +1203,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			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;
 
@@ -1220,8 +1221,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].datum;
+			*op->resnull = fcinfo->args[0].isnull;
 
 			EEO_NEXT();
 		}
@@ -1287,7 +1288,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);
@@ -1526,10 +1527,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 */
@@ -1559,15 +1558,29 @@ 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_ARGS)
 		{
 			int			argno;
-			bool	   *nulls = op->d.agg_strict_input_check.nulls;
+			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 (nulls[argno])
+				if (args[argno].isnull)
+					EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
+			}
+			EEO_NEXT();
+		}
+
+		EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
+		{
+			int			argno;
+			bool		*isnull = op->d.agg_strict_input_check.nulls;
+			int			nargs = op->d.agg_strict_input_check.nargs;
+
+			for (argno = 0; argno < nargs; argno++)
+			{
+				if (isnull[argno])
 					EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
 			}
 			EEO_NEXT();
@@ -1643,7 +1656,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;
@@ -1655,8 +1668,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].datum = pergroup->transValue;
+			fcinfo->args[0].isnull = pergroup->transValueIsNull;
 			fcinfo->isnull = false; /* just in case transfn doesn't set it */
 
 			newVal = FunctionCallInvoke(fcinfo);
@@ -1694,7 +1707,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;
@@ -1706,8 +1719,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].datum = pergroup->transValue;
+			fcinfo->args[0].isnull = pergroup->transValueIsNull;
 			fcinfo->isnull = false; /* just in case transfn doesn't set it */
 
 			newVal = FunctionCallInvoke(fcinfo);
@@ -2060,7 +2073,7 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
 {
 	ExprEvalStep *op = &state->steps[0];
 	FunctionCallInfo fcinfo;
-	bool	   *argnull;
+	NullableDatum *args;
 	int			argno;
 	Datum		d;
 
@@ -2074,12 +2087,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;
@@ -2205,14 +2218,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;
@@ -2303,7 +2316,7 @@ void
 ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
 {
 	SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 0);
 
 	*op->resnull = false;
 
@@ -2335,24 +2348,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;
 	}
 }
@@ -2785,8 +2798,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;
@@ -2808,8 +2821,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 			int			cmpresult;
 
 			/* apply comparison function */
-			fcinfo->arg[0] = *op->resvalue;
-			fcinfo->arg[1] = values[off];
+			fcinfo->args[0].datum = *op->resvalue;
+			fcinfo->args[1].datum = values[off];
 
 			fcinfo->isnull = false;
 			cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
@@ -3361,7 +3374,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;
@@ -3401,20 +3414,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].datum = (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].datum = 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;
@@ -4013,7 +4026,7 @@ ExecEvalWholeRowVar(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;
 
 	/*
@@ -4024,7 +4037,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].datum,
 									 pertrans->transtypeByVal,
 									 pertrans->transtypeLen);
 	pergroup->transValueIsNull = false;
diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c
index b97b8d797ec..a50670f537a 100644
--- a/src/backend/executor/execSRF.c
+++ b/src/backend/executor/execSRF.c
@@ -109,7 +109,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
 	Oid			funcrettype;
 	bool		returnsTuple;
 	bool		returnsSet = false;
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	PgStat_FunctionCallUsage fcusage;
 	ReturnSetInfo rsinfo;
 	HeapTupleData tmptup;
@@ -157,9 +157,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 +174,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
 		 */
 		MemoryContextReset(argContext);
 		oldcontext = MemoryContextSwitchTo(argContext);
-		ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext);
+		ExecEvalFuncArgs(fcinfo, setexpr->args, econtext);
 		MemoryContextSwitchTo(oldcontext);
 
 		/*
@@ -186,9 +186,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 +196,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 +224,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 +236,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
 		else
 		{
 			result =
-				ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull);
+				ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
 			rsinfo.isDone = ExprSingleResult;
 		}
 
@@ -277,7 +277,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr,
 			 */
 			if (returnsTuple)
 			{
-				if (!fcinfo.isnull)
+				if (!fcinfo->isnull)
 				{
 					HeapTupleHeader td = DatumGetHeapTupleHeader(result);
 
@@ -338,7 +338,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 +547,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 +587,7 @@ restart:
 	{
 		for (i = 0; i < fcinfo->nargs; i++)
 		{
-			if (fcinfo->argnull[i])
+			if (fcinfo->args[i].isnull)
 			{
 				callit = false;
 				break;
@@ -704,7 +704,8 @@ 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),
+	sexpr->fcinfo = (FunctionCallInfo) palloc(SizeForFunctionCallInfoData(list_length(sexpr->args)));
+	InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func),
 							 list_length(sexpr->args),
 							 input_collation, NULL, NULL);
 
@@ -820,9 +821,9 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
 	{
 		ExprState  *argstate = (ExprState *) lfirst(arg);
 
-		fcinfo->arg[i] = ExecEvalExpr(argstate,
-									  econtext,
-									  &fcinfo->argnull[i]);
+		fcinfo->args[i].datum = ExecEvalExpr(argstate,
+											 econtext,
+											 &fcinfo->args[i].isnull);
 		i++;
 	}
 
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 23545896d4d..672dcd981cd 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -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].datum;
+			prm->isnull = fcinfo->args[i].isnull;
 			prm->pflags = 0;
 			prm->ptype = fcache->pinfo->argtypes[i];
 		}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 98d8483b720..e9bea4a46a2 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -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].datum,
 												  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].datum = 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].datum;
+	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].datum = 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;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	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].datum = ExecEvalExpr(expr,
+											 aggstate->ss.ps.ps_ExprContext,
+											 &fcinfo->args[i].isnull);
+		anynull |= fcinfo->args[i].isnull;
 		i++;
 	}
 
@@ -934,27 +934,27 @@ 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].datum = 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].datum = (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 +962,8 @@ finalize_aggregate(AggState *aggstate,
 		}
 		else
 		{
-			*resultVal = FunctionCallInvoke(&fcinfo);
-			*resultIsNull = fcinfo.isnull;
+			*resultVal = FunctionCallInvoke(fcinfo);
+			*resultIsNull = fcinfo->isnull;
 		}
 		aggstate->curperagg = NULL;
 	}
@@ -1018,12 +1018,12 @@ 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].datum = MakeExpandedObjectReadOnly(pergroupstate->transValue,
+															   pergroupstate->transValueIsNull,
+															   pertrans->transtypeLen);
+			fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
 
 			*resultVal = FunctionCallInvoke(fcinfo);
 			*resultIsNull = fcinfo->isnull;
@@ -2925,7 +2925,8 @@ 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(SizeForFunctionCallInfoData(2));
+		InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
 								 &pertrans->transfn,
 								 2,
 								 pertrans->aggCollation,
@@ -2963,7 +2964,8 @@ 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(SizeForFunctionCallInfoData(pertrans->numTransInputs + 1));
+		InitFunctionCallInfoData(*pertrans->transfn_fcinfo,
 								 &pertrans->transfn,
 								 pertrans->numTransInputs + 1,
 								 pertrans->aggCollation,
@@ -3001,7 +3003,8 @@ 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(SizeForFunctionCallInfoData(1));
+		InitFunctionCallInfoData(*pertrans->serialfn_fcinfo,
 								 &pertrans->serialfn,
 								 1,
 								 InvalidOid,
@@ -3015,7 +3018,8 @@ 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(SizeForFunctionCallInfoData(2));
+		InitFunctionCallInfoData(*pertrans->deserialfn_fcinfo,
 								 &pertrans->deserialfn,
 								 2,
 								 InvalidOid,
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 729c376d86b..032598bd5bb 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -243,8 +243,7 @@ advance_windowaggregate(WindowAggState *winstate,
 {
 	WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
 	int			numArguments = perfuncstate->numArguments;
-	FunctionCallInfoData fcinfodata;
-	FunctionCallInfo fcinfo = &fcinfodata;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	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].datum = 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].datum,
 												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].datum = peraggstate->transValue;
+	fcinfo->args[0].isnull = peraggstate->transValueIsNull;
 	winstate->curaggcontext = peraggstate->aggcontext;
 	newVal = FunctionCallInvoke(fcinfo);
 	winstate->curaggcontext = NULL;
@@ -420,8 +419,7 @@ advance_windowaggregate_base(WindowAggState *winstate,
 {
 	WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
 	int			numArguments = perfuncstate->numArguments;
-	FunctionCallInfoData fcinfodata;
-	FunctionCallInfo fcinfo = &fcinfodata;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	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].datum = 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].datum = peraggstate->transValue;
+	fcinfo->args[0].isnull = peraggstate->transValueIsNull;
 	winstate->curaggcontext = peraggstate->aggcontext;
 	newVal = FunctionCallInvoke(fcinfo);
 	winstate->curaggcontext = NULL;
@@ -592,29 +590,29 @@ finalize_windowaggregate(WindowAggState *winstate,
 	if (OidIsValid(peraggstate->finalfn_oid))
 	{
 		int			numFinalArgs = peraggstate->numFinalArgs;
-		FunctionCallInfoData fcinfo;
+		STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 		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].datum = 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].datum = (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 +621,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,8 +1030,9 @@ static void
 eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
 					Datum *result, bool *isnull)
 {
-	FunctionCallInfoData fcinfo;
+	FunctionCallInfo fcinfo;
 	MemoryContext oldContext;
+	int argno;
 
 	oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
 
@@ -1043,24 +1042,26 @@ 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),
+	fcinfo = palloc(SizeForFunctionCallInfoData(perfuncstate->numArguments));
+	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 (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,
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 99e0cee157f..13aedc93016 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -2117,15 +2117,16 @@ llvm_compile_expr(ExprState *state)
 			case EEOP_AGG_STRICT_INPUT_CHECK:
 				{
 					int			nargs = op->d.agg_strict_input_check.nargs;
-					bool	   *nulls = op->d.agg_strict_input_check.nulls;
+					NullableDatum *args = op->d.agg_strict_input_check.args;
 					int			jumpnull;
 					int			argno;
 
-					LLVMValueRef v_nullp;
+					LLVMValueRef v_argp;
 					LLVMBasicBlockRef *b_checknulls;
 
 					jumpnull = op->d.agg_strict_input_check.jumpnull;
-					v_nullp = l_ptr_const(nulls, l_ptr(TypeStorageBool));
+					/* FIXME: This isn't correct, it's a NullableDatum now */
+					v_argp = l_ptr_const(args, l_ptr(TypeStorageBool));
 
 					/* create blocks for checking args */
 					b_checknulls = palloc(sizeof(LLVMBasicBlockRef *) * nargs);
@@ -2153,7 +2154,8 @@ llvm_compile_expr(ExprState *state)
 						else
 							b_argnotnull = b_checknulls[argno + 1];
 
-						v_argisnull = l_load_gep1(b, v_nullp, v_argno, "");
+						/* FIXME: This isn't correct */
+						v_argisnull = l_load_gep1(b, v_argp, v_argno, "");
 
 						LLVMBuildCondBr(b,
 										LLVMBuildICmp(b,
@@ -2352,7 +2354,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));
@@ -2622,12 +2624,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));
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index d16ba5ec927..4d2b687fb1f 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -260,7 +260,7 @@ HandleFunctionRequest(StringInfo msgBuf)
 {
 	Oid			fid;
 	AclResult	aclresult;
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
 	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].datum = 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].datum = OidReceiveFunctionCall(typreceive, bufptr,
+														   typioparam, -1);
 
 			/* Trouble if it didn't eat the whole buffer */
 			if (argsize != -1 && abuf.cursor != abuf.len)
@@ -579,12 +579,13 @@ 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);
+			/* FIXME: huh? */
+			fcinfo->args[i].isnull = true;
+			fcinfo->args[i].datum = 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 +598,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].datum = OidReceiveFunctionCall(typreceive, &abuf,
+													   typioparam, -1);
 
 		/* Trouble if it didn't eat the whole buffer */
 		if (abuf.cursor != abuf.len)
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index ce1ded888f1..577e8637768 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -3590,7 +3590,7 @@ array_eq(PG_FUNCTION_ARGS)
 	array_iter	it1;
 	array_iter	it2;
 	int			i;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 3);
 
 	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].datum = elt1;
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->args[1].datum = elt2;
+			locfcinfo->args[1].isnull = false;
+			locfcinfo->isnull = false;
+			oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
 			if (!oprresult)
 			{
 				result = false;
@@ -3761,7 +3761,7 @@ array_cmp(FunctionCallInfo fcinfo)
 	array_iter	it1;
 	array_iter	it2;
 	int			i;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
 
 	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].datum = elt1;
+		locfcinfo->args[0].isnull = false;
+		locfcinfo->args[1].datum = elt2;
+		locfcinfo->args[1].isnull = false;
+		locfcinfo->isnull = false;
+		cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
 		if (cmpresult == 0)
 			continue;			/* equal */
@@ -3925,7 +3925,7 @@ hash_array(PG_FUNCTION_ARGS)
 	char		typalign;
 	int			i;
 	array_iter	iter;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 1);
 
 	/*
 	 * 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].datum = elt;
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->isnull = false;
+			elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
 		}
 
 		/*
@@ -4023,7 +4023,7 @@ hash_array_extended(PG_FUNCTION_ARGS)
 	char		typalign;
 	int			i;
 	array_iter	iter;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
 
 	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].datum = elt;
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->args[1].datum = Int64GetDatum(seed);
+			locfcinfo->args[1].isnull = false;
+			elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
 		}
 
 		result = (result << 5) - result + elthash;
@@ -4113,7 +4112,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
 	int			i;
 	int			j;
 	array_iter	it1;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
 
 	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].datum = elt1;
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->args[1].datum = elt2;
+			locfcinfo->args[1].isnull = false;
+			locfcinfo->isnull = false;
+			oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
 			if (oprresult)
 				break;
 		}
@@ -6062,7 +6061,7 @@ array_replace_internal(ArrayType *array,
 	int			bitmask;
 	bool		changed = false;
 	TypeCacheEntry *typentry;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
 
 	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].datum = elt;
+				locfcinfo->args[0].isnull = false;
+				locfcinfo->args[1].datum = search;
+				locfcinfo->args[1].isnull = false;
+				locfcinfo->isnull = false;
+				oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
 				if (!oprresult)
 				{
 					/* no match, keep element */
@@ -6460,7 +6459,8 @@ width_bucket_array_fixed(Datum operand,
 	char	   *thresholds_data;
 	int			typlen = typentry->typlen;
 	bool		typbyval = typentry->typbyval;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
+
 	int			left;
 	int			right;
 
@@ -6470,7 +6470,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 +6484,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].datum = operand;
+		locfcinfo->args[0].isnull = false;
+		locfcinfo->args[1].datum = 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;
@@ -6514,13 +6514,13 @@ width_bucket_array_variable(Datum operand,
 	int			typlen = typentry->typlen;
 	bool		typbyval = typentry->typbyval;
 	char		typalign = typentry->typalign;
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 2);
 	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 +6541,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].datum = operand;
+		locfcinfo->args[0].isnull = false;
+		locfcinfo->args[1].datum = fetch_att(ptr, typbyval, typlen);
+		locfcinfo->args[1].isnull = false;
 
-		cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+		cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
 		if (cmpresult < 0)
 			right = mid;
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 8149dc1369b..cb92b0f98bb 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -202,7 +202,7 @@ Datum
 int2vectorrecv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 3);
 	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].datum = PointerGetDatum(buf);
+	locfcinfo->args[0].isnull = false;
+	locfcinfo->args[1].datum = ObjectIdGetDatum(INT2OID);
+	locfcinfo->args[1].isnull = false;
+	locfcinfo->args[2].datum = 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 ||
diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c
index b0670e0d9f7..cf50f843115 100644
--- a/src/backend/utils/adt/oid.c
+++ b/src/backend/utils/adt/oid.c
@@ -257,7 +257,7 @@ Datum
 oidvectorrecv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
-	FunctionCallInfoData locfcinfo;
+	STACK_FCINFO_FOR_ARGS(locfcinfo, 3);
 	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].datum = PointerGetDatum(buf);
+	locfcinfo->args[0].isnull = false;
+	locfcinfo->args[1].datum = ObjectIdGetDatum(OIDOID);
+	locfcinfo->args[1].isnull = false;
+	locfcinfo->args[2].datum = 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 ||
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 5f729342f8d..de2bd560eea 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -942,7 +942,7 @@ record_cmp(FunctionCallInfo fcinfo)
 		 */
 		if (!nulls1[i1] || !nulls2[i2])
 		{
-			FunctionCallInfoData locfcinfo;
+			STACK_FCINFO_FOR_ARGS(locfcinfo, 3);
 			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].datum = values1[i1];
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->args[1].datum = values2[i2];
+			locfcinfo->args[1].isnull = false;
+			locfcinfo->isnull = false;
+			cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
 
 			if (cmpresult < 0)
 			{
@@ -1123,7 +1123,7 @@ record_eq(PG_FUNCTION_ARGS)
 		Form_pg_attribute att2;
 		TypeCacheEntry *typentry;
 		Oid			collation;
-		FunctionCallInfoData locfcinfo;
+		STACK_FCINFO_FOR_ARGS(locfcinfo, 3);
 		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].datum = values1[i1];
+			locfcinfo->args[0].isnull = false;
+			locfcinfo->args[1].datum = values2[i2];
+			locfcinfo->args[1].isnull = false;
+			locfcinfo->isnull = false;
+			oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
 			if (!oprresult)
 			{
 				result = false;
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 6cbbd5b78b0..86d5cef8108 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -782,7 +782,6 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
  *		Support routines for callers of fmgr-compatible functions
  *-------------------------------------------------------------------------
  */
-
 /*
  * These are for invocation of a specifically named function with a
  * directly-computed parameter list.  Note that neither arguments nor result
@@ -792,18 +791,18 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
 Datum
 DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = 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 +811,20 @@ DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
 Datum
 DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = 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 +834,22 @@ Datum
 DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = 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 +859,24 @@ Datum
 DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3, Datum arg4)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = 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 +886,26 @@ Datum
 DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3, Datum arg4, Datum arg5)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = 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 +916,28 @@ DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3, Datum arg4, Datum arg5,
 						Datum arg6)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = 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 +948,30 @@ DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3, Datum arg4, Datum arg5,
 						Datum arg6, Datum arg7)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 7);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, NULL, 7, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].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;
@@ -983,32 +982,32 @@ DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg3, Datum arg4, Datum arg5,
 						Datum arg6, Datum arg7, Datum arg8)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 8);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, NULL, 8, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].isnull = false;
+	fcinfo->args[7].datum = arg8;
+	fcinfo->args[7].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;
@@ -1020,34 +1019,34 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 						Datum arg6, Datum arg7, Datum arg8,
 						Datum arg9)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 9);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, NULL, 9, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].isnull = false;
+	fcinfo->args[7].datum = arg8;
+	fcinfo->args[7].isnull = false;
+	fcinfo->args[8].datum = arg9;
+	fcinfo->args[8].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;
@@ -1065,18 +1064,18 @@ DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
 Datum
 CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = 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,25 +1084,47 @@ CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum
 Datum
 CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = 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;
 }
 
+/*
+ * These are for invocation of a previously-looked-up function with a
+ * directly-computed parameter list.  Note that neither arguments nor result
+ * are allowed to be NULL.
+ */
+Datum
+FunctionCall0Coll(FmgrInfo *flinfo, Oid collation)
+{
+	STACK_FCINFO_FOR_ARGS(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;
+}
+
 /*
  * These are for invocation of a previously-looked-up function with a
  * directly-computed parameter list.  Note that neither arguments nor result
@@ -1112,19 +1133,19 @@ CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum
 Datum
 FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = 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 +1153,21 @@ FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
 Datum
 FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = 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 +1176,23 @@ Datum
 FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = 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 +1201,25 @@ Datum
 FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3, Datum arg4)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = 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 +1228,27 @@ Datum
 FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3, Datum arg4, Datum arg5)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = 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 +1258,29 @@ FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3, Datum arg4, Datum arg5,
 				  Datum arg6)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = 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 +1290,31 @@ FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3, Datum arg4, Datum arg5,
 				  Datum arg6, Datum arg7)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 7);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, flinfo, 7, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].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;
 }
@@ -1303,33 +1324,33 @@ FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg3, Datum arg4, Datum arg5,
 				  Datum arg6, Datum arg7, Datum arg8)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 8);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, flinfo, 8, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].isnull = false;
+	fcinfo->args[7].datum = arg8;
+	fcinfo->args[7].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;
 }
@@ -1340,35 +1361,35 @@ FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
 				  Datum arg6, Datum arg7, Datum arg8,
 				  Datum arg9)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 9);
 	Datum		result;
 
-	InitFunctionCallInfoData(fcinfo, flinfo, 9, collation, NULL, NULL);
+	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;
+	fcinfo->args[0].datum = arg1;
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = arg2;
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = arg3;
+	fcinfo->args[2].isnull = false;
+	fcinfo->args[3].datum = arg4;
+	fcinfo->args[3].isnull = false;
+	fcinfo->args[4].datum = arg5;
+	fcinfo->args[4].isnull = false;
+	fcinfo->args[5].datum = arg6;
+	fcinfo->args[5].isnull = false;
+	fcinfo->args[6].datum = arg7;
+	fcinfo->args[6].isnull = false;
+	fcinfo->args[7].datum = arg8;
+	fcinfo->args[7].isnull = false;
+	fcinfo->args[8].datum = arg9;
+	fcinfo->args[8].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;
 }
@@ -1385,68 +1406,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 +1437,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 +1448,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 +1459,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 +1471,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 +1484,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 +1497,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 +1511,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 +1534,35 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
 Datum
 InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = CStringGetDatum(str);
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = ObjectIdGetDatum(typioparam);
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = 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 +1593,35 @@ Datum
 ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
 					Oid typioparam, int32 typmod)
 {
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(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].datum = PointerGetDatum(buf);
+	fcinfo->args[0].isnull = false;
+	fcinfo->args[1].datum = ObjectIdGetDatum(typioparam);
+	fcinfo->args[1].isnull = false;
+	fcinfo->args[2].datum = 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;
diff --git a/src/backend/utils/sort/sortsupport.c b/src/backend/utils/sort/sortsupport.c
index 8c09fe4a430..31aa4100d67 100644
--- a/src/backend/utils/sort/sortsupport.c
+++ b/src/backend/utils/sort/sortsupport.c
@@ -26,10 +26,11 @@
 /* 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 */
+	FunctionCallInfoData fcinfo;	/* reusable callinfo structure */
 } SortShimExtra;
 
+#define SizeForSortShimExtra(nargs) (offsetof(SortShimExtra, fcinfo) + SizeForFunctionCallInfoData(nargs))
 
 /*
  * Shim function for calling an old-style comparator
@@ -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].datum = x;
+	extra->fcinfo.args[1].datum = 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;
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 02af68f2c25..8233a465189 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -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,
@@ -599,7 +600,8 @@ typedef struct ExprEvalStep
 		/* for EEOP_AGG_STRICT_INPUT_CHECK */
 		struct
 		{
-			bool	   *nulls;
+			NullableDatum *args;
+			bool *nulls;
 			int			nargs;
 			int			jumpnull;
 		}			agg_strict_input_check;
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index 8fb8c8fe802..51aec33fd8d 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -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;
 
 /*
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 101f513ba67..ee1dbd5fcbb 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -83,12 +83,28 @@ 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 */
+#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6
+
+	NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
+
 } FunctionCallInfoData;
 
+#define SizeForFunctionCallInfoData(nargs) (offsetof(FunctionCallInfoData, args) + sizeof(NullableDatum) * (nargs))
+
+/*
+ * This macro ensures that `name` points to a stack-allocated
+ * FunctionCallInfoData struct with sufficient space for `nargs` arguments.
+ */
+#define STACK_FCINFO_FOR_ARGS(name, nargs) \
+	union \
+	{ \
+		FunctionCallInfoData fcinfo; \
+		/* ensure enough space for nargs args is available */ \
+		char *fcinfo_data[SizeForFunctionCallInfoData(nargs)]; \
+	} name##data; \
+	FunctionCallInfo name = &name##data.fcinfo
+
+
 /*
  * This routine fills a FmgrInfo struct, given the OID
  * of the function to be called.
@@ -141,7 +157,6 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn);
  */
 #define FunctionCallInvoke(fcinfo)	((* (fcinfo)->flinfo->fn_addr) (fcinfo))
 
-
 /*-------------------------------------------------------------------------
  *		Support macros to ease writing fmgr-compatible functions
  *
@@ -176,7 +191,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 +250,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].datum)
 #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 +529,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,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 834708944bf..e04573f11ae 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -828,7 +828,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;
 
 /* ----------------
diff --git a/src/include/postgres.h b/src/include/postgres.h
index b596fcb513e..b3ff25dc6e2 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -366,6 +366,13 @@ typedef struct
 
 typedef uintptr_t Datum;
 
+typedef struct NullableDatum
+{
+	Datum datum;
+	bool isnull;
+	/* FIXME: space for flags? */
+} NullableDatum;
+
 #define SIZEOF_DATUM SIZEOF_VOID_P
 
 /*
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 4cfc5062531..3d4350a16c9 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1877,7 +1877,7 @@ Datum
 plperl_inline_handler(PG_FUNCTION_ARGS)
 {
 	InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
-	FunctionCallInfoData fake_fcinfo;
+	STACK_FCINFO_FOR_ARGS(fake_fcinfo, 0);
 	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_fcinfodata, 0, sizeof(fake_fcinfodata));
 	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].datum);
 
 			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].datum, 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].datum));
 			else
 			{
 				char	   *tmp;
 
 				tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
-										 fcinfo->arg[i]);
+										 fcinfo->args[i].datum);
 				sv = cstr2sv(tmp);
 				pfree(tmp);
 			}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 45526383f25..665118cfe82 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -489,8 +489,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].datum,
+									  fcinfo->args[i].isnull,
 									  false);
 
 					/*
@@ -541,12 +541,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].datum);
 					}
 					else
 					{
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 47ed95dcc60..d1a8c395ffd 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -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].datum);
 
 			if (arg == NULL)
 			{
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e2fa43b890d..3ee2a7fd4a2 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -601,7 +601,8 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
 	Form_pg_proc procStruct;
 	AclResult	aclresult;
 	FmgrInfo	finfo;
-	FunctionCallInfoData fcinfo;
+	STACK_FCINFO_FOR_ARGS(fcinfo, 3);
+
 	PgStat_FunctionCallUsage fcusage;
 
 	/* select appropriate GUC */
@@ -662,11 +663,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 */
@@ -873,7 +874,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
 				{
@@ -884,7 +885,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].datum);
 					/* Extract rowtype info and find a tupdesc */
 					tupType = HeapTupleHeaderGetTypeId(td);
 					tupTypmod = HeapTupleHeaderGetTypMod(td);
@@ -905,14 +906,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].datum);
 					UTF_BEGIN;
 					Tcl_ListObjAppendElement(NULL, tcl_cmd,
 											 Tcl_NewStringObj(UTF_E2U(tmp), -1));
-- 
2.18.0.rc2.dirty

