Allow polymorphic aggregates to have non-polymorphic state data types.

Before 9.4, such an aggregate couldn't be declared, because its final
function would have to have polymorphic result type but no polymorphic
argument, which CREATE FUNCTION would quite properly reject.  The
ordered-set-aggregate patch found a workaround: allow the final function
to be declared as accepting additional dummy arguments that have types
matching the aggregate's regular input arguments.  However, we failed
to notice that this problem applies just as much to regular aggregates,
despite the fact that we had a built-in regular aggregate array_agg()
that was known to be undeclarable in SQL because its final function
had an illegal signature.  So what we should have done, and what this
patch does, is to decouple the extra-dummy-arguments behavior from
ordered-set aggregates and make it generally available for all aggregate
declarations.  We have to put this into 9.4 rather than waiting till
later because it slightly alters the rules for declaring ordered-set
aggregates.

The patch turned out a bit bigger than I'd hoped because it proved
necessary to record the extra-arguments option in a new pg_aggregate
column.  I'd thought we could just look at the final function's pronargs
at runtime, but that didn't work well for variadic final functions.
It's probably just as well though, because it simplifies life for pg_dump
to record the option explicitly.

While at it, fix array_agg() to have a valid final-function signature,
and add an opr_sanity test to notice future deviations from polymorphic
consistency.  I also marked the percentile_cont() aggregates as not
needing extra arguments, since they don't.
This commit is contained in:
Tom Lane 2014-04-23 19:17:31 -04:00
parent 125ba2945a
commit f0fedfe82c
17 changed files with 509 additions and 298 deletions

View File

@ -404,6 +404,18 @@
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>Final function for moving-aggregate mode (zero if none)</entry>
</row>
<row>
<entry><structfield>aggfinalextra</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>True to pass extra dummy arguments to aggfinalfn</entry>
</row>
<row>
<entry><structfield>aggmfinalextra</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>True to pass extra dummy arguments to aggmfinalfn</entry>
</row>
<row>
<entry><structfield>aggsortop</structfield></entry>
<entry><type>oid</type></entry>

View File

@ -26,12 +26,14 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replacea
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , MSFUNC = <replaceable class="PARAMETER">msfunc</replaceable> ]
[ , MINVFUNC = <replaceable class="PARAMETER">minvfunc</replaceable> ]
[ , MSTYPE = <replaceable class="PARAMETER">mstate_data_type</replaceable> ]
[ , MSSPACE = <replaceable class="PARAMETER">mstate_data_size</replaceable> ]
[ , MFINALFUNC = <replaceable class="PARAMETER">mffunc</replaceable> ]
[ , MFINALFUNC_EXTRA ]
[ , MINITCOND = <replaceable class="PARAMETER">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
)
@ -42,6 +44,7 @@ CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ [ <replac
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , HYPOTHETICAL ]
)
@ -54,12 +57,14 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , MSFUNC = <replaceable class="PARAMETER">sfunc</replaceable> ]
[ , MINVFUNC = <replaceable class="PARAMETER">invfunc</replaceable> ]
[ , MSTYPE = <replaceable class="PARAMETER">state_data_type</replaceable> ]
[ , MSSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , MFINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , MFINALFUNC_EXTRA ]
[ , MINITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
)
@ -166,12 +171,25 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
input rows.
</para>
<para>
Sometimes it is useful to declare the final function as taking not just
the state value, but extra parameters corresponding to the aggregate's
input values. The main reason for doing this is if the final function
is polymorphic and the state value's data type would be inadequate to
pin down the result type. These extra parameters are always passed as
NULL (and so the final function must not be strict when
the <literal>FINALFUNC_EXTRA</> option is used), but nonetheless they
are valid parameters. The final function could for example make use
of <function>get_fn_expr_argtype</> to identify the actual argument type
in the current call.
</para>
<para>
An aggregate can optionally support <firstterm>moving-aggregate mode</>,
as described in <xref linkend="xaggr-moving-aggregates">. This requires
specifying the <literal>MSFUNC</>, <literal>MINVFUNC</>,
and <literal>MSTYPE</> parameters, and optionally
the <literal>MSPACE</>, <literal>MFINALFUNC</>,
the <literal>MSPACE</>, <literal>MFINALFUNC</>, <literal>MFINALFUNC_EXTRA</>,
and <literal>MINITCOND</> parameters. Except for <literal>MINVFUNC</>,
these parameters work like the corresponding simple-aggregate parameters
without <literal>M</>; they define a separate implementation of the
@ -361,12 +379,16 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
<para>
For ordered-set (including hypothetical-set) aggregates, the
final function receives not only the final state value,
but also the values of all the direct arguments, followed by
null values corresponding to each aggregated argument.
(The reason for including the aggregated arguments in the function
signature is that this may be necessary to allow correct resolution
of the aggregate result type, when a polymorphic aggregate is
being defined.)
but also the values of all the direct arguments.
</para>
<para>
If <literal>FINALFUNC_EXTRA</> is specified, then in addition to the
final state value and any direct arguments, the final function
receives extra NULL values corresponding to the aggregate's regular
(aggregated) arguments. This is mainly useful to allow correct
resolution of the aggregate result type when a polymorphic aggregate
is being defined.
</para>
</listitem>
</varlistentry>
@ -438,9 +460,11 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
The name of the final function called to compute the aggregate's
result after all input rows have been traversed, when using
moving-aggregate mode. This works the same as <replaceable>ffunc</>,
except that its input type is <replaceable>mstate_data_type</>.
except that its first argument's type
is <replaceable>mstate_data_type</> and extra dummy arguments are
specified by writing <literal>MFINALFUNC_EXTRA</>.
The aggregate result type determined by <replaceable>mffunc</>
and <replaceable>mstate_data_type</> must match that determined by the
or <replaceable>mstate_data_type</> must match that determined by the
aggregate's regular implementation.
</para>
</listitem>
@ -494,6 +518,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
<refsect1>
<title>Notes</title>
<para>
In parameters that specify support function names, you can write
a schema name if needed, for example <literal>SFUNC = public.sum</>.
Do not write argument types there, however &mdash; the argument types
of the support functions are determined from other parameters.
</para>
<para>
If an aggregate supports moving-aggregate mode, it will improve
calculation efficiency when the aggregate is used as a window function

View File

@ -127,7 +127,7 @@ CREATE AGGREGATE avg (float8)
<function>float8_accum</> requires a three-element array, not just
two elements, because it accumulates the sum of squares as well as
the sum and count of the inputs. This is so that it can be used for
some other aggregates besides <function>avg</>.
some other aggregates as well as <function>avg</>.
</para>
</note>
@ -182,7 +182,7 @@ CREATE AGGREGATE avg (float8)
The inverse transition function is passed the current state value and the
aggregate input value(s) for the earliest row included in the current
state. It must reconstruct what the state value would have been if the
given input value had never been aggregated, but only the rows following
given input row had never been aggregated, but only the rows following
it. This sometimes requires that the forward transition function keep
more state than is needed for plain aggregation mode. Therefore, the
moving-aggregate mode uses a completely separate implementation from the
@ -339,6 +339,47 @@ SELECT attrelid::regclass, array_accum(atttypid::regtype)
</programlisting>
</para>
<para>
Ordinarily, an aggregate function with a polymorphic result type has a
polymorphic state type, as in the above example. This is necessary
because otherwise the final function cannot be declared sensibly: it
would need to have a polymorphic result type but no polymorphic argument
type, which <command>CREATE FUNCTION</> will reject on the grounds that
the result type cannot be deduced from a call. But sometimes it is
inconvenient to use a polymorphic state type. The most common case is
where the aggregate support functions are to be written in C and the
state type should be declared as <type>internal</> because there is
no SQL-level equivalent for it. To address this case, it is possible to
declare the final function as taking extra <quote>dummy</> arguments
that match the input arguments of the aggregate. Such dummy arguments
are always passed as NULLs since no specific value is available when the
final function is called. Their only use is to allow a polymorphic
final function's result type to be connected to the aggregate's input
type(s). For example, the definition of the built-in
aggregate <function>array_agg</> is equivalent to
<programlisting>
CREATE FUNCTION array_agg_transfn(internal, anyelement)
RETURNS internal ...;
CREATE FUNCTION array_agg_finalfn(internal, anyelement)
RETURNS anyarray ...;
CREATE AGGREGATE array_agg (anyelement)
(
sfunc = array_agg_transfn,
stype = internal,
finalfunc = array_agg_finalfn,
finalfunc_extra
);
</programlisting>
Here, the <literal>finalfunc_extra</> option specifies that the final
function receives, in addition to the state value, extra dummy
argument(s) corresponding to the aggregate's input argument(s).
The extra <type>anyelement</> argument allows the declaration
of <function>array_agg_finalfn</> to be valid.
</para>
<para>
An aggregate function can be made to accept a varying number of arguments
by declaring its last argument as a <literal>VARIADIC</> array, in much
@ -401,15 +442,23 @@ SELECT myaggregate(a, b, c ORDER BY a) FROM ...
definition of <function>percentile_disc</> is equivalent to:
<programlisting>
CREATE FUNCTION ordered_set_transition(internal, anyelement)
RETURNS internal ...;
CREATE FUNCTION percentile_disc_final(internal, float8, anyelement)
RETURNS anyelement ...;
CREATE AGGREGATE percentile_disc (float8 ORDER BY anyelement)
(
sfunc = ordered_set_transition,
stype = internal,
finalfunc = percentile_disc_final
finalfunc = percentile_disc_final,
finalfunc_extra
);
</programlisting>
which could be used to obtain a median household income like this:
This aggregate takes a <type>float8</> direct argument (the percentile
fraction) and an aggregated input that can be of any sortable data type.
It could be used to obtain a median household income like this:
<programlisting>
SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
@ -447,25 +496,12 @@ SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
same definition as for normal aggregates, but note that the direct
arguments (if any) are not provided. The final function receives
the last state value, the values of the direct arguments if any,
and null values corresponding to the aggregated input(s). While the
null values seem useless at first sight, they are important because
they make it possible to include the data types of the aggregated
input(s) in the final function's signature, which may be necessary
to resolve the output type of a polymorphic aggregate. For example,
the built-in <function>mode()</> ordered-set aggregate takes a
single aggregated column of any sortable data type and returns a
value of that same type. This is possible because the final function
is declared as <literal>mode_final(internal, anyelement) returns
anyelement</>, with the <type>anyelement</> parameter corresponding
to the dummy null argument that represents the aggregated column.
The actual data is conveyed in the <type>internal</>-type state
value, but type resolution needs a parse-time indication of what the
result data type will be, and the dummy argument provides that.
In the example of <function>percentile_disc</>, the support functions
are respectively declared as
<literal>ordered_set_transition(internal, "any") returns internal</>
and <literal>percentile_disc_final(internal, float8, anyelement)
returns anyelement</>.
and (if <literal>finalfunc_extra</> is specified) NULL values
corresponding to the aggregated input(s). As with normal
aggregates, <literal>finalfunc_extra</> is only really useful if the
aggregate is polymorphic; then the extra dummy argument(s) are needed
to connect the final function's result type to the aggregate's input
type(s).
</para>
<para>

View File

@ -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);

View File

@ -64,6 +64,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
List *mtransfuncName = NIL;
List *minvtransfuncName = NIL;
List *mfinalfuncName = NIL;
bool finalfuncExtraArgs = false;
bool mfinalfuncExtraArgs = false;
List *sortoperatorName = NIL;
TypeName *baseType = NULL;
TypeName *transType = NULL;
@ -128,6 +130,10 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
minvtransfuncName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
mfinalfuncName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
finalfuncExtraArgs = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
mfinalfuncExtraArgs = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "basetype") == 0)
@ -380,6 +386,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
mtransfuncName, /* fwd trans function name */
minvtransfuncName, /* inv trans function name */
mfinalfuncName, /* final function name */
finalfuncExtraArgs,
mfinalfuncExtraArgs,
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
transSpace, /* transition space */

View File

@ -37,11 +37,12 @@
*
* Ordered-set aggregates are treated specially in one other way: we
* evaluate any "direct" arguments and pass them to the finalfunc along
* with the transition value. In addition, NULL placeholders are
* provided to match the remaining finalfunc arguments, which correspond
* to the aggregated expressions. (These arguments have no use at
* runtime, but may be needed to allow resolution of a polymorphic
* aggregate's result type.)
* with the transition value.
*
* A finalfunc can have additional arguments beyond the transvalue and
* any "direct" arguments, corresponding to the input arguments of the
* aggregate. These are always just passed as NULL. Such arguments may be
* needed to allow resolution of a polymorphic aggregate's result type.
*
* We compute aggregate input expressions and run the transition functions
* in a temporary econtext (aggstate->tmpcontext). This is reset at
@ -151,6 +152,14 @@ typedef struct AggStatePerAggData
*/
int numTransInputs;
/*
* Number of arguments to pass to the finalfn. This is always at least 1
* (the transition state value) plus any ordered-set direct args. If the
* finalfn wants extra args then we pass nulls corresponding to the
* aggregated input columns.
*/
int numFinalArgs;
/* Oids of transfer functions */
Oid transfn_oid;
Oid finalfn_oid; /* may be InvalidOid */
@ -797,6 +806,8 @@ finalize_aggregate(AggState *aggstate,
/*
* Evaluate any direct arguments. We do this even if there's no finalfn
* (which is unlikely anyway), so that side-effects happen as expected.
* The direct arguments go into arg positions 1 and up, leaving position 0
* for the transition state value.
*/
i = 1;
foreach(lc, peraggstate->aggrefstate->aggdirectargs)
@ -816,19 +827,7 @@ finalize_aggregate(AggState *aggstate,
*/
if (OidIsValid(peraggstate->finalfn_oid))
{
int numFinalArgs;
/*
* Identify number of arguments being passed to the finalfn. For a
* plain agg it's just one (the transition state value). For
* ordered-set aggs we also pass the direct argument(s), plus nulls
* corresponding to the aggregate-input columns.
*/
if (AGGKIND_IS_ORDERED_SET(peraggstate->aggref->aggkind))
numFinalArgs = peraggstate->numArguments + 1;
else
numFinalArgs = 1;
Assert(i <= numFinalArgs);
int numFinalArgs = peraggstate->numFinalArgs;
/* set up aggstate->curperagg for AggGetAggref() */
aggstate->curperagg = peraggstate;
@ -844,12 +843,11 @@ finalize_aggregate(AggState *aggstate,
anynull |= pergroupstate->transValueIsNull;
/* Fill any remaining argument positions with nulls */
while (i < numFinalArgs)
for (; i < numFinalArgs; i++)
{
fcinfo.arg[i] = (Datum) 0;
fcinfo.argnull[i] = true;
anynull = true;
i++;
}
if (fcinfo.flinfo->fn_strict && anynull)
@ -1776,12 +1774,18 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
numInputs = list_length(aggref->args);
peraggstate->numInputs = numInputs;
/* Detect how many columns to pass to the transfn */
/* Detect how many arguments to pass to the transfn */
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
peraggstate->numTransInputs = numInputs;
else
peraggstate->numTransInputs = numArguments;
/* Detect how many arguments to pass to the finalfn */
if (aggform->aggfinalextra)
peraggstate->numFinalArgs = numArguments + 1;
else
peraggstate->numFinalArgs = numDirectArgs + 1;
/* resolve actual type of transition state, if polymorphic */
aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid,
aggform->aggtranstype,
@ -1792,7 +1796,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
build_aggregate_fnexprs(inputTypes,
numArguments,
numDirectArgs,
AGGKIND_IS_ORDERED_SET(aggref->aggkind),
peraggstate->numFinalArgs,
aggref->aggvariadic,
aggtranstype,
aggref->aggtype,

View File

@ -116,6 +116,8 @@ typedef struct WindowStatePerAggData
FmgrInfo invtransfn;
FmgrInfo finalfn;
int numFinalArgs; /* number of arguments to pass to finalfn */
/*
* initial value from pg_aggregate entry
*/
@ -557,14 +559,28 @@ finalize_windowaggregate(WindowAggState *winstate,
*/
if (OidIsValid(peraggstate->finalfn_oid))
{
int numFinalArgs = peraggstate->numFinalArgs;
FunctionCallInfoData fcinfo;
bool anynull;
int i;
InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), 1,
InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn),
numFinalArgs,
perfuncstate->winCollation,
(void *) winstate, NULL);
fcinfo.arg[0] = peraggstate->transValue;
fcinfo.argnull[0] = peraggstate->transValueIsNull;
if (fcinfo.flinfo->fn_strict && 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;
anynull = true;
}
if (fcinfo.flinfo->fn_strict && anynull)
{
/* don't call a strict function with NULL inputs */
*result = (Datum) 0;
@ -2089,6 +2105,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
Oid transfn_oid,
invtransfn_oid,
finalfn_oid;
bool finalextra;
Expr *transfnexpr,
*invtransfnexpr,
*finalfnexpr;
@ -2127,6 +2144,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
peraggstate->transfn_oid = transfn_oid = aggform->aggmtransfn;
peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn;
finalextra = aggform->aggmfinalextra;
aggtranstype = aggform->aggmtranstype;
initvalAttNo = Anum_pg_aggregate_aggminitval;
}
@ -2135,6 +2153,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid;
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
finalextra = aggform->aggfinalextra;
aggtranstype = aggform->aggtranstype;
initvalAttNo = Anum_pg_aggregate_agginitval;
}
@ -2185,6 +2204,12 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
}
}
/* Detect how many arguments to pass to the finalfn */
if (finalextra)
peraggstate->numFinalArgs = numArguments + 1;
else
peraggstate->numFinalArgs = 1;
/* resolve actual type of transition state, if polymorphic */
aggtranstype = resolve_aggregate_transtype(wfunc->winfnoid,
aggtranstype,
@ -2195,7 +2220,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
build_aggregate_fnexprs(inputTypes,
numArguments,
0, /* no ordered-set window functions yet */
false,
peraggstate->numFinalArgs,
false, /* no variadic window functions yet */
aggtranstype,
wfunc->wintype,
@ -2207,6 +2232,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
&invtransfnexpr,
&finalfnexpr);
/* set up infrastructure for calling the transfn(s) and finalfn */
fmgr_info(transfn_oid, &peraggstate->transfn);
fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
@ -2222,6 +2248,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
}
/* get info about relevant datatypes */
get_typlenbyval(wfunc->wintype,
&peraggstate->resulttypeLen,
&peraggstate->resulttypeByVal);

View File

@ -1199,7 +1199,7 @@ void
build_aggregate_fnexprs(Oid *agg_input_types,
int agg_num_inputs,
int agg_num_direct_inputs,
bool agg_ordered_set,
int num_finalfn_inputs,
bool agg_variadic,
Oid agg_state_type,
Oid agg_result_type,
@ -1292,19 +1292,17 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->location = -1;
args = list_make1(argp);
if (agg_ordered_set)
/* finalfn may take additional args, which match agg's input types */
for (i = 0; i < num_finalfn_inputs - 1; i++)
{
for (i = 0; i < agg_num_inputs; i++)
{
argp = makeNode(Param);
argp->paramkind = PARAM_EXEC;
argp->paramid = -1;
argp->paramtype = agg_input_types[i];
argp->paramtypmod = -1;
argp->paramcollid = agg_input_collation;
argp->location = -1;
args = lappend(args, argp);
}
argp = makeNode(Param);
argp->paramkind = PARAM_EXEC;
argp->paramid = -1;
argp->paramtype = agg_input_types[i];
argp->paramtypmod = -1;
argp->paramcollid = agg_input_collation;
argp->location = -1;
args = lappend(args, argp);
}
*finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,

View File

@ -11551,6 +11551,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
int i_aggmtransfn;
int i_aggminvtransfn;
int i_aggmfinalfn;
int i_aggfinalextra;
int i_aggmfinalextra;
int i_aggsortop;
int i_hypothetical;
int i_aggtranstype;
@ -11565,6 +11567,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
const char *aggmtransfn;
const char *aggminvtransfn;
const char *aggmfinalfn;
bool aggfinalextra;
bool aggmfinalextra;
const char *aggsortop;
char *aggsortconvop;
bool hypothetical;
@ -11596,11 +11600,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggmtransfn, aggminvtransfn, aggmfinalfn, "
"aggmtranstype::pg_catalog.regtype, "
"aggfinalextra, aggmfinalextra, "
"aggsortop::pg_catalog.regoperator, "
"(aggkind = 'h') as hypothetical, "
"(aggkind = 'h') AS hypothetical, "
"aggtransspace, agginitval, "
"aggmtransspace, aggminitval, "
"'t'::boolean AS convertok, "
"true AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
@ -11614,11 +11619,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"'-' AS aggmtransfn, '-' AS aggminvtransfn, "
"'-' AS aggmfinalfn, 0 AS aggmtranstype, "
"false AS aggfinalextra, false AS aggmfinalextra, "
"aggsortop::pg_catalog.regoperator, "
"false as hypothetical, "
"false AS hypothetical, "
"0 AS aggtransspace, agginitval, "
"0 AS aggmtransspace, NULL AS aggminitval, "
"'t'::boolean AS convertok, "
"true AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
@ -11632,11 +11638,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"'-' AS aggmtransfn, '-' AS aggminvtransfn, "
"'-' AS aggmfinalfn, 0 AS aggmtranstype, "
"false AS aggfinalextra, false AS aggmfinalextra, "
"aggsortop::pg_catalog.regoperator, "
"false as hypothetical, "
"false AS hypothetical, "
"0 AS aggtransspace, agginitval, "
"0 AS aggmtransspace, NULL AS aggminitval, "
"'t'::boolean AS convertok "
"true AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid",
@ -11648,11 +11655,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"'-' AS aggmtransfn, '-' AS aggminvtransfn, "
"'-' AS aggmfinalfn, 0 AS aggmtranstype, "
"false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
"'f'::boolean as hypothetical, "
"false AS hypothetical, "
"0 AS aggtransspace, agginitval, "
"0 AS aggmtransspace, NULL AS aggminitval, "
"'t'::boolean AS convertok "
"true AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid",
@ -11664,11 +11672,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"format_type(aggtranstype, NULL) AS aggtranstype, "
"'-' AS aggmtransfn, '-' AS aggminvtransfn, "
"'-' AS aggmfinalfn, 0 AS aggmtranstype, "
"false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
"'f'::boolean as hypothetical, "
"false AS hypothetical, "
"0 AS aggtransspace, agginitval, "
"0 AS aggmtransspace, NULL AS aggminitval, "
"'t'::boolean AS convertok "
"true AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
agginfo->aggfn.dobj.catId.oid);
@ -11680,8 +11689,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"'-' AS aggmtransfn, '-' AS aggminvtransfn, "
"'-' AS aggmfinalfn, 0 AS aggmtranstype, "
"false AS aggfinalextra, false AS aggmfinalextra, "
"0 AS aggsortop, "
"'f'::boolean as hypothetical, "
"false AS hypothetical, "
"0 AS aggtransspace, agginitval1 AS agginitval, "
"0 AS aggmtransspace, NULL AS aggminitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
@ -11697,6 +11707,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
i_aggmtransfn = PQfnumber(res, "aggmtransfn");
i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
i_aggfinalextra = PQfnumber(res, "aggfinalextra");
i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
i_aggsortop = PQfnumber(res, "aggsortop");
i_hypothetical = PQfnumber(res, "hypothetical");
i_aggtranstype = PQfnumber(res, "aggtranstype");
@ -11712,6 +11724,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
aggsortop = PQgetvalue(res, 0, i_aggsortop);
hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
@ -11791,6 +11805,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
{
appendPQExpBuffer(details, ",\n FINALFUNC = %s",
aggfinalfn);
if (aggfinalextra)
appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
}
if (strcmp(aggmtransfn, "-") != 0)
@ -11817,6 +11833,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
{
appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
aggmfinalfn);
if (aggmfinalextra)
appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
}
aggsortconvop = convertOperatorReference(fout, aggsortop);

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201404161
#define CATALOG_VERSION_NO 201404231
#endif

View File

@ -35,6 +35,8 @@
* aggmtransfn forward function for moving-aggregate mode (0 if none)
* aggminvtransfn inverse function for moving-aggregate mode (0 if none)
* aggmfinalfn final function for moving-aggregate mode (0 if none)
* aggfinalextra true to pass extra dummy arguments to aggfinalfn
* aggmfinalextra true to pass extra dummy arguments to aggmfinalfn
* aggsortop associated sort operator (0 if none)
* aggtranstype type of aggregate's transition (state) data
* aggtransspace estimated size of state data (0 for default estimate)
@ -56,6 +58,8 @@ CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
regproc aggmtransfn;
regproc aggminvtransfn;
regproc aggmfinalfn;
bool aggfinalextra;
bool aggmfinalextra;
Oid aggsortop;
Oid aggtranstype;
int32 aggtransspace;
@ -80,7 +84,7 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
#define Natts_pg_aggregate 15
#define Natts_pg_aggregate 17
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggkind 2
#define Anum_pg_aggregate_aggnumdirectargs 3
@ -89,13 +93,15 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
#define Anum_pg_aggregate_aggmtransfn 6
#define Anum_pg_aggregate_aggminvtransfn 7
#define Anum_pg_aggregate_aggmfinalfn 8
#define Anum_pg_aggregate_aggsortop 9
#define Anum_pg_aggregate_aggtranstype 10
#define Anum_pg_aggregate_aggtransspace 11
#define Anum_pg_aggregate_aggmtranstype 12
#define Anum_pg_aggregate_aggmtransspace 13
#define Anum_pg_aggregate_agginitval 14
#define Anum_pg_aggregate_aggminitval 15
#define Anum_pg_aggregate_aggfinalextra 9
#define Anum_pg_aggregate_aggmfinalextra 10
#define Anum_pg_aggregate_aggsortop 11
#define Anum_pg_aggregate_aggtranstype 12
#define Anum_pg_aggregate_aggtransspace 13
#define Anum_pg_aggregate_aggmtranstype 14
#define Anum_pg_aggregate_aggmtransspace 15
#define Anum_pg_aggregate_agginitval 16
#define Anum_pg_aggregate_aggminitval 17
/*
* Symbolic values for aggkind column. We distinguish normal aggregates
@ -119,177 +125,177 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg 0 1016 0 1016 0 "{0,0}" "{0,0}" ));
DATA(insert ( 2102 n 0 int2_avg_accum int8_avg int2_avg_accum int2_avg_accum_inv int8_avg 0 1016 0 1016 0 "{0,0}" "{0,0}" ));
DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg numeric_avg_accum numeric_accum_inv numeric_avg 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2104 n 0 float4_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2105 n 0 float8_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2106 n 0 interval_accum interval_avg interval_accum interval_accum_inv interval_avg 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 0 1016 0 1016 0 "{0,0}" "{0,0}" ));
DATA(insert ( 2102 n 0 int2_avg_accum int8_avg int2_avg_accum int2_avg_accum_inv int8_avg f f 0 1016 0 1016 0 "{0,0}" "{0,0}" ));
DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg numeric_avg_accum numeric_accum_inv numeric_avg f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2106 n 0 interval_accum interval_avg interval_accum interval_accum_inv interval_avg f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2110 n 0 float4pl - - - - 0 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2111 n 0 float8pl - - - - 0 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - 0 790 0 790 0 _null_ _null_ ));
DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - 0 1186 0 1186 0 _null_ _null_ ));
DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum numeric_avg_accum numeric_accum_inv numeric_sum 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 0 1186 0 1186 0 _null_ _null_ ));
DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum numeric_avg_accum numeric_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - 413 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2116 n 0 int4larger - - - - 521 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2117 n 0 int2larger - - - - 520 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2118 n 0 oidlarger - - - - 610 26 0 0 0 _null_ _null_ ));
DATA(insert ( 2119 n 0 float4larger - - - - 623 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2120 n 0 float8larger - - - - 674 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2121 n 0 int4larger - - - - 563 702 0 0 0 _null_ _null_ ));
DATA(insert ( 2122 n 0 date_larger - - - - 1097 1082 0 0 0 _null_ _null_ ));
DATA(insert ( 2123 n 0 time_larger - - - - 1112 1083 0 0 0 _null_ _null_ ));
DATA(insert ( 2124 n 0 timetz_larger - - - - 1554 1266 0 0 0 _null_ _null_ ));
DATA(insert ( 2125 n 0 cashlarger - - - - 903 790 0 0 0 _null_ _null_ ));
DATA(insert ( 2126 n 0 timestamp_larger - - - - 2064 1114 0 0 0 _null_ _null_ ));
DATA(insert ( 2127 n 0 timestamptz_larger - - - - 1324 1184 0 0 0 _null_ _null_ ));
DATA(insert ( 2128 n 0 interval_larger - - - - 1334 1186 0 0 0 _null_ _null_ ));
DATA(insert ( 2129 n 0 text_larger - - - - 666 25 0 0 0 _null_ _null_ ));
DATA(insert ( 2130 n 0 numeric_larger - - - - 1756 1700 0 0 0 _null_ _null_ ));
DATA(insert ( 2050 n 0 array_larger - - - - 1073 2277 0 0 0 _null_ _null_ ));
DATA(insert ( 2244 n 0 bpchar_larger - - - - 1060 1042 0 0 0 _null_ _null_ ));
DATA(insert ( 2797 n 0 tidlarger - - - - 2800 27 0 0 0 _null_ _null_ ));
DATA(insert ( 3526 n 0 enum_larger - - - - 3519 3500 0 0 0 _null_ _null_ ));
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2116 n 0 int4larger - - - - f f 521 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2117 n 0 int2larger - - - - f f 520 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2118 n 0 oidlarger - - - - f f 610 26 0 0 0 _null_ _null_ ));
DATA(insert ( 2119 n 0 float4larger - - - - f f 623 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2120 n 0 float8larger - - - - f f 674 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2121 n 0 int4larger - - - - f f 563 702 0 0 0 _null_ _null_ ));
DATA(insert ( 2122 n 0 date_larger - - - - f f 1097 1082 0 0 0 _null_ _null_ ));
DATA(insert ( 2123 n 0 time_larger - - - - f f 1112 1083 0 0 0 _null_ _null_ ));
DATA(insert ( 2124 n 0 timetz_larger - - - - f f 1554 1266 0 0 0 _null_ _null_ ));
DATA(insert ( 2125 n 0 cashlarger - - - - f f 903 790 0 0 0 _null_ _null_ ));
DATA(insert ( 2126 n 0 timestamp_larger - - - - f f 2064 1114 0 0 0 _null_ _null_ ));
DATA(insert ( 2127 n 0 timestamptz_larger - - - - f f 1324 1184 0 0 0 _null_ _null_ ));
DATA(insert ( 2128 n 0 interval_larger - - - - f f 1334 1186 0 0 0 _null_ _null_ ));
DATA(insert ( 2129 n 0 text_larger - - - - f f 666 25 0 0 0 _null_ _null_ ));
DATA(insert ( 2130 n 0 numeric_larger - - - - f f 1756 1700 0 0 0 _null_ _null_ ));
DATA(insert ( 2050 n 0 array_larger - - - - f f 1073 2277 0 0 0 _null_ _null_ ));
DATA(insert ( 2244 n 0 bpchar_larger - - - - f f 1060 1042 0 0 0 _null_ _null_ ));
DATA(insert ( 2797 n 0 tidlarger - - - - f f 2800 27 0 0 0 _null_ _null_ ));
DATA(insert ( 3526 n 0 enum_larger - - - - f f 3519 3500 0 0 0 _null_ _null_ ));
/* min */
DATA(insert ( 2131 n 0 int8smaller - - - - 412 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2132 n 0 int4smaller - - - - 97 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2133 n 0 int2smaller - - - - 95 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2134 n 0 oidsmaller - - - - 609 26 0 0 0 _null_ _null_ ));
DATA(insert ( 2135 n 0 float4smaller - - - - 622 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2136 n 0 float8smaller - - - - 672 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2137 n 0 int4smaller - - - - 562 702 0 0 0 _null_ _null_ ));
DATA(insert ( 2138 n 0 date_smaller - - - - 1095 1082 0 0 0 _null_ _null_ ));
DATA(insert ( 2139 n 0 time_smaller - - - - 1110 1083 0 0 0 _null_ _null_ ));
DATA(insert ( 2140 n 0 timetz_smaller - - - - 1552 1266 0 0 0 _null_ _null_ ));
DATA(insert ( 2141 n 0 cashsmaller - - - - 902 790 0 0 0 _null_ _null_ ));
DATA(insert ( 2142 n 0 timestamp_smaller - - - - 2062 1114 0 0 0 _null_ _null_ ));
DATA(insert ( 2143 n 0 timestamptz_smaller - - - - 1322 1184 0 0 0 _null_ _null_ ));
DATA(insert ( 2144 n 0 interval_smaller - - - - 1332 1186 0 0 0 _null_ _null_ ));
DATA(insert ( 2145 n 0 text_smaller - - - - 664 25 0 0 0 _null_ _null_ ));
DATA(insert ( 2146 n 0 numeric_smaller - - - - 1754 1700 0 0 0 _null_ _null_ ));
DATA(insert ( 2051 n 0 array_smaller - - - - 1072 2277 0 0 0 _null_ _null_ ));
DATA(insert ( 2245 n 0 bpchar_smaller - - - - 1058 1042 0 0 0 _null_ _null_ ));
DATA(insert ( 2798 n 0 tidsmaller - - - - 2799 27 0 0 0 _null_ _null_ ));
DATA(insert ( 3527 n 0 enum_smaller - - - - 3518 3500 0 0 0 _null_ _null_ ));
DATA(insert ( 2131 n 0 int8smaller - - - - f f 412 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2132 n 0 int4smaller - - - - f f 97 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2133 n 0 int2smaller - - - - f f 95 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2134 n 0 oidsmaller - - - - f f 609 26 0 0 0 _null_ _null_ ));
DATA(insert ( 2135 n 0 float4smaller - - - - f f 622 700 0 0 0 _null_ _null_ ));
DATA(insert ( 2136 n 0 float8smaller - - - - f f 672 701 0 0 0 _null_ _null_ ));
DATA(insert ( 2137 n 0 int4smaller - - - - f f 562 702 0 0 0 _null_ _null_ ));
DATA(insert ( 2138 n 0 date_smaller - - - - f f 1095 1082 0 0 0 _null_ _null_ ));
DATA(insert ( 2139 n 0 time_smaller - - - - f f 1110 1083 0 0 0 _null_ _null_ ));
DATA(insert ( 2140 n 0 timetz_smaller - - - - f f 1552 1266 0 0 0 _null_ _null_ ));
DATA(insert ( 2141 n 0 cashsmaller - - - - f f 902 790 0 0 0 _null_ _null_ ));
DATA(insert ( 2142 n 0 timestamp_smaller - - - - f f 2062 1114 0 0 0 _null_ _null_ ));
DATA(insert ( 2143 n 0 timestamptz_smaller - - - - f f 1322 1184 0 0 0 _null_ _null_ ));
DATA(insert ( 2144 n 0 interval_smaller - - - - f f 1332 1186 0 0 0 _null_ _null_ ));
DATA(insert ( 2145 n 0 text_smaller - - - - f f 664 25 0 0 0 _null_ _null_ ));
DATA(insert ( 2146 n 0 numeric_smaller - - - - f f 1754 1700 0 0 0 _null_ _null_ ));
DATA(insert ( 2051 n 0 array_smaller - - - - f f 1072 2277 0 0 0 _null_ _null_ ));
DATA(insert ( 2245 n 0 bpchar_smaller - - - - f f 1058 1042 0 0 0 _null_ _null_ ));
DATA(insert ( 2798 n 0 tidsmaller - - - - f f 2799 27 0 0 0 _null_ _null_ ));
DATA(insert ( 3527 n 0 enum_smaller - - - - f f 3518 3500 0 0 0 _null_ _null_ ));
/* count */
DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - 0 20 0 20 0 "0" "0" ));
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - 0 20 0 20 0 "0" "0" ));
DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 20 0 20 0 "0" "0" ));
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2719 n 0 int4_accum numeric_var_pop int4_accum int4_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2720 n 0 int2_accum numeric_var_pop int2_accum int2_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop numeric_accum numeric_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2719 n 0 int4_accum numeric_var_pop int4_accum int4_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2720 n 0 int2_accum numeric_var_pop int2_accum int2_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop numeric_accum numeric_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2642 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2643 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2642 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2643 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2149 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2150 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2149 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2150 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2725 n 0 int4_accum numeric_stddev_pop int4_accum int4_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2726 n 0 int2_accum numeric_stddev_pop int2_accum int2_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop numeric_accum numeric_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2725 n 0 int4_accum numeric_stddev_pop int4_accum int4_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2726 n 0 int2_accum numeric_stddev_pop int2_accum int2_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop numeric_accum numeric_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2713 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2714 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2713 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2714 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2155 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2156 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2155 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2156 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - 0 20 0 0 0 "0" _null_ ));
DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - f f 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ));
/* boolean-and and boolean-or */
DATA(insert ( 2517 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue 58 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2518 n 0 boolor_statefunc - bool_accum bool_accum_inv bool_anytrue 59 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2519 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue 58 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2517 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue f f 58 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2518 n 0 boolor_statefunc - bool_accum bool_accum_inv bool_anytrue f f 59 16 0 2281 16 _null_ _null_ ));
DATA(insert ( 2519 n 0 booland_statefunc - bool_accum bool_accum_inv bool_alltrue f f 58 16 0 2281 16 _null_ _null_ ));
/* bitwise integer */
DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2237 n 0 int2or - - - - 0 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2238 n 0 int4and - - - - 0 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2239 n 0 int4or - - - - 0 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2240 n 0 int8and - - - - 0 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2241 n 0 int8or - - - - 0 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2242 n 0 bitand - - - - 0 1560 0 0 0 _null_ _null_ ));
DATA(insert ( 2243 n 0 bitor - - - - 0 1560 0 0 0 _null_ _null_ ));
DATA(insert ( 2236 n 0 int2and - - - - f f 0 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2237 n 0 int2or - - - - f f 0 21 0 0 0 _null_ _null_ ));
DATA(insert ( 2238 n 0 int4and - - - - f f 0 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2239 n 0 int4or - - - - f f 0 23 0 0 0 _null_ _null_ ));
DATA(insert ( 2240 n 0 int8and - - - - f f 0 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2241 n 0 int8or - - - - f f 0 20 0 0 0 _null_ _null_ ));
DATA(insert ( 2242 n 0 bitand - - - - f f 0 1560 0 0 0 _null_ _null_ ));
DATA(insert ( 2243 n 0 bitor - - - - f f 0 1560 0 0 0 _null_ _null_ ));
/* xml */
DATA(insert ( 2901 n 0 xmlconcat2 - - - - 0 142 0 0 0 _null_ _null_ ));
DATA(insert ( 2901 n 0 xmlconcat2 - - - - f f 0 142 0 0 0 _null_ _null_ ));
/* array */
DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - t f 0 2281 0 0 0 _null_ _null_ ));
/* text */
DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - f f 0 2281 0 0 0 _null_ _null_ ));
/* bytea */
DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - f f 0 2281 0 0 0 _null_ _null_ ));
/* json */
DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - f f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - f f 0 2281 0 0 0 _null_ _null_ ));
/* ordered-set and hypothetical-set aggregates */
DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - f f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - f f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - f f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - f f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - t f 0 2281 0 0 0 _null_ _null_ ));
/*
@ -311,6 +317,8 @@ extern Oid AggregateCreate(const char *aggName,
List *aggmtransfnName,
List *aggminvtransfnName,
List *aggmfinalfnName,
bool finalfnExtraArgs,
bool mfinalfnExtraArgs,
List *aggsortopName,
Oid aggTransType,
int32 aggTransSpace,

View File

@ -879,7 +879,7 @@ DATA(insert OID = 3168 ( array_replace PGNSP PGUID 12 1 0 0 0 f f f f f f i
DESCR("replace any occurrences of an element in an array");
DATA(insert OID = 2333 ( array_agg_transfn PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 2283" _null_ _null_ _null_ _null_ array_agg_transfn _null_ _null_ _null_ ));
DESCR("aggregate transition function");
DATA(insert OID = 2334 ( array_agg_finalfn PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2277 "2281" _null_ _null_ _null_ _null_ array_agg_finalfn _null_ _null_ _null_ ));
DATA(insert OID = 2334 ( array_agg_finalfn PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2277 "2281 2283" _null_ _null_ _null_ _null_ array_agg_finalfn _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 2335 ( array_agg PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 2277 "2283" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("concatenate aggregate input into an array");
@ -4990,11 +4990,11 @@ DATA(insert OID = 3973 ( percentile_disc_final PGNSP PGUID 12 1 0 0 0 f f f f f
DESCR("aggregate final function");
DATA(insert OID = 3974 ( percentile_cont PGNSP PGUID 12 1 0 0 0 t f f f f f i 2 0 701 "701 701" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("continuous distribution percentile");
DATA(insert OID = 3975 ( percentile_cont_float8_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 3 0 701 "2281 701 701" _null_ _null_ _null_ _null_ percentile_cont_float8_final _null_ _null_ _null_ ));
DATA(insert OID = 3975 ( percentile_cont_float8_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 701 "2281 701" _null_ _null_ _null_ _null_ percentile_cont_float8_final _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 3976 ( percentile_cont PGNSP PGUID 12 1 0 0 0 t f f f f f i 2 0 1186 "701 1186" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("continuous distribution percentile");
DATA(insert OID = 3977 ( percentile_cont_interval_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 3 0 1186 "2281 701 1186" _null_ _null_ _null_ _null_ percentile_cont_interval_final _null_ _null_ _null_ ));
DATA(insert OID = 3977 ( percentile_cont_interval_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1186 "2281 701" _null_ _null_ _null_ _null_ percentile_cont_interval_final _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 3978 ( percentile_disc PGNSP PGUID 12 1 0 0 0 t f f f f f i 2 0 2277 "1022 2283" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("multiple discrete percentiles");
@ -5002,11 +5002,11 @@ DATA(insert OID = 3979 ( percentile_disc_multi_final PGNSP PGUID 12 1 0 0 0 f f
DESCR("aggregate final function");
DATA(insert OID = 3980 ( percentile_cont PGNSP PGUID 12 1 0 0 0 t f f f f f i 2 0 1022 "1022 701" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("multiple continuous percentiles");
DATA(insert OID = 3981 ( percentile_cont_float8_multi_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 3 0 1022 "2281 1022 701" _null_ _null_ _null_ _null_ percentile_cont_float8_multi_final _null_ _null_ _null_ ));
DATA(insert OID = 3981 ( percentile_cont_float8_multi_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1022 "2281 1022" _null_ _null_ _null_ _null_ percentile_cont_float8_multi_final _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 3982 ( percentile_cont PGNSP PGUID 12 1 0 0 0 t f f f f f i 2 0 1187 "1022 1186" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("multiple continuous percentiles");
DATA(insert OID = 3983 ( percentile_cont_interval_multi_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 3 0 1187 "2281 1022 1186" _null_ _null_ _null_ _null_ percentile_cont_interval_multi_final _null_ _null_ _null_ ));
DATA(insert OID = 3983 ( percentile_cont_interval_multi_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1187 "2281 1022" _null_ _null_ _null_ _null_ percentile_cont_interval_multi_final _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 3984 ( mode PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 2283 "2283" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("most common value");

View File

@ -33,7 +33,7 @@ extern Oid resolve_aggregate_transtype(Oid aggfuncid,
extern void build_aggregate_fnexprs(Oid *agg_input_types,
int agg_num_inputs,
int agg_num_direct_inputs,
bool agg_ordered_set,
int num_finalfn_inputs,
bool agg_variadic,
Oid agg_state_type,
Oid agg_result_type,

View File

@ -70,12 +70,14 @@ create aggregate least_agg(variadic items anyarray) (
create aggregate my_percentile_disc(float8 ORDER BY anyelement) (
stype = internal,
sfunc = ordered_set_transition,
finalfunc = percentile_disc_final
finalfunc = percentile_disc_final,
finalfunc_extra = true
);
create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") (
stype = internal,
sfunc = ordered_set_transition_multi,
finalfunc = rank_final,
finalfunc_extra = true,
hypothetical
);
alter aggregate my_percentile_disc(float8 ORDER BY anyelement)

View File

@ -283,6 +283,38 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
2304 | internal_in
(1 row)
-- Look for functions that return a polymorphic type and do not have any
-- polymorphic argument. Calls of such functions would be unresolvable
-- at parse time. As of 9.4 this query should find only some input functions
-- associated with these pseudotypes.
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE p1.prorettype IN
('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype,
'anyenum'::regtype, 'anyrange'::regtype)
AND NOT
('anyelement'::regtype = ANY (p1.proargtypes) OR
'anyarray'::regtype = ANY (p1.proargtypes) OR
'anynonarray'::regtype = ANY (p1.proargtypes) OR
'anyenum'::regtype = ANY (p1.proargtypes) OR
'anyrange'::regtype = ANY (p1.proargtypes))
ORDER BY 2;
oid | proname
------+----------------
2296 | anyarray_in
2502 | anyarray_recv
2312 | anyelement_in
3504 | anyenum_in
2777 | anynonarray_in
3832 | anyrange_in
750 | array_in
2400 | array_recv
3506 | enum_in
3532 | enum_recv
3834 | range_in
3836 | range_recv
(12 rows)
-- Check for length inconsistencies between the various argument-info arrays.
SELECT p1.oid, p1.proname
FROM pg_proc as p1
@ -800,16 +832,16 @@ WHERE a.aggfnoid = p.oid AND
(pfn.proretset OR
NOT binary_coercible(pfn.prorettype, p.prorettype) OR
NOT binary_coercible(a.aggtranstype, pfn.proargtypes[0]) OR
CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1
ELSE pfn.pronargs != p.pronargs + 1
OR (p.pronargs > 0 AND
CASE WHEN a.aggfinalextra THEN pfn.pronargs != p.pronargs + 1
ELSE pfn.pronargs != a.aggnumdirectargs + 1 END
OR (pfn.pronargs > 1 AND
NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1]))
OR (p.pronargs > 1 AND
OR (pfn.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2]))
OR (p.pronargs > 2 AND
OR (pfn.pronargs > 3 AND
NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3]))
-- we could carry the check further, but 3 args is enough for now
END);
-- we could carry the check further, but 3 args is enough for now
);
aggfnoid | proname | oid | proname
----------+---------+-----+---------
(0 rows)
@ -909,16 +941,16 @@ WHERE a.aggfnoid = p.oid AND
(pfn.proretset OR
NOT binary_coercible(pfn.prorettype, p.prorettype) OR
NOT binary_coercible(a.aggmtranstype, pfn.proargtypes[0]) OR
CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1
ELSE pfn.pronargs != p.pronargs + 1
OR (p.pronargs > 0 AND
CASE WHEN a.aggmfinalextra THEN pfn.pronargs != p.pronargs + 1
ELSE pfn.pronargs != a.aggnumdirectargs + 1 END
OR (pfn.pronargs > 1 AND
NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1]))
OR (p.pronargs > 1 AND
OR (pfn.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2]))
OR (p.pronargs > 2 AND
OR (pfn.pronargs > 3 AND
NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3]))
-- we could carry the check further, but 3 args is enough for now
END);
-- we could carry the check further, but 3 args is enough for now
);
aggfnoid | proname | oid | proname
----------+---------+-----+---------
(0 rows)

View File

@ -85,13 +85,15 @@ create aggregate least_agg(variadic items anyarray) (
create aggregate my_percentile_disc(float8 ORDER BY anyelement) (
stype = internal,
sfunc = ordered_set_transition,
finalfunc = percentile_disc_final
finalfunc = percentile_disc_final,
finalfunc_extra = true
);
create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") (
stype = internal,
sfunc = ordered_set_transition_multi,
finalfunc = rank_final,
finalfunc_extra = true,
hypothetical
);

View File

@ -226,6 +226,24 @@ FROM pg_proc as p1
WHERE p1.prorettype = 'internal'::regtype AND NOT
'internal'::regtype = ANY (p1.proargtypes);
-- Look for functions that return a polymorphic type and do not have any
-- polymorphic argument. Calls of such functions would be unresolvable
-- at parse time. As of 9.4 this query should find only some input functions
-- associated with these pseudotypes.
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE p1.prorettype IN
('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype,
'anyenum'::regtype, 'anyrange'::regtype)
AND NOT
('anyelement'::regtype = ANY (p1.proargtypes) OR
'anyarray'::regtype = ANY (p1.proargtypes) OR
'anynonarray'::regtype = ANY (p1.proargtypes) OR
'anyenum'::regtype = ANY (p1.proargtypes) OR
'anyrange'::regtype = ANY (p1.proargtypes))
ORDER BY 2;
-- Check for length inconsistencies between the various argument-info arrays.
SELECT p1.oid, p1.proname
@ -646,16 +664,16 @@ WHERE a.aggfnoid = p.oid AND
(pfn.proretset OR
NOT binary_coercible(pfn.prorettype, p.prorettype) OR
NOT binary_coercible(a.aggtranstype, pfn.proargtypes[0]) OR
CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1
ELSE pfn.pronargs != p.pronargs + 1
OR (p.pronargs > 0 AND
CASE WHEN a.aggfinalextra THEN pfn.pronargs != p.pronargs + 1
ELSE pfn.pronargs != a.aggnumdirectargs + 1 END
OR (pfn.pronargs > 1 AND
NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1]))
OR (p.pronargs > 1 AND
OR (pfn.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2]))
OR (p.pronargs > 2 AND
OR (pfn.pronargs > 3 AND
NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3]))
-- we could carry the check further, but 3 args is enough for now
END);
-- we could carry the check further, but 3 args is enough for now
);
-- If transfn is strict then either initval should be non-NULL, or
-- input type should match transtype so that the first non-null input
@ -738,16 +756,16 @@ WHERE a.aggfnoid = p.oid AND
(pfn.proretset OR
NOT binary_coercible(pfn.prorettype, p.prorettype) OR
NOT binary_coercible(a.aggmtranstype, pfn.proargtypes[0]) OR
CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1
ELSE pfn.pronargs != p.pronargs + 1
OR (p.pronargs > 0 AND
CASE WHEN a.aggmfinalextra THEN pfn.pronargs != p.pronargs + 1
ELSE pfn.pronargs != a.aggnumdirectargs + 1 END
OR (pfn.pronargs > 1 AND
NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1]))
OR (p.pronargs > 1 AND
OR (pfn.pronargs > 2 AND
NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2]))
OR (p.pronargs > 2 AND
OR (pfn.pronargs > 3 AND
NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3]))
-- we could carry the check further, but 3 args is enough for now
END);
-- we could carry the check further, but 3 args is enough for now
);
-- If mtransfn is strict then either minitval should be non-NULL, or
-- input type should match mtranstype so that the first non-null input