diff options
Diffstat (limited to 'src/backend/catalog/pg_aggregate.c')
| -rw-r--r-- | src/backend/catalog/pg_aggregate.c | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 633b8f1d6a..d99c2e5eda 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -60,6 +60,8 @@ AggregateCreate(const char *aggName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, + bool finalfnExtraArgs, + bool mfinalfnExtraArgs, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, @@ -344,48 +346,46 @@ AggregateCreate(const char *aggName, ReleaseSysCache(tup); } - /* - * Set up fnArgs for looking up finalfn(s) - * - * For ordinary aggs, the finalfn just takes the transtype. For - * ordered-set aggs, it takes the transtype plus all args. (The - * aggregated args are useless at runtime, and are actually passed as - * NULLs, but we may need them in the function signature to allow - * resolution of a polymorphic agg's result type.) - */ - fnArgs[0] = aggTransType; - if (AGGKIND_IS_ORDERED_SET(aggKind)) - { - nargs_finalfn = numArgs + 1; - memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); - } - else - { - nargs_finalfn = 1; - /* variadic-ness of the aggregate doesn't affect finalfn */ - variadicArgType = InvalidOid; - } - /* handle finalfn, if supplied */ if (aggfinalfnName) { + /* + * If finalfnExtraArgs is specified, the transfn takes the transtype + * plus all args; otherwise, it just takes the transtype plus any + * direct args. (Non-direct args are useless at runtime, and are + * actually passed as NULLs, but we may need them in the function + * signature to allow resolution of a polymorphic agg's result type.) + */ + Oid ffnVariadicArgType = variadicArgType; + + fnArgs[0] = aggTransType; + memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); + if (finalfnExtraArgs) + nargs_finalfn = numArgs + 1; + else + { + nargs_finalfn = numDirectArgs + 1; + if (numDirectArgs < numArgs) + { + /* variadic argument doesn't affect finalfn */ + ffnVariadicArgType = InvalidOid; + } + } + finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn, - fnArgs, variadicArgType, + fnArgs, ffnVariadicArgType, &finaltype); /* - * The finalfn of an ordered-set agg will certainly be passed at least - * one null argument, so complain if it's strict. Nothing bad would - * happen at runtime (you'd just get a null result), but it's surely - * not what the user wants, so let's complain now. - * - * Note: it's likely that a strict transfn would also be a mistake, - * but the case isn't quite so airtight, so we let that pass. + * When finalfnExtraArgs is specified, the finalfn will certainly be + * passed at least one null argument, so complain if it's strict. + * Nothing bad would happen at runtime (you'd just get a null result), + * but it's surely not what the user wants, so let's complain now. */ - if (AGGKIND_IS_ORDERED_SET(aggKind) && func_strict(finalfn)) + if (finalfnExtraArgs && func_strict(finalfn)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("final function of an ordered-set aggregate must not be declared STRICT"))); + errmsg("final function with extra arguments must not be declared STRICT"))); } else { @@ -434,21 +434,34 @@ AggregateCreate(const char *aggName, if (aggmfinalfnName) { /* - * The arguments are the same as for the regular finalfn, except - * that the transition data type might be different. So re-use - * the fnArgs values set up above, except for that one. + * The arguments are figured the same way as for the regular + * finalfn, but using aggmTransType and mfinalfnExtraArgs. */ + Oid ffnVariadicArgType = variadicArgType; + fnArgs[0] = aggmTransType; + memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); + if (mfinalfnExtraArgs) + nargs_finalfn = numArgs + 1; + else + { + nargs_finalfn = numDirectArgs + 1; + if (numDirectArgs < numArgs) + { + /* variadic argument doesn't affect finalfn */ + ffnVariadicArgType = InvalidOid; + } + } mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn, - fnArgs, variadicArgType, + fnArgs, ffnVariadicArgType, &rettype); - /* As above, check strictness if it's an ordered-set agg */ - if (AGGKIND_IS_ORDERED_SET(aggKind) && func_strict(mfinalfn)) + /* As above, check strictness if mfinalfnExtraArgs is given */ + if (mfinalfnExtraArgs && func_strict(mfinalfn)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("final function of an ordered-set aggregate must not be declared STRICT"))); + errmsg("final function with extra arguments must not be declared STRICT"))); } else { @@ -554,6 +567,8 @@ AggregateCreate(const char *aggName, values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn); values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn); values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn); + values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs); + values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs); values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop); values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType); values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace); |
