diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/README | 6 | ||||
-rw-r--r-- | src/backend/executor/execExpr.c | 83 | ||||
-rw-r--r-- | src/backend/executor/execExprInterp.c | 139 | ||||
-rw-r--r-- | src/backend/executor/execSRF.c | 45 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 83 | ||||
-rw-r--r-- | src/backend/executor/nodeWindowAgg.c | 64 |
7 files changed, 230 insertions, 194 deletions
diff --git a/src/backend/executor/README b/src/backend/executor/README index ddbd62b4dba..05f197bc75b 100644 --- a/src/backend/executor/README +++ b/src/backend/executor/README @@ -124,7 +124,7 @@ For example, "a + b" (one OpExpr, with two Var expressions) would be represented as two steps to fetch the Var values, and one step for the evaluation of the function underlying the + operator. The steps for the Vars would have their resvalue/resnull pointing directly to the appropriate -arg[] and argnull[] array elements in the FunctionCallInfoData struct that +args[].value .isnull elements in the FunctionCallInfoBaseData struct that is used by the function evaluation step, thus avoiding extra work to copy the result values around. @@ -145,7 +145,7 @@ sub-expressions. Each ExecInitExprRec() call has to specify where that subexpression's results are to be stored (via the resv/resnull parameters). This allows the above scenario of evaluating a (sub-)expression directly into -fcinfo->arg/argnull, but also requires some care: target Datum/isnull +fcinfo->args[].value/isnull, but also requires some care: target Datum/isnull variables may not be shared with another ExecInitExprRec() unless the results are only needed by steps executing before further usages of those target Datum/isnull variables. Due to the non-recursiveness of the @@ -158,7 +158,7 @@ not enough space. Because of that it is *not* allowed to point directly into any of the steps during expression initialization. Therefore, the resv/resnull for a subexpression usually point to some storage that is palloc'd separately from the steps array. For instance, the -FunctionCallInfoData for a function call step is separately allocated +FunctionCallInfoBaseData for a function call step is separately allocated rather than being part of the ExprEvalStep array. The overall result of a complete expression is typically returned into the resvalue/resnull fields of the ExprState node itself. diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 4047d24b03e..2e061a5ee36 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -966,7 +966,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* Set up the primary fmgr lookup information */ finfo = palloc0(sizeof(FmgrInfo)); - fcinfo = palloc0(sizeof(FunctionCallInfoData)); + fcinfo = palloc0(SizeForFunctionCallInfo(2)); fmgr_info(opexpr->opfuncid, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, @@ -974,7 +974,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* Evaluate scalar directly into left function argument */ ExecInitExprRec(scalararg, state, - &fcinfo->arg[0], &fcinfo->argnull[0]); + &fcinfo->args[0].value, &fcinfo->args[0].isnull); /* * Evaluate array argument into our return value. There's no @@ -1263,7 +1263,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* lookup the source type's output function */ scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo)); - scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData)); + scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1)); getTypeOutputInfo(exprType((Node *) iocoerce->arg), &iofunc, &typisvarlena); @@ -1275,7 +1275,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* lookup the result type's input function */ scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo)); - scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData)); + scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3)); getTypeInputInfo(iocoerce->resulttype, &iofunc, &typioparam); @@ -1290,10 +1290,10 @@ ExecInitExprRec(Expr *node, ExprState *state, * function, since they're constants. */ fcinfo_in = scratch.d.iocoerce.fcinfo_data_in; - fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam); - fcinfo_in->argnull[1] = false; - fcinfo_in->arg[2] = Int32GetDatum(-1); - fcinfo_in->argnull[2] = false; + fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam); + fcinfo_in->args[1].isnull = false; + fcinfo_in->args[2].value = Int32GetDatum(-1); + fcinfo_in->args[2].isnull = false; ExprEvalPushStep(state, &scratch); break; @@ -1735,7 +1735,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* Set up the primary fmgr lookup information */ finfo = palloc0(sizeof(FmgrInfo)); - fcinfo = palloc0(sizeof(FunctionCallInfoData)); + fcinfo = palloc0(SizeForFunctionCallInfo(2)); fmgr_info(proc, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, @@ -1750,9 +1750,9 @@ ExecInitExprRec(Expr *node, ExprState *state, /* evaluate left and right args directly into fcinfo */ ExecInitExprRec(left_expr, state, - &fcinfo->arg[0], &fcinfo->argnull[0]); + &fcinfo->args[0].value, &fcinfo->args[0].isnull); ExecInitExprRec(right_expr, state, - &fcinfo->arg[1], &fcinfo->argnull[1]); + &fcinfo->args[1].value, &fcinfo->args[1].isnull); scratch.opcode = EEOP_ROWCOMPARE_STEP; scratch.d.rowcompare_step.finfo = finfo; @@ -1878,7 +1878,7 @@ ExecInitExprRec(Expr *node, ExprState *state, /* Perform function lookup */ finfo = palloc0(sizeof(FmgrInfo)); - fcinfo = palloc0(sizeof(FunctionCallInfoData)); + fcinfo = palloc0(SizeForFunctionCallInfo(2)); fmgr_info(typentry->cmp_proc, finfo); fmgr_info_set_expr((Node *) node, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, @@ -2187,7 +2187,7 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, /* Allocate function lookup data and parameter workspace for this call */ scratch->d.func.finfo = palloc0(sizeof(FmgrInfo)); - scratch->d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData)); + scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs)); flinfo = scratch->d.func.finfo; fcinfo = scratch->d.func.fcinfo_data; @@ -2226,13 +2226,14 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, */ Const *con = (Const *) arg; - fcinfo->arg[argno] = con->constvalue; - fcinfo->argnull[argno] = con->constisnull; + fcinfo->args[argno].value = con->constvalue; + fcinfo->args[argno].isnull = con->constisnull; } else { ExecInitExprRec(arg, state, - &fcinfo->arg[argno], &fcinfo->argnull[argno]); + &fcinfo->args[argno].value, + &fcinfo->args[argno].isnull); } argno++; } @@ -2961,10 +2962,11 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, AggStatePerTrans pertrans = &aggstate->pertrans[transno]; int argno; int setno; - FunctionCallInfo trans_fcinfo = &pertrans->transfn_fcinfo; + FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo; ListCell *arg; ListCell *bail; List *adjust_bailout = NIL; + NullableDatum *strictargs = NULL; bool *strictnulls = NULL; /* @@ -3002,7 +3004,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, Assert(pertrans->numSortCols == 0); Assert(list_length(pertrans->aggref->args) == 1); - strictnulls = trans_fcinfo->argnull + 1; + strictargs = trans_fcinfo->args + 1; source_tle = (TargetEntry *) linitial(pertrans->aggref->args); /* @@ -3016,21 +3018,21 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, * value */ ExecInitExprRec(source_tle->expr, state, - &trans_fcinfo->arg[argno + 1], - &trans_fcinfo->argnull[argno + 1]); + &trans_fcinfo->args[argno + 1].value, + &trans_fcinfo->args[argno + 1].isnull); } else { - FunctionCallInfo ds_fcinfo = &pertrans->deserialfn_fcinfo; + FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo; /* evaluate argument */ ExecInitExprRec(source_tle->expr, state, - &ds_fcinfo->arg[0], - &ds_fcinfo->argnull[0]); + &ds_fcinfo->args[0].value, + &ds_fcinfo->args[0].isnull); /* Dummy second argument for type-safety reasons */ - ds_fcinfo->arg[1] = PointerGetDatum(NULL); - ds_fcinfo->argnull[1] = false; + ds_fcinfo->args[1].value = PointerGetDatum(NULL); + ds_fcinfo->args[1].isnull = false; /* * Don't call a strict deserialization function with NULL @@ -3044,8 +3046,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, scratch.d.agg_deserialize.aggstate = aggstate; scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo; scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */ - scratch.resvalue = &trans_fcinfo->arg[argno + 1]; - scratch.resnull = &trans_fcinfo->argnull[argno + 1]; + scratch.resvalue = &trans_fcinfo->args[argno + 1].value; + scratch.resnull = &trans_fcinfo->args[argno + 1].isnull; ExprEvalPushStep(state, &scratch); adjust_bailout = lappend_int(adjust_bailout, @@ -3062,7 +3064,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, /* * Normal transition function without ORDER BY / DISTINCT. */ - strictnulls = trans_fcinfo->argnull + 1; + strictargs = trans_fcinfo->args + 1; foreach(arg, pertrans->aggref->args) { @@ -3073,8 +3075,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, * value */ ExecInitExprRec(source_tle->expr, state, - &trans_fcinfo->arg[argno + 1], - &trans_fcinfo->argnull[argno + 1]); + &trans_fcinfo->args[argno + 1].value, + &trans_fcinfo->args[argno + 1].isnull); argno++; } } @@ -3122,8 +3124,12 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, */ if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0) { - scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK; + if (strictnulls) + scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS; + else + scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS; scratch.d.agg_strict_input_check.nulls = strictnulls; + scratch.d.agg_strict_input_check.args = strictargs; scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */ scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs; ExprEvalPushStep(state, &scratch); @@ -3177,7 +3183,8 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, Assert(as->d.jump.jumpdone == -1); as->d.jump.jumpdone = state->steps_len; } - else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK) + else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS || + as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS) { Assert(as->d.agg_strict_input_check.jumpnull == -1); as->d.agg_strict_input_check.jumpnull = state->steps_len; @@ -3312,7 +3319,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate, */ ExprState * ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, - const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, + const TupleTableSlotOps * lops, const TupleTableSlotOps * rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, @@ -3389,7 +3396,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, /* Set up the primary fmgr lookup information */ finfo = palloc0(sizeof(FmgrInfo)); - fcinfo = palloc0(sizeof(FunctionCallInfoData)); + fcinfo = palloc0(SizeForFunctionCallInfo(2)); fmgr_info(foid, finfo); fmgr_info_set_expr(NULL, finfo); InitFunctionCallInfoData(*fcinfo, finfo, 2, @@ -3399,16 +3406,16 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, scratch.opcode = EEOP_INNER_VAR; scratch.d.var.attnum = attno - 1; scratch.d.var.vartype = latt->atttypid; - scratch.resvalue = &fcinfo->arg[0]; - scratch.resnull = &fcinfo->argnull[0]; + scratch.resvalue = &fcinfo->args[0].value; + scratch.resnull = &fcinfo->args[0].isnull; ExprEvalPushStep(state, &scratch); /* right arg */ scratch.opcode = EEOP_OUTER_VAR; scratch.d.var.attnum = attno - 1; scratch.d.var.vartype = ratt->atttypid; - scratch.resvalue = &fcinfo->arg[1]; - scratch.resnull = &fcinfo->argnull[1]; + scratch.resvalue = &fcinfo->args[1].value; + scratch.resnull = &fcinfo->args[1].isnull; ExprEvalPushStep(state, &scratch); /* evaluate distinctness */ diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 5a7206f5882..5c5f655645d 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -387,7 +387,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_ALTERNATIVE_SUBPLAN, &&CASE_EEOP_AGG_STRICT_DESERIALIZE, &&CASE_EEOP_AGG_DESERIALIZE, - &&CASE_EEOP_AGG_STRICT_INPUT_CHECK, + &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS, + &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS, &&CASE_EEOP_AGG_INIT_TRANS, &&CASE_EEOP_AGG_STRICT_TRANS_CHECK, &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL, @@ -631,14 +632,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_FUNCEXPR_STRICT) { FunctionCallInfo fcinfo = op->d.func.fcinfo_data; - bool *argnull = fcinfo->argnull; + NullableDatum *args = fcinfo->args; int argno; Datum d; /* strict function, so check for NULL args */ for (argno = 0; argno < op->d.func.nargs; argno++) { - if (argnull[argno]) + if (args[argno].isnull) { *op->resnull = true; goto strictfail; @@ -1054,8 +1055,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) FunctionCallInfo fcinfo_out; fcinfo_out = op->d.iocoerce.fcinfo_data_out; - fcinfo_out->arg[0] = *op->resvalue; - fcinfo_out->argnull[0] = false; + fcinfo_out->args[0].value = *op->resvalue; + fcinfo_out->args[0].isnull = false; fcinfo_out->isnull = false; str = DatumGetCString(FunctionCallInvoke(fcinfo_out)); @@ -1071,8 +1072,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) Datum d; fcinfo_in = op->d.iocoerce.fcinfo_data_in; - fcinfo_in->arg[0] = PointerGetDatum(str); - fcinfo_in->argnull[0] = *op->resnull; + fcinfo_in->args[0].value = PointerGetDatum(str); + fcinfo_in->args[0].isnull = *op->resnull; /* second and third arguments are already set up */ fcinfo_in->isnull = false; @@ -1099,23 +1100,23 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) { /* * IS DISTINCT FROM must evaluate arguments (already done into - * fcinfo->arg/argnull) to determine whether they are NULL; if - * either is NULL then the result is determined. If neither is - * NULL, then proceed to evaluate the comparison function, which - * is just the type's standard equality operator. We need not - * care whether that function is strict. Because the handling of - * nulls is different, we can't just reuse EEOP_FUNCEXPR. + * fcinfo->args) to determine whether they are NULL; if either is + * NULL then the result is determined. If neither is NULL, then + * proceed to evaluate the comparison function, which is just the + * type's standard equality operator. We need not care whether + * that function is strict. Because the handling of nulls is + * different, we can't just reuse EEOP_FUNCEXPR. */ FunctionCallInfo fcinfo = op->d.func.fcinfo_data; /* check function arguments for NULLness */ - if (fcinfo->argnull[0] && fcinfo->argnull[1]) + if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) { /* Both NULL? Then is not distinct... */ *op->resvalue = BoolGetDatum(false); *op->resnull = false; } - else if (fcinfo->argnull[0] || fcinfo->argnull[1]) + else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) { /* Only one is NULL? Then is distinct... */ *op->resvalue = BoolGetDatum(true); @@ -1141,12 +1142,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) { FunctionCallInfo fcinfo = op->d.func.fcinfo_data; - if (fcinfo->argnull[0] && fcinfo->argnull[1]) + if (fcinfo->args[0].isnull && fcinfo->args[1].isnull) { *op->resvalue = BoolGetDatum(true); *op->resnull = false; } - else if (fcinfo->argnull[0] || fcinfo->argnull[1]) + else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull) { *op->resvalue = BoolGetDatum(false); *op->resnull = false; @@ -1167,12 +1168,12 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_NULLIF) { /* - * The arguments are already evaluated into fcinfo->arg/argnull. + * The arguments are already evaluated into fcinfo->args. */ FunctionCallInfo fcinfo = op->d.func.fcinfo_data; /* if either argument is NULL they can't be equal */ - if (!fcinfo->argnull[0] && !fcinfo->argnull[1]) + if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull) { Datum result; @@ -1190,8 +1191,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) } /* Arguments aren't equal, so return the first one */ - *op->resvalue = fcinfo->arg[0]; - *op->resnull = fcinfo->argnull[0]; + *op->resvalue = fcinfo->args[0].value; + *op->resnull = fcinfo->args[0].isnull; EEO_NEXT(); } @@ -1257,7 +1258,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) /* force NULL result if strict fn and NULL input */ if (op->d.rowcompare_step.finfo->fn_strict && - (fcinfo->argnull[0] || fcinfo->argnull[1])) + (fcinfo->args[0].isnull || fcinfo->args[1].isnull)) { *op->resnull = true; EEO_JUMP(op->d.rowcompare_step.jumpnull); @@ -1496,10 +1497,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) /* evaluate a strict aggregate deserialization function */ EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE) { - bool *argnull = op->d.agg_deserialize.fcinfo_data->argnull; - /* Don't call a strict deserialization function with NULL input */ - if (argnull[0]) + if (op->d.agg_deserialize.fcinfo_data->args[0].isnull) EEO_JUMP(op->d.agg_deserialize.jumpnull); /* fallthrough */ @@ -1529,7 +1528,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * Check that a strict aggregate transition / combination function's * input is not NULL. */ - EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK) + EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS) { int argno; bool *nulls = op->d.agg_strict_input_check.nulls; @@ -1543,6 +1542,20 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS) + { + int argno; + NullableDatum *args = op->d.agg_strict_input_check.args; + int nargs = op->d.agg_strict_input_check.nargs; + + for (argno = 0; argno < nargs; argno++) + { + if (args[argno].isnull) + EEO_JUMP(op->d.agg_strict_input_check.jumpnull); + } + EEO_NEXT(); + } + /* * Initialize an aggregate's first value if necessary. */ @@ -1613,7 +1626,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) Assert(pertrans->transtypeByVal); - fcinfo = &pertrans->transfn_fcinfo; + fcinfo = pertrans->transfn_fcinfo; /* cf. select_current_set() */ aggstate->curaggcontext = op->d.agg_trans.aggcontext; @@ -1625,8 +1638,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) /* invoke transition function in per-tuple context */ oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); - fcinfo->arg[0] = pergroup->transValue; - fcinfo->argnull[0] = pergroup->transValueIsNull; + fcinfo->args[0].value = pergroup->transValue; + fcinfo->args[0].isnull = pergroup->transValueIsNull; fcinfo->isnull = false; /* just in case transfn doesn't set it */ newVal = FunctionCallInvoke(fcinfo); @@ -1664,7 +1677,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) Assert(!pertrans->transtypeByVal); - fcinfo = &pertrans->transfn_fcinfo; + fcinfo = pertrans->transfn_fcinfo; /* cf. select_current_set() */ aggstate->curaggcontext = op->d.agg_trans.aggcontext; @@ -1676,8 +1689,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) /* invoke transition function in per-tuple context */ oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory); - fcinfo->arg[0] = pergroup->transValue; - fcinfo->argnull[0] = pergroup->transValueIsNull; + fcinfo->args[0].value = pergroup->transValue; + fcinfo->args[0].isnull = pergroup->transValueIsNull; fcinfo->isnull = false; /* just in case transfn doesn't set it */ newVal = FunctionCallInvoke(fcinfo); @@ -2075,7 +2088,7 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull) { ExprEvalStep *op = &state->steps[0]; FunctionCallInfo fcinfo; - bool *argnull; + NullableDatum *args; int argno; Datum d; @@ -2089,12 +2102,12 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull) op++; fcinfo = op->d.func.fcinfo_data; - argnull = fcinfo->argnull; + args = fcinfo->args; /* strict function, so check for NULL args */ for (argno = 0; argno < op->d.func.nargs; argno++) { - if (argnull[argno]) + if (args[argno].isnull) { *isnull = true; return (Datum) 0; @@ -2220,14 +2233,14 @@ ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op, FunctionCallInfo fcinfo = op->d.func.fcinfo_data; PgStat_FunctionCallUsage fcusage; - bool *argnull = fcinfo->argnull; + NullableDatum *args = fcinfo->args; int argno; Datum d; /* strict function, so check for NULL args */ for (argno = 0; argno < op->d.func.nargs; argno++) { - if (argnull[argno]) + if (args[argno].isnull) { *op->resnull = true; return; @@ -2317,8 +2330,8 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) { + LOCAL_FCINFO(fcinfo, 0); SQLValueFunction *svf = op->d.sqlvaluefunction.svf; - FunctionCallInfoData fcinfo; *op->resnull = false; @@ -2350,24 +2363,24 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) case SVFOP_CURRENT_ROLE: case SVFOP_CURRENT_USER: case SVFOP_USER: - InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); - *op->resvalue = current_user(&fcinfo); - *op->resnull = fcinfo.isnull; + InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); + *op->resvalue = current_user(fcinfo); + *op->resnull = fcinfo->isnull; break; case SVFOP_SESSION_USER: - InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); - *op->resvalue = session_user(&fcinfo); - *op->resnull = fcinfo.isnull; + InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); + *op->resvalue = session_user(fcinfo); + *op->resnull = fcinfo->isnull; break; case SVFOP_CURRENT_CATALOG: - InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); - *op->resvalue = current_database(&fcinfo); - *op->resnull = fcinfo.isnull; + InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); + *op->resvalue = current_database(fcinfo); + *op->resnull = fcinfo->isnull; break; case SVFOP_CURRENT_SCHEMA: - InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); - *op->resvalue = current_schema(&fcinfo); - *op->resnull = fcinfo.isnull; + InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); + *op->resvalue = current_schema(fcinfo); + *op->resnull = fcinfo->isnull; break; } } @@ -2800,8 +2813,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op) int off; /* set at initialization */ - Assert(fcinfo->argnull[0] == false); - Assert(fcinfo->argnull[1] == false); + Assert(fcinfo->args[0].isnull == false); + Assert(fcinfo->args[1].isnull == false); /* default to null result */ *op->resnull = true; @@ -2823,8 +2836,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op) int cmpresult; /* apply comparison function */ - fcinfo->arg[0] = *op->resvalue; - fcinfo->arg[1] = values[off]; + fcinfo->args[0].value = *op->resvalue; + fcinfo->args[1].value = values[off]; fcinfo->isnull = false; cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo)); @@ -3324,7 +3337,7 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext * Evaluate "scalar op ANY/ALL (array)". * * Source array is in our result area, scalar arg is already evaluated into - * fcinfo->arg[0]/argnull[0]. + * fcinfo->args[0]. * * The operator always yields boolean, and we combine the results across all * array elements using OR and AND (for ANY and ALL respectively). Of course @@ -3376,7 +3389,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) * If the scalar is NULL, and the function is strict, return NULL; no * point in iterating the loop. */ - if (fcinfo->argnull[0] && strictfunc) + if (fcinfo->args[0].isnull && strictfunc) { *op->resnull = true; return; @@ -3416,20 +3429,20 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) /* Get array element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { - fcinfo->arg[1] = (Datum) 0; - fcinfo->argnull[1] = true; + fcinfo->args[1].value = (Datum) 0; + fcinfo->args[1].isnull = true; } else { elt = fetch_att(s, typbyval, typlen); s = att_addlength_pointer(s, typlen, s); s = (char *) att_align_nominal(s, typalign); - fcinfo->arg[1] = elt; - fcinfo->argnull[1] = false; + fcinfo->args[1].value = elt; + fcinfo->args[1].isnull = false; } /* Call comparison function */ - if (fcinfo->argnull[1] && strictfunc) + if (fcinfo->args[1].isnull && strictfunc) { fcinfo->isnull = true; thisresult = (Datum) 0; @@ -4044,7 +4057,7 @@ ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext, void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup) { - FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; + FunctionCallInfo fcinfo = pertrans->transfn_fcinfo; MemoryContext oldContext; /* @@ -4055,7 +4068,7 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup */ oldContext = MemoryContextSwitchTo( aggstate->curaggcontext->ecxt_per_tuple_memory); - pergroup->transValue = datumCopy(fcinfo->arg[1], + pergroup->transValue = datumCopy(fcinfo->args[1].value, pertrans->transtypeByVal, pertrans->transtypeLen); pergroup->transValueIsNull = false; diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index 0c086c52904..265250186a1 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; + FunctionCallInfo fcinfo; PgStat_FunctionCallUsage fcusage; ReturnSetInfo rsinfo; HeapTupleData tmptup; @@ -141,6 +141,8 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, rsinfo.setResult = NULL; rsinfo.setDesc = NULL; + fcinfo = palloc(SizeForFunctionCallInfo(list_length(setexpr->args))); + /* * Normally the passed expression tree will be a SetExprState, since the * grammar only allows a function call at the top level of a table @@ -157,9 +159,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, * This path is similar to ExecMakeFunctionResultSet. */ returnsSet = setexpr->funcReturnsSet; - InitFunctionCallInfoData(fcinfo, &(setexpr->func), + InitFunctionCallInfoData(*fcinfo, &(setexpr->func), list_length(setexpr->args), - setexpr->fcinfo_data.fncollation, + setexpr->fcinfo->fncollation, NULL, (Node *) &rsinfo); /* @@ -174,7 +176,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, */ MemoryContextReset(argContext); oldcontext = MemoryContextSwitchTo(argContext); - ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext); + ExecEvalFuncArgs(fcinfo, setexpr->args, econtext); MemoryContextSwitchTo(oldcontext); /* @@ -186,9 +188,9 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, { int i; - for (i = 0; i < fcinfo.nargs; i++) + for (i = 0; i < fcinfo->nargs; i++) { - if (fcinfo.argnull[i]) + if (fcinfo->args[i].isnull) goto no_function_result; } } @@ -196,7 +198,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, else { /* Treat setexpr as a generic expression */ - InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); + InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); } /* @@ -224,11 +226,11 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, /* Call the function or expression one time */ if (!setexpr->elidedFuncState) { - pgstat_init_function_usage(&fcinfo, &fcusage); + pgstat_init_function_usage(fcinfo, &fcusage); - fcinfo.isnull = false; + fcinfo->isnull = false; rsinfo.isDone = ExprSingleResult; - result = FunctionCallInvoke(&fcinfo); + result = FunctionCallInvoke(fcinfo); pgstat_end_function_usage(&fcusage, rsinfo.isDone != ExprMultipleResult); @@ -236,7 +238,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, else { result = - ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull); + ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull); rsinfo.isDone = ExprSingleResult; } @@ -277,7 +279,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, */ if (returnsTuple) { - if (!fcinfo.isnull) + if (!fcinfo->isnull) { HeapTupleHeader td = DatumGetHeapTupleHeader(result); @@ -338,7 +340,7 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, else { /* Scalar-type case: just store the function result */ - tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull); + tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull); } /* @@ -547,7 +549,7 @@ restart: * rows from this SRF have been returned, otherwise ValuePerCall SRFs * would reference freed memory after the first returned row. */ - fcinfo = &fcache->fcinfo_data; + fcinfo = fcache->fcinfo; arguments = fcache->args; if (!fcache->setArgsValid) { @@ -587,7 +589,7 @@ restart: { for (i = 0; i < fcinfo->nargs; i++) { - if (fcinfo->argnull[i]) + if (fcinfo->args[i].isnull) { callit = false; break; @@ -678,6 +680,7 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node, MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF) { AclResult aclresult; + size_t numargs = list_length(sexpr->args); /* Check permission to call function */ aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE); @@ -704,8 +707,10 @@ init_sexpr(Oid foid, Oid input_collation, Expr *node, fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func)); /* Initialize the function call parameter struct as well */ - InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func), - list_length(sexpr->args), + sexpr->fcinfo = + (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs)); + InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func), + numargs, input_collation, NULL, NULL); /* If function returns set, check if that's allowed by caller */ @@ -820,9 +825,9 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo, { ExprState *argstate = (ExprState *) lfirst(arg); - fcinfo->arg[i] = ExecEvalExpr(argstate, - econtext, - &fcinfo->argnull[i]); + fcinfo->args[i].value = ExecEvalExpr(argstate, + econtext, + &fcinfo->args[i].isnull); i++; } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index de41588105e..c6b7203f813 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -933,8 +933,8 @@ postquel_sub_params(SQLFunctionCachePtr fcache, { ParamExternData *prm = ¶mLI->params[i]; - prm->value = fcinfo->arg[i]; - prm->isnull = fcinfo->argnull[i]; + prm->value = fcinfo->args[i].value; + prm->isnull = fcinfo->args[i].isnull; prm->pflags = 0; prm->ptype = fcache->pinfo->argtypes[i]; } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 508c9195743..2a260a71f24 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].value, pertrans->transtypeByVal, pertrans->transtypeLen); pergroupstate->transValueIsNull = false; @@ -613,8 +613,8 @@ advance_transition_function(AggState *aggstate, /* * OK to call the transition function */ - fcinfo->arg[0] = pergroupstate->transValue; - fcinfo->argnull[0] = pergroupstate->transValueIsNull; + fcinfo->args[0].value = pergroupstate->transValue; + fcinfo->args[0].isnull = pergroupstate->transValueIsNull; fcinfo->isnull = false; /* just in case transfn doesn't set it */ newVal = FunctionCallInvoke(fcinfo); @@ -717,7 +717,7 @@ process_ordered_aggregate_single(AggState *aggstate, bool isDistinct = (pertrans->numDistinctCols > 0); Datum newAbbrevVal = (Datum) 0; Datum oldAbbrevVal = (Datum) 0; - FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; + FunctionCallInfo fcinfo = pertrans->transfn_fcinfo; Datum *newVal; bool *isNull; @@ -726,8 +726,8 @@ process_ordered_aggregate_single(AggState *aggstate, tuplesort_performsort(pertrans->sortstates[aggstate->current_set]); /* Load the column into argument 1 (arg 0 will be transition value) */ - newVal = fcinfo->arg + 1; - isNull = fcinfo->argnull + 1; + newVal = &fcinfo->args[1].value; + isNull = &fcinfo->args[1].isnull; /* * Note: if input type is pass-by-ref, the datums returned by the sort are @@ -803,7 +803,7 @@ process_ordered_aggregate_multi(AggState *aggstate, AggStatePerGroup pergroupstate) { ExprContext *tmpcontext = aggstate->tmpcontext; - FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; + FunctionCallInfo fcinfo = pertrans->transfn_fcinfo; TupleTableSlot *slot1 = pertrans->sortslot; TupleTableSlot *slot2 = pertrans->uniqslot; int numTransInputs = pertrans->numTransInputs; @@ -843,8 +843,8 @@ process_ordered_aggregate_multi(AggState *aggstate, /* Start from 1, since the 0th arg will be the transition value */ for (i = 0; i < numTransInputs; i++) { - fcinfo->arg[i + 1] = slot1->tts_values[i]; - fcinfo->argnull[i + 1] = slot1->tts_isnull[i]; + fcinfo->args[i + 1].value = slot1->tts_values[i]; + fcinfo->args[i + 1].isnull = slot1->tts_isnull[i]; } advance_transition_function(aggstate, pertrans, pergroupstate); @@ -897,7 +897,7 @@ finalize_aggregate(AggState *aggstate, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull) { - FunctionCallInfoData fcinfo; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); bool anynull = false; MemoryContext oldContext; int i; @@ -917,10 +917,10 @@ finalize_aggregate(AggState *aggstate, { ExprState *expr = (ExprState *) lfirst(lc); - fcinfo.arg[i] = ExecEvalExpr(expr, - aggstate->ss.ps.ps_ExprContext, - &fcinfo.argnull[i]); - anynull |= fcinfo.argnull[i]; + fcinfo->args[i].value = ExecEvalExpr(expr, + aggstate->ss.ps.ps_ExprContext, + &fcinfo->args[i].isnull); + anynull |= fcinfo->args[i].isnull; i++; } @@ -934,27 +934,28 @@ finalize_aggregate(AggState *aggstate, /* set up aggstate->curperagg for AggGetAggref() */ aggstate->curperagg = peragg; - InitFunctionCallInfoData(fcinfo, &peragg->finalfn, + InitFunctionCallInfoData(*fcinfo, &peragg->finalfn, numFinalArgs, pertrans->aggCollation, (void *) aggstate, NULL); /* Fill in the transition state value */ - fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue, - pergroupstate->transValueIsNull, - pertrans->transtypeLen); - fcinfo.argnull[0] = pergroupstate->transValueIsNull; + fcinfo->args[0].value = + MakeExpandedObjectReadOnly(pergroupstate->transValue, + pergroupstate->transValueIsNull, + pertrans->transtypeLen); + fcinfo->args[0].isnull = pergroupstate->transValueIsNull; anynull |= pergroupstate->transValueIsNull; /* Fill any remaining argument positions with nulls */ for (; i < numFinalArgs; i++) { - fcinfo.arg[i] = (Datum) 0; - fcinfo.argnull[i] = true; + fcinfo->args[i].value = (Datum) 0; + fcinfo->args[i].isnull = true; anynull = true; } - if (fcinfo.flinfo->fn_strict && anynull) + if (fcinfo->flinfo->fn_strict && anynull) { /* don't call a strict function with NULL inputs */ *resultVal = (Datum) 0; @@ -962,8 +963,8 @@ finalize_aggregate(AggState *aggstate, } else { - *resultVal = FunctionCallInvoke(&fcinfo); - *resultIsNull = fcinfo.isnull; + *resultVal = FunctionCallInvoke(fcinfo); + *resultIsNull = fcinfo->isnull; } aggstate->curperagg = NULL; } @@ -1018,12 +1019,13 @@ finalize_partialaggregate(AggState *aggstate, } else { - FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo; + FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo; - fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue, - pergroupstate->transValueIsNull, - pertrans->transtypeLen); - fcinfo->argnull[0] = pergroupstate->transValueIsNull; + fcinfo->args[0].value = + MakeExpandedObjectReadOnly(pergroupstate->transValue, + pergroupstate->transValueIsNull, + pertrans->transtypeLen); + fcinfo->args[0].isnull = pergroupstate->transValueIsNull; *resultVal = FunctionCallInvoke(fcinfo); *resultIsNull = fcinfo->isnull; @@ -2927,7 +2929,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, fmgr_info(aggtransfn, &pertrans->transfn); fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn); - InitFunctionCallInfoData(pertrans->transfn_fcinfo, + pertrans->transfn_fcinfo = + (FunctionCallInfo) palloc(SizeForFunctionCallInfo(2)); + InitFunctionCallInfoData(*pertrans->transfn_fcinfo, &pertrans->transfn, 2, pertrans->aggCollation, @@ -2947,6 +2951,7 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, else { Expr *transfnexpr; + size_t numInputs = pertrans->numTransInputs + 1; /* * Set up infrastructure for calling the transfn. Note that invtrans @@ -2965,9 +2970,11 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, fmgr_info(aggtransfn, &pertrans->transfn); fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn); - InitFunctionCallInfoData(pertrans->transfn_fcinfo, + pertrans->transfn_fcinfo = + (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numInputs)); + InitFunctionCallInfoData(*pertrans->transfn_fcinfo, &pertrans->transfn, - pertrans->numTransInputs + 1, + numInputs, pertrans->aggCollation, (void *) aggstate, NULL); @@ -3003,7 +3010,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, fmgr_info(aggserialfn, &pertrans->serialfn); fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn); - InitFunctionCallInfoData(pertrans->serialfn_fcinfo, + pertrans->serialfn_fcinfo = + (FunctionCallInfo) palloc(SizeForFunctionCallInfo(1)); + InitFunctionCallInfoData(*pertrans->serialfn_fcinfo, &pertrans->serialfn, 1, InvalidOid, @@ -3017,7 +3026,9 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, fmgr_info(aggdeserialfn, &pertrans->deserialfn); fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn); - InitFunctionCallInfoData(pertrans->deserialfn_fcinfo, + pertrans->deserialfn_fcinfo = + (FunctionCallInfo) palloc(SizeForFunctionCallInfo(2)); + InitFunctionCallInfoData(*pertrans->deserialfn_fcinfo, &pertrans->deserialfn, 2, InvalidOid, diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 7ae56074ca8..731391f1907 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -241,10 +241,9 @@ advance_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate) { + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate; int numArguments = perfuncstate->numArguments; - FunctionCallInfoData fcinfodata; - FunctionCallInfo fcinfo = &fcinfodata; Datum newVal; ListCell *arg; int i; @@ -273,8 +272,8 @@ advance_windowaggregate(WindowAggState *winstate, { ExprState *argstate = (ExprState *) lfirst(arg); - fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i]); + fcinfo->args[i].value = ExecEvalExpr(argstate, econtext, + &fcinfo->args[i].isnull); i++; } @@ -287,7 +286,7 @@ advance_windowaggregate(WindowAggState *winstate, */ for (i = 1; i <= numArguments; i++) { - if (fcinfo->argnull[i]) + if (fcinfo->args[i].isnull) { MemoryContextSwitchTo(oldContext); return; @@ -306,7 +305,7 @@ advance_windowaggregate(WindowAggState *winstate, if (peraggstate->transValueCount == 0 && peraggstate->transValueIsNull) { MemoryContextSwitchTo(peraggstate->aggcontext); - peraggstate->transValue = datumCopy(fcinfo->arg[1], + peraggstate->transValue = datumCopy(fcinfo->args[1].value, peraggstate->transtypeByVal, peraggstate->transtypeLen); peraggstate->transValueIsNull = false; @@ -339,8 +338,8 @@ advance_windowaggregate(WindowAggState *winstate, numArguments + 1, perfuncstate->winCollation, (void *) winstate, NULL); - fcinfo->arg[0] = peraggstate->transValue; - fcinfo->argnull[0] = peraggstate->transValueIsNull; + fcinfo->args[0].value = peraggstate->transValue; + fcinfo->args[0].isnull = peraggstate->transValueIsNull; winstate->curaggcontext = peraggstate->aggcontext; newVal = FunctionCallInvoke(fcinfo); winstate->curaggcontext = NULL; @@ -418,10 +417,9 @@ advance_windowaggregate_base(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate) { + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate; int numArguments = perfuncstate->numArguments; - FunctionCallInfoData fcinfodata; - FunctionCallInfo fcinfo = &fcinfodata; Datum newVal; ListCell *arg; int i; @@ -450,8 +448,8 @@ advance_windowaggregate_base(WindowAggState *winstate, { ExprState *argstate = (ExprState *) lfirst(arg); - fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, - &fcinfo->argnull[i]); + fcinfo->args[i].value = ExecEvalExpr(argstate, econtext, + &fcinfo->args[i].isnull); i++; } @@ -464,7 +462,7 @@ advance_windowaggregate_base(WindowAggState *winstate, */ for (i = 1; i <= numArguments; i++) { - if (fcinfo->argnull[i]) + if (fcinfo->args[i].isnull) { MemoryContextSwitchTo(oldContext); return true; @@ -510,8 +508,8 @@ advance_windowaggregate_base(WindowAggState *winstate, numArguments + 1, perfuncstate->winCollation, (void *) winstate, NULL); - fcinfo->arg[0] = peraggstate->transValue; - fcinfo->argnull[0] = peraggstate->transValueIsNull; + fcinfo->args[0].value = peraggstate->transValue; + fcinfo->args[0].isnull = peraggstate->transValueIsNull; winstate->curaggcontext = peraggstate->aggcontext; newVal = FunctionCallInvoke(fcinfo); winstate->curaggcontext = NULL; @@ -591,30 +589,31 @@ finalize_windowaggregate(WindowAggState *winstate, */ if (OidIsValid(peraggstate->finalfn_oid)) { + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); int numFinalArgs = peraggstate->numFinalArgs; - FunctionCallInfoData fcinfo; bool anynull; int i; - InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), + InitFunctionCallInfoData(fcinfodata.fcinfo, &(peraggstate->finalfn), numFinalArgs, perfuncstate->winCollation, (void *) winstate, NULL); - fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue, - peraggstate->transValueIsNull, - peraggstate->transtypeLen); - fcinfo.argnull[0] = peraggstate->transValueIsNull; + fcinfo->args[0].value = + MakeExpandedObjectReadOnly(peraggstate->transValue, + peraggstate->transValueIsNull, + peraggstate->transtypeLen); + fcinfo->args[0].isnull = peraggstate->transValueIsNull; anynull = peraggstate->transValueIsNull; /* Fill any remaining argument positions with nulls */ for (i = 1; i < numFinalArgs; i++) { - fcinfo.arg[i] = (Datum) 0; - fcinfo.argnull[i] = true; + fcinfo->args[i].value = (Datum) 0; + fcinfo->args[i].isnull = true; anynull = true; } - if (fcinfo.flinfo->fn_strict && anynull) + if (fcinfo->flinfo->fn_strict && anynull) { /* don't call a strict function with NULL inputs */ *result = (Datum) 0; @@ -623,9 +622,9 @@ finalize_windowaggregate(WindowAggState *winstate, else { winstate->curaggcontext = peraggstate->aggcontext; - *result = FunctionCallInvoke(&fcinfo); + *result = FunctionCallInvoke(fcinfo); winstate->curaggcontext = NULL; - *isnull = fcinfo.isnull; + *isnull = fcinfo->isnull; } } else @@ -1032,7 +1031,7 @@ static void eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull) { - FunctionCallInfoData fcinfo; + LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); MemoryContext oldContext; oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory); @@ -1043,24 +1042,25 @@ eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, * implementations to support varying numbers of arguments. The real info * goes through the WindowObject, which is passed via fcinfo->context. */ - InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo), + InitFunctionCallInfoData(*fcinfo, &(perfuncstate->flinfo), perfuncstate->numArguments, perfuncstate->winCollation, (void *) perfuncstate->winobj, NULL); /* Just in case, make all the regular argument slots be null */ - memset(fcinfo.argnull, true, perfuncstate->numArguments); + for (int argno = 0; argno < perfuncstate->numArguments; argno++) + fcinfo->args[argno].isnull = true; /* Window functions don't have a current aggregate context, either */ winstate->curaggcontext = NULL; - *result = FunctionCallInvoke(&fcinfo); - *isnull = fcinfo.isnull; + *result = FunctionCallInvoke(fcinfo); + *isnull = fcinfo->isnull; /* * Make sure pass-by-ref data is allocated in the appropriate context. (We * need this in case the function returns a pointer into some short-lived * tuple, as is entirely possible.) */ - if (!perfuncstate->resulttypeByVal && !fcinfo.isnull && + if (!perfuncstate->resulttypeByVal && !fcinfo->isnull && !MemoryContextContains(CurrentMemoryContext, DatumGetPointer(*result))) *result = datumCopy(*result, |