Allow aggregates to provide estimates of their transition state data size.
authorTom Lane
Sat, 16 Nov 2013 21:03:40 +0000 (16:03 -0500)
committerTom Lane
Sat, 16 Nov 2013 21:03:40 +0000 (16:03 -0500)
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

14 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/create_aggregate.sgml
src/backend/catalog/pg_aggregate.c
src/backend/commands/aggregatecmds.c
src/backend/commands/define.c
src/backend/optimizer/util/clauses.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.h
src/include/commands/defrem.h
src/test/regress/expected/create_aggregate.out
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/create_aggregate.sql
src/test/regress/sql/opr_sanity.sql

index 9388df5ac273d32750027618e299f56ad8ba7004..acc261ca516cd91368ad19dd4750c4bbb0294809 100644 (file)
       pg_type.oid
       Data type of the aggregate function's internal transition (state) data
      
+     
+      aggtransspace
+      int4
+      
+      Approximate average size (in bytes) of the transition state
+       data, or zero to use a default estimate
+     
      
       agginitval
       text
index 2b35fa4d5226adccfe4d8a6c1e244a56d0ac084f..17819dd1a8edf627df699bdc198ffffdfa2a24e2 100644 (file)
@@ -24,6 +24,7 @@ PostgreSQL documentation
 CREATE AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] ) (
     SFUNC = sfunc,
     STYPE = state_data_type
+    [ , SSPACE = state_data_size ]
     [ , FINALFUNC = ffunc ]
     [ , INITCOND = initial_condition ]
     [ , SORTOP = sort_operator ]
@@ -35,6 +36,7 @@ CREATE AGGREGATE name (
     BASETYPE = base_type,
     SFUNC = sfunc,
     STYPE = state_data_type
+    [ , SSPACE = state_data_size ]
     [ , FINALFUNC = ffunc ]
     [ , INITCOND = initial_condition ]
     [ , SORTOP = sort_operator ]
@@ -264,6 +266,22 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
     
    
 
+   
+    state_data_size
+    
+     
+      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 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 ; therefore, large values of this
+      parameter discourage use of hash aggregation.
+     
+    
+   
+
    
     ffunc
     
index d9e961ebfad668cc56232e8793d230c4044cf70f..9dbec508a0d696863fd01c0d99369efd8ca2bef4 100644 (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
index 78af09246547a7fd091b13509ae1e5ddf1c44102..6fc3e045492d97e0c5f789088e0fad43477902f9 100644 (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 */
 }
index 9fa222f5fc0f5a4c0766a7e1e840cdf796317995..75f77da2cffefea87c6b118ca62cd6eca5a511b0 100644 (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.
  */
index add29f54d09e68b30d1985eec7f0cf490be707d8..7ce8a9d8180df60be2d36c0b2e260c9a9f6716f9 100644 (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;
 
-           avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);
-           avgwidth = MAXALIGN(avgwidth);
+               if (numArguments > 0 && aggtranstype == inputTypes[0])
+                   aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
+               else
+                   aggtranstypmod = -1;
+
+               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;
        }
 
        /*
index 6c16b3ca49e6ad364117bf4d47c554476cd94cb5..f81094ee7055796916ef81fd77ae93c85383676e 100644 (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, "
+                         "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, "
-                         "agginitval, "
+                         "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 = ");
index 4108f6c16c046af629cad1c525a8b75827b7ef6e..cb9021c525afd7d73c84ecb5dff54114ebe83aef 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201311081
+#define CATALOG_VERSION_NO 201311161
 
 #endif
index 5ad6ea6e3d1a9c89372069bb9334a04b91f7f626..416d651bf0a040dae4e3913de2a7e741a15af41a 100644 (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 */
index 836c99e97ea5127131491bfe77a2a0dbdf87c8de..f8ceb5da2eb6d7a43469f955ce0dcd46b4d1d350 100644 (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);
index 6c7566f1728fed6a2547870ba608be64a320bc45..9ecaea149927c04667185f908317b7bf0268e33d 100644 (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
index 57d614f651702f08e5d9592d422ed2984674aa1d..10d65c0b28720470252b47d6c6b3fae33f50fc7a 100644 (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)
index 3c7d330960ff5f6723e8f1c82c79f61791c7a49c..7ea23de0b6af29ec5803bde2daa07f7cceaa436a 100644 (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 = '{}'
 );
 
index efcd70f03be89a9a49210e722ee3d807a8cc3e1b..1c71c964a5b7e0ce5821d1fa90e8a9545fc83c25 100644 (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.