diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/pg_aggregate.c | 2 | ||||
-rw-r--r-- | src/backend/commands/aggregatecmds.c | 4 | ||||
-rw-r--r-- | src/backend/commands/define.c | 24 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 40 |
4 files changed, 57 insertions, 13 deletions
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index d9e961ebfad..9dbec508a0d 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -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 diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 78af0924654..6fc3e045492 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -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 */ } diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 9fa222f5fc0..75f77da2cff 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -165,6 +165,30 @@ defGetBoolean(DefElem *def) } /* + * 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. */ int64 diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index add29f54d09..7ce8a9d8180 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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; } /* |