Commit 0a27641c authored by Tom Lane's avatar Tom Lane

nodeAgg has always been willing to accept an aggregate with a finalFunc

and only one transition state, but the CREATE AGGREGATE code rejected
this combination.
parent 4579e68d
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.29 2000/01/26 05:56:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.30 2000/03/26 19:43:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* aggregates overloading has been added. Instead of the full * aggregates overloading has been added. Instead of the full
* overload support we have for functions, aggregate overloading only * overload support we have for functions, aggregate overloading only
* applies to exact basetype matches. That is, we don't check the * applies to exact basetype matches. That is, we don't check the
* the inheritance hierarchy * inheritance hierarchy
* *
* OLD COMMENTS: * OLD COMMENTS:
* Currently, redefining aggregates using the same name is not * Currently, redefining aggregates using the same name is not
...@@ -85,6 +85,10 @@ AggregateCreate(char *aggName, ...@@ -85,6 +85,10 @@ AggregateCreate(char *aggName,
if (!aggtransfn1Name && !aggtransfn2Name) if (!aggtransfn1Name && !aggtransfn2Name)
elog(ERROR, "AggregateCreate: aggregate must have at least one transition function"); elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
/* handle the aggregate's base type (input data type) */
tup = SearchSysCacheTuple(TYPENAME, tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(aggbasetypeName), PointerGetDatum(aggbasetypeName),
0, 0, 0); 0, 0, 0);
...@@ -92,6 +96,17 @@ AggregateCreate(char *aggName, ...@@ -92,6 +96,17 @@ AggregateCreate(char *aggName,
elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName); elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
xbase = tup->t_data->t_oid; xbase = tup->t_data->t_oid;
/* make sure there is no existing agg of same name and base type */
tup = SearchSysCacheTuple(AGGNAME,
PointerGetDatum(aggName),
ObjectIdGetDatum(xbase),
0, 0);
if (HeapTupleIsValid(tup))
elog(ERROR,
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
aggName, aggbasetypeName);
/* handle transfn1 and transtype1 */
if (aggtransfn1Name) if (aggtransfn1Name)
{ {
tup = SearchSysCacheTuple(TYPENAME, tup = SearchSysCacheTuple(TYPENAME,
...@@ -114,14 +129,14 @@ AggregateCreate(char *aggName, ...@@ -114,14 +129,14 @@ AggregateCreate(char *aggName,
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName); aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1) if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'", elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
aggtransfn1Name, aggtransfn1Name, aggtransfn1typeName);
aggtransfn1typeName);
xfn1 = tup->t_data->t_oid; xfn1 = tup->t_data->t_oid;
if (!OidIsValid(xfn1) || !OidIsValid(xret1) || if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
!OidIsValid(xbase)) !OidIsValid(xbase))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName); elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn1Name);
} }
/* handle transfn2 and transtype2 */
if (aggtransfn2Name) if (aggtransfn2Name)
{ {
tup = SearchSysCacheTuple(TYPENAME, tup = SearchSysCacheTuple(TYPENAME,
...@@ -147,47 +162,57 @@ AggregateCreate(char *aggName, ...@@ -147,47 +162,57 @@ AggregateCreate(char *aggName,
aggtransfn2Name, aggtransfn2typeName); aggtransfn2Name, aggtransfn2typeName);
xfn2 = tup->t_data->t_oid; xfn2 = tup->t_data->t_oid;
if (!OidIsValid(xfn2) || !OidIsValid(xret2)) if (!OidIsValid(xfn2) || !OidIsValid(xret2))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName); elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn2Name);
} }
tup = SearchSysCacheTuple(AGGNAME, /* handle finalfn */
PointerGetDatum(aggName),
ObjectIdGetDatum(xbase),
0, 0);
if (HeapTupleIsValid(tup))
elog(ERROR,
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
aggName, aggbasetypeName);
/* more sanity checks */
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
elog(ERROR, "AggregateCreate: Aggregate cannot have final function without both transition functions");
if (aggfinalfnName) if (aggfinalfnName)
{ {
fnArgs[0] = xret1; int nargs = 0;
fnArgs[1] = xret2;
if (OidIsValid(xret1))
fnArgs[nargs++] = xret1;
if (OidIsValid(xret2))
fnArgs[nargs++] = xret2;
fnArgs[nargs] = 0; /* make sure slot 2 is empty if just 1 arg */
tup = SearchSysCacheTuple(PROCNAME, tup = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(aggfinalfnName), PointerGetDatum(aggfinalfnName),
Int32GetDatum(2), Int32GetDatum(nargs),
PointerGetDatum(fnArgs), PointerGetDatum(fnArgs),
0); 0);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist", {
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName); if (nargs == 2)
elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
else if (OidIsValid(xret1))
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
aggfinalfnName, aggtransfn1typeName);
else
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
aggfinalfnName, aggtransfn2typeName);
}
ffn = tup->t_data->t_oid; ffn = tup->t_data->t_oid;
proc = (Form_pg_proc) GETSTRUCT(tup); proc = (Form_pg_proc) GETSTRUCT(tup);
fret = proc->prorettype; fret = proc->prorettype;
if (!OidIsValid(ffn) || !OidIsValid(fret)) if (!OidIsValid(ffn) || !OidIsValid(fret))
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName); elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
} }
else
{
/* If no finalfn, aggregate result type is type of the sole
* state value (we already checked there is only one)
*/
if (OidIsValid(xret1))
fret = xret1;
else
fret = xret2;
}
Assert(OidIsValid(fret));
/* /*
* If transition function 2 is defined, it must have an initial value, * If transition function 2 is defined, it must have an initial value,
* whereas transition function 1 does not, which allows man and min * whereas transition function 1 need not, which allows max and min
* aggregates to return NULL if they are evaluated on empty sets. * aggregates to return NULL if they are evaluated on empty sets.
*/ */
if (OidIsValid(xfn2) && !agginitval2) if (OidIsValid(xfn2) && !agginitval2)
...@@ -205,26 +230,10 @@ AggregateCreate(char *aggName, ...@@ -205,26 +230,10 @@ AggregateCreate(char *aggName,
values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1); values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2); values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn); values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase); values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
if (!OidIsValid(xfn1)) values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
{ values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(InvalidOid); values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret2);
}
else if (!OidIsValid(xfn2))
{
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret1);
}
else
{
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
}
if (agginitval1) if (agginitval1)
values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1)); values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment