Allow aggregates to provide estimates of their transition state data size.

Formerly the planner had a hard-wired rule of thumb for guessing the amount
of space consumed by an aggregate function's transition state data.  This
estimate is critical to deciding whether it's OK to use hash aggregation,
and in many situations the built-in estimate isn't very good.  This patch
adds a column to pg_aggregate wherein a per-aggregate estimate can be
provided, overriding the planner's default, and infrastructure for setting
the column via CREATE AGGREGATE.

It may be that additional smarts will be required in future, perhaps even
a per-aggregate estimation function.  But this is already a step forward.

This is extracted from a larger patch to improve the performance of numeric
and int8 aggregates.  I (tgl) thought it was worth reviewing and committing
this infrastructure separately.  In this commit, all built-in aggregates
are given aggtransspace = 0, so no behavior should change.

Hadi Moshayedi, reviewed by Pavel Stehule and Tomas Vondra
This commit is contained in:
Tom Lane 2013-11-16 16:03:40 -05:00
parent 55c3d86a2a
commit 6cb86143e8
14 changed files with 245 additions and 147 deletions

View File

@ -372,6 +372,13 @@
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Data type of the aggregate function's internal transition (state) data</entry>
</row>
<row>
<entry><structfield>aggtransspace</structfield></entry>
<entry><type>int4</type></entry>
<entry></entry>
<entry>Approximate average size (in bytes) of the transition state
data, or zero to use a default estimate</entry>
</row>
<row>
<entry><structfield>agginitval</structfield></entry>
<entry><type>text</type></entry>

View File

@ -24,6 +24,7 @@ PostgreSQL documentation
CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
@ -35,6 +36,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
@ -264,6 +266,22 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">state_data_size</replaceable></term>
<listitem>
<para>
The approximate average size (in bytes) of the aggregate's state value.
If this parameter is omitted or is zero, a default estimate is used
based on the <replaceable>state_data_type</>.
The planner uses this value to estimate the memory required for a
grouped aggregate query. The planner will consider using hash
aggregation for such a query only if the hash table is estimated to fit
in <xref linkend="guc-work-mem">; therefore, large values of this
parameter discourage use of hash aggregation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
<listitem>

View File

@ -55,6 +55,7 @@ AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
@ -273,6 +274,7 @@ AggregateCreate(const char *aggName,
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
if (agginitval)
values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
else

View File

@ -60,6 +60,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
List *sortoperatorName = NIL;
TypeName *baseType = NULL;
TypeName *transType = NULL;
int32 transSpace = 0;
char *initval = NULL;
int numArgs;
oidvector *parameterTypes;
@ -102,6 +103,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "sspace") == 0)
transSpace = defGetInt32(defel);
else if (pg_strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
@ -248,5 +251,6 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
transSpace, /* transition space */
initval); /* initial condition */
}

View File

@ -164,6 +164,30 @@ defGetBoolean(DefElem *def)
return false; /* keep compiler quiet */
}
/*
* Extract an int32 value from a DefElem.
*/
int32
defGetInt32(DefElem *def)
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires an integer value",
def->defname)));
switch (nodeTag(def->arg))
{
case T_Integer:
return (int32) intVal(def->arg);
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires an integer value",
def->defname)));
}
return 0; /* keep compiler quiet */
}
/*
* Extract an int64 value from a DefElem.
*/

View File

@ -461,6 +461,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
@ -478,6 +479,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
@ -541,22 +543,30 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
*/
if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
/*
* If transition state is of same type as first input, assume it's
* the same typmod (same width) as well. This works for cases
* like MAX/MIN and is probably somewhat reasonable otherwise.
*/
if (numArguments > 0 && aggtranstype == inputTypes[0])
aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
/* Use average width if aggregate definition gave one */
if (aggtransspace > 0)
avgwidth = aggtransspace;
else
aggtranstypmod = -1;
{
/*
* If transition state is of same type as first input, assume
* it's the same typmod (same width) as well. This works for
* cases like MAX/MIN and is probably somewhat reasonable
* otherwise.
*/
int32 aggtranstypmod;
if (numArguments > 0 && aggtranstype == inputTypes[0])
aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
else
aggtranstypmod = -1;
avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);
}
avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);
avgwidth = MAXALIGN(avgwidth);
costs->transitionSpace += avgwidth + 2 * sizeof(void *);
}
else if (aggtranstype == INTERNALOID)
@ -564,12 +574,16 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
/*
* INTERNAL transition type is a special case: although INTERNAL
* is pass-by-value, it's almost certainly being used as a pointer
* to some large data structure. We assume usage of
* to some large data structure. The aggregate definition can
* provide an estimate of the size. If it doesn't, then we assume
* ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
* being kept in a private memory context, as is done by
* array_agg() for instance.
*/
costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
if (aggtransspace > 0)
costs->transitionSpace += aggtransspace;
else
costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
}
/*

View File

@ -11521,12 +11521,14 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
int i_aggfinalfn;
int i_aggsortop;
int i_aggtranstype;
int i_aggtransspace;
int i_agginitval;
int i_convertok;
const char *aggtransfn;
const char *aggfinalfn;
const char *aggsortop;
const char *aggtranstype;
const char *aggtransspace;
const char *agginitval;
bool convertok;
@ -11544,12 +11546,26 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
if (fout->remoteVersion >= 80400)
if (fout->remoteVersion >= 90400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
"agginitval, "
"aggtransspace, agginitval, "
"'t'::boolean 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 "
"WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid",
agginfo->aggfn.dobj.catId.oid);
}
else if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
"0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
@ -11563,7 +11579,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
"agginitval, "
"0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@ -11575,7 +11591,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
"agginitval, "
"0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@ -11587,7 +11603,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
"agginitval, "
"0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@ -11599,7 +11615,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
"agginitval1 AS agginitval, "
"0 AS aggtransspace, agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@ -11612,6 +11628,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
i_aggsortop = PQfnumber(res, "aggsortop");
i_aggtranstype = PQfnumber(res, "aggtranstype");
i_aggtransspace = PQfnumber(res, "aggtransspace");
i_agginitval = PQfnumber(res, "agginitval");
i_convertok = PQfnumber(res, "convertok");
@ -11619,6 +11636,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
aggsortop = PQgetvalue(res, 0, i_aggsortop);
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
agginitval = PQgetvalue(res, 0, i_agginitval);
convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
@ -11672,6 +11690,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
fmtId(aggtranstype));
}
if (strcmp(aggtransspace, "0") != 0)
{
appendPQExpBuffer(details, ",\n SSPACE = %s",
aggtransspace);
}
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201311081
#define CATALOG_VERSION_NO 201311161
#endif

View File

@ -32,6 +32,7 @@
* aggfinalfn final function (0 if none)
* 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)
* agginitval initial value for transition state (can be NULL)
* ----------------------------------------------------------------
*/
@ -44,6 +45,7 @@ CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
regproc aggfinalfn;
Oid aggsortop;
Oid aggtranstype;
int32 aggtransspace;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text agginitval;
@ -62,13 +64,14 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
#define Natts_pg_aggregate 6
#define Natts_pg_aggregate 7
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggtransfn 2
#define Anum_pg_aggregate_aggfinalfn 3
#define Anum_pg_aggregate_aggsortop 4
#define Anum_pg_aggregate_aggtranstype 5
#define Anum_pg_aggregate_agginitval 6
#define Anum_pg_aggregate_aggtransspace 6
#define Anum_pg_aggregate_agginitval 7
/* ----------------
@ -77,163 +80,163 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 "{0,0}" ));
DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 "{0,0}" ));
DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 1231 "{0,0}" ));
DATA(insert ( 2104 float4_accum float8_avg 0 1022 "{0,0,0}" ));
DATA(insert ( 2105 float8_accum float8_avg 0 1022 "{0,0,0}" ));
DATA(insert ( 2106 interval_accum interval_avg 0 1187 "{0 second,0 second}" ));
DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 0 "{0,0}" ));
DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 0 "{0,0}" ));
DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 0 "{0,0}" ));
DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 1231 0 "{0,0}" ));
DATA(insert ( 2104 float4_accum float8_avg 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2105 float8_accum float8_avg 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2106 interval_accum interval_avg 0 1187 0 "{0 second,0 second}" ));
/* sum */
DATA(insert ( 2107 int8_sum - 0 1700 _null_ ));
DATA(insert ( 2108 int4_sum - 0 20 _null_ ));
DATA(insert ( 2109 int2_sum - 0 20 _null_ ));
DATA(insert ( 2110 float4pl - 0 700 _null_ ));
DATA(insert ( 2111 float8pl - 0 701 _null_ ));
DATA(insert ( 2112 cash_pl - 0 790 _null_ ));
DATA(insert ( 2113 interval_pl - 0 1186 _null_ ));
DATA(insert ( 2114 numeric_add - 0 1700 _null_ ));
DATA(insert ( 2107 int8_sum - 0 1700 0 _null_ ));
DATA(insert ( 2108 int4_sum - 0 20 0 _null_ ));
DATA(insert ( 2109 int2_sum - 0 20 0 _null_ ));
DATA(insert ( 2110 float4pl - 0 700 0 _null_ ));
DATA(insert ( 2111 float8pl - 0 701 0 _null_ ));
DATA(insert ( 2112 cash_pl - 0 790 0 _null_ ));
DATA(insert ( 2113 interval_pl - 0 1186 0 _null_ ));
DATA(insert ( 2114 numeric_add - 0 1700 0 _null_ ));
/* max */
DATA(insert ( 2115 int8larger - 413 20 _null_ ));
DATA(insert ( 2116 int4larger - 521 23 _null_ ));
DATA(insert ( 2117 int2larger - 520 21 _null_ ));
DATA(insert ( 2118 oidlarger - 610 26 _null_ ));
DATA(insert ( 2119 float4larger - 623 700 _null_ ));
DATA(insert ( 2120 float8larger - 674 701 _null_ ));
DATA(insert ( 2121 int4larger - 563 702 _null_ ));
DATA(insert ( 2122 date_larger - 1097 1082 _null_ ));
DATA(insert ( 2123 time_larger - 1112 1083 _null_ ));
DATA(insert ( 2124 timetz_larger - 1554 1266 _null_ ));
DATA(insert ( 2125 cashlarger - 903 790 _null_ ));
DATA(insert ( 2126 timestamp_larger - 2064 1114 _null_ ));
DATA(insert ( 2127 timestamptz_larger - 1324 1184 _null_ ));
DATA(insert ( 2128 interval_larger - 1334 1186 _null_ ));
DATA(insert ( 2129 text_larger - 666 25 _null_ ));
DATA(insert ( 2130 numeric_larger - 1756 1700 _null_ ));
DATA(insert ( 2050 array_larger - 1073 2277 _null_ ));
DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ ));
DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
DATA(insert ( 3526 enum_larger - 3519 3500 _null_ ));
DATA(insert ( 2115 int8larger - 413 20 0 _null_ ));
DATA(insert ( 2116 int4larger - 521 23 0 _null_ ));
DATA(insert ( 2117 int2larger - 520 21 0 _null_ ));
DATA(insert ( 2118 oidlarger - 610 26 0 _null_ ));
DATA(insert ( 2119 float4larger - 623 700 0 _null_ ));
DATA(insert ( 2120 float8larger - 674 701 0 _null_ ));
DATA(insert ( 2121 int4larger - 563 702 0 _null_ ));
DATA(insert ( 2122 date_larger - 1097 1082 0 _null_ ));
DATA(insert ( 2123 time_larger - 1112 1083 0 _null_ ));
DATA(insert ( 2124 timetz_larger - 1554 1266 0 _null_ ));
DATA(insert ( 2125 cashlarger - 903 790 0 _null_ ));
DATA(insert ( 2126 timestamp_larger - 2064 1114 0 _null_ ));
DATA(insert ( 2127 timestamptz_larger - 1324 1184 0 _null_ ));
DATA(insert ( 2128 interval_larger - 1334 1186 0 _null_ ));
DATA(insert ( 2129 text_larger - 666 25 0 _null_ ));
DATA(insert ( 2130 numeric_larger - 1756 1700 0 _null_ ));
DATA(insert ( 2050 array_larger - 1073 2277 0 _null_ ));
DATA(insert ( 2244 bpchar_larger - 1060 1042 0 _null_ ));
DATA(insert ( 2797 tidlarger - 2800 27 0 _null_ ));
DATA(insert ( 3526 enum_larger - 3519 3500 0 _null_ ));
/* min */
DATA(insert ( 2131 int8smaller - 412 20 _null_ ));
DATA(insert ( 2132 int4smaller - 97 23 _null_ ));
DATA(insert ( 2133 int2smaller - 95 21 _null_ ));
DATA(insert ( 2134 oidsmaller - 609 26 _null_ ));
DATA(insert ( 2135 float4smaller - 622 700 _null_ ));
DATA(insert ( 2136 float8smaller - 672 701 _null_ ));
DATA(insert ( 2137 int4smaller - 562 702 _null_ ));
DATA(insert ( 2138 date_smaller - 1095 1082 _null_ ));
DATA(insert ( 2139 time_smaller - 1110 1083 _null_ ));
DATA(insert ( 2140 timetz_smaller - 1552 1266 _null_ ));
DATA(insert ( 2141 cashsmaller - 902 790 _null_ ));
DATA(insert ( 2142 timestamp_smaller - 2062 1114 _null_ ));
DATA(insert ( 2143 timestamptz_smaller - 1322 1184 _null_ ));
DATA(insert ( 2144 interval_smaller - 1332 1186 _null_ ));
DATA(insert ( 2145 text_smaller - 664 25 _null_ ));
DATA(insert ( 2146 numeric_smaller - 1754 1700 _null_ ));
DATA(insert ( 2051 array_smaller - 1072 2277 _null_ ));
DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ ));
DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ ));
DATA(insert ( 2131 int8smaller - 412 20 0 _null_ ));
DATA(insert ( 2132 int4smaller - 97 23 0 _null_ ));
DATA(insert ( 2133 int2smaller - 95 21 0 _null_ ));
DATA(insert ( 2134 oidsmaller - 609 26 0 _null_ ));
DATA(insert ( 2135 float4smaller - 622 700 0 _null_ ));
DATA(insert ( 2136 float8smaller - 672 701 0 _null_ ));
DATA(insert ( 2137 int4smaller - 562 702 0 _null_ ));
DATA(insert ( 2138 date_smaller - 1095 1082 0 _null_ ));
DATA(insert ( 2139 time_smaller - 1110 1083 0 _null_ ));
DATA(insert ( 2140 timetz_smaller - 1552 1266 0 _null_ ));
DATA(insert ( 2141 cashsmaller - 902 790 0 _null_ ));
DATA(insert ( 2142 timestamp_smaller - 2062 1114 0 _null_ ));
DATA(insert ( 2143 timestamptz_smaller - 1322 1184 0 _null_ ));
DATA(insert ( 2144 interval_smaller - 1332 1186 0 _null_ ));
DATA(insert ( 2145 text_smaller - 664 25 0 _null_ ));
DATA(insert ( 2146 numeric_smaller - 1754 1700 0 _null_ ));
DATA(insert ( 2051 array_smaller - 1072 2277 0 _null_ ));
DATA(insert ( 2245 bpchar_smaller - 1058 1042 0 _null_ ));
DATA(insert ( 2798 tidsmaller - 2799 27 0 _null_ ));
DATA(insert ( 3527 enum_smaller - 3518 3500 0 _null_ ));
/* count */
DATA(insert ( 2147 int8inc_any - 0 20 "0" ));
DATA(insert ( 2803 int8inc - 0 20 "0" ));
DATA(insert ( 2147 int8inc_any - 0 20 0 "0" ));
DATA(insert ( 2803 int8inc - 0 20 0 "0" ));
/* var_pop */
DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 "{0,0,0}" ));
DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 "{0,0,0}" ));
DATA(insert ( 2723 numeric_accum numeric_var_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2723 numeric_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
/* var_samp */
DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2646 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2646 numeric_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
/* variance: historical Postgres syntax for var_samp */
DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2153 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2153 numeric_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
/* stddev_pop */
DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
/* stddev_samp */
DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
/* stddev: historical Postgres syntax for stddev_samp */
DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 int8inc_float8_float8 - 0 20 "0" ));
DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 "{0,0,0,0,0,0}" ));
DATA(insert ( 2818 int8inc_float8_float8 - 0 20 0 "0" ));
DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 0 "{0,0,0,0,0,0}" ));
DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 0 "{0,0,0,0,0,0}" ));
/* boolean-and and boolean-or */
DATA(insert ( 2517 booland_statefunc - 58 16 _null_ ));
DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ ));
DATA(insert ( 2519 booland_statefunc - 58 16 _null_ ));
DATA(insert ( 2517 booland_statefunc - 58 16 0 _null_ ));
DATA(insert ( 2518 boolor_statefunc - 59 16 0 _null_ ));
DATA(insert ( 2519 booland_statefunc - 58 16 0 _null_ ));
/* bitwise integer */
DATA(insert ( 2236 int2and - 0 21 _null_ ));
DATA(insert ( 2237 int2or - 0 21 _null_ ));
DATA(insert ( 2238 int4and - 0 23 _null_ ));
DATA(insert ( 2239 int4or - 0 23 _null_ ));
DATA(insert ( 2240 int8and - 0 20 _null_ ));
DATA(insert ( 2241 int8or - 0 20 _null_ ));
DATA(insert ( 2242 bitand - 0 1560 _null_ ));
DATA(insert ( 2243 bitor - 0 1560 _null_ ));
DATA(insert ( 2236 int2and - 0 21 0 _null_ ));
DATA(insert ( 2237 int2or - 0 21 0 _null_ ));
DATA(insert ( 2238 int4and - 0 23 0 _null_ ));
DATA(insert ( 2239 int4or - 0 23 0 _null_ ));
DATA(insert ( 2240 int8and - 0 20 0 _null_ ));
DATA(insert ( 2241 int8or - 0 20 0 _null_ ));
DATA(insert ( 2242 bitand - 0 1560 0 _null_ ));
DATA(insert ( 2243 bitor - 0 1560 0 _null_ ));
/* xml */
DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ ));
DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ ));
/* array */
DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ ));
DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 0 _null_ ));
/* text */
DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 _null_ ));
DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 0 _null_ ));
/* bytea */
DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 _null_ ));
DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 0 _null_ ));
/* json */
DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 _null_ ));
DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
@ -250,6 +253,7 @@ extern Oid AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
int32 aggTransSpace,
const char *agginitval);
#endif /* PG_AGGREGATE_H */

View File

@ -133,6 +133,7 @@ extern Datum transformGenericOptions(Oid catalogId,
extern char *defGetString(DefElem *def);
extern double defGetNumeric(DefElem *def);
extern bool defGetBoolean(DefElem *def);
extern int32 defGetInt32(DefElem *def);
extern int64 defGetInt64(DefElem *def);
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);

View File

@ -56,7 +56,7 @@ create aggregate aggfstr(integer,integer,text) (
initcond = '{}'
);
create aggregate aggfns(integer,integer,text) (
sfunc = aggfns_trans, stype = aggtype[],
sfunc = aggfns_trans, stype = aggtype[], sspace = 10000,
initcond = '{}'
);
-- variadic aggregate

View File

@ -702,7 +702,7 @@ SELECT * FROM funcdescs
-- Look for illegal values in pg_aggregate fields.
SELECT ctid, aggfnoid::oid
FROM pg_aggregate as p1
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0;
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0 OR aggtransspace < 0;
ctid | aggfnoid
------+----------
(0 rows)

View File

@ -68,7 +68,7 @@ create aggregate aggfstr(integer,integer,text) (
);
create aggregate aggfns(integer,integer,text) (
sfunc = aggfns_trans, stype = aggtype[],
sfunc = aggfns_trans, stype = aggtype[], sspace = 10000,
initcond = '{}'
);

View File

@ -567,7 +567,7 @@ SELECT * FROM funcdescs
SELECT ctid, aggfnoid::oid
FROM pg_aggregate as p1
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0;
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0 OR aggtransspace < 0;
-- Make sure the matching pg_proc entry is sensible, too.