Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/pg_aggregate.c2
-rw-r--r--src/backend/commands/aggregatecmds.c4
-rw-r--r--src/backend/commands/define.c24
-rw-r--r--src/backend/optimizer/util/clauses.c40
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;
}
/*