Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0a27641

Browse files
committed
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.
1 parent 4579e68 commit 0a27641

File tree

1 file changed

+56
-47
lines changed

1 file changed

+56
-47
lines changed

src/backend/catalog/pg_aggregate.c

+56-47
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.29 2000/01/26 05:56:10 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.30 2000/03/26 19:43:58 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -30,7 +30,7 @@
3030
* aggregates overloading has been added. Instead of the full
3131
* overload support we have for functions, aggregate overloading only
3232
* applies to exact basetype matches. That is, we don't check the
33-
* the inheritance hierarchy
33+
* inheritance hierarchy
3434
*
3535
* OLD COMMENTS:
3636
* Currently, redefining aggregates using the same name is not
@@ -85,13 +85,28 @@ AggregateCreate(char *aggName,
8585
if (!aggtransfn1Name && !aggtransfn2Name)
8686
elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
8787

88+
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
89+
elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
90+
91+
/* handle the aggregate's base type (input data type) */
8892
tup = SearchSysCacheTuple(TYPENAME,
8993
PointerGetDatum(aggbasetypeName),
9094
0, 0, 0);
9195
if (!HeapTupleIsValid(tup))
9296
elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
9397
xbase = tup->t_data->t_oid;
9498

99+
/* make sure there is no existing agg of same name and base type */
100+
tup = SearchSysCacheTuple(AGGNAME,
101+
PointerGetDatum(aggName),
102+
ObjectIdGetDatum(xbase),
103+
0, 0);
104+
if (HeapTupleIsValid(tup))
105+
elog(ERROR,
106+
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
107+
aggName, aggbasetypeName);
108+
109+
/* handle transfn1 and transtype1 */
95110
if (aggtransfn1Name)
96111
{
97112
tup = SearchSysCacheTuple(TYPENAME,
@@ -114,14 +129,14 @@ AggregateCreate(char *aggName,
114129
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
115130
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
116131
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
117-
aggtransfn1Name,
118-
aggtransfn1typeName);
132+
aggtransfn1Name, aggtransfn1typeName);
119133
xfn1 = tup->t_data->t_oid;
120134
if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
121135
!OidIsValid(xbase))
122-
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
136+
elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn1Name);
123137
}
124138

139+
/* handle transfn2 and transtype2 */
125140
if (aggtransfn2Name)
126141
{
127142
tup = SearchSysCacheTuple(TYPENAME,
@@ -147,47 +162,57 @@ AggregateCreate(char *aggName,
147162
aggtransfn2Name, aggtransfn2typeName);
148163
xfn2 = tup->t_data->t_oid;
149164
if (!OidIsValid(xfn2) || !OidIsValid(xret2))
150-
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
165+
elog(ERROR, "AggregateCreate: bogus function '%s'", aggtransfn2Name);
151166
}
152167

153-
tup = SearchSysCacheTuple(AGGNAME,
154-
PointerGetDatum(aggName),
155-
ObjectIdGetDatum(xbase),
156-
0, 0);
157-
if (HeapTupleIsValid(tup))
158-
elog(ERROR,
159-
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
160-
aggName, aggbasetypeName);
161-
162-
/* more sanity checks */
163-
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
164-
elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
165-
166-
if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
167-
elog(ERROR, "AggregateCreate: Aggregate cannot have final function without both transition functions");
168-
168+
/* handle finalfn */
169169
if (aggfinalfnName)
170170
{
171-
fnArgs[0] = xret1;
172-
fnArgs[1] = xret2;
171+
int nargs = 0;
172+
173+
if (OidIsValid(xret1))
174+
fnArgs[nargs++] = xret1;
175+
if (OidIsValid(xret2))
176+
fnArgs[nargs++] = xret2;
177+
fnArgs[nargs] = 0; /* make sure slot 2 is empty if just 1 arg */
173178
tup = SearchSysCacheTuple(PROCNAME,
174179
PointerGetDatum(aggfinalfnName),
175-
Int32GetDatum(2),
180+
Int32GetDatum(nargs),
176181
PointerGetDatum(fnArgs),
177182
0);
178183
if (!HeapTupleIsValid(tup))
179-
elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
180-
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
184+
{
185+
if (nargs == 2)
186+
elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
187+
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
188+
else if (OidIsValid(xret1))
189+
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
190+
aggfinalfnName, aggtransfn1typeName);
191+
else
192+
elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
193+
aggfinalfnName, aggtransfn2typeName);
194+
}
181195
ffn = tup->t_data->t_oid;
182196
proc = (Form_pg_proc) GETSTRUCT(tup);
183197
fret = proc->prorettype;
184198
if (!OidIsValid(ffn) || !OidIsValid(fret))
185199
elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
186200
}
201+
else
202+
{
203+
/* If no finalfn, aggregate result type is type of the sole
204+
* state value (we already checked there is only one)
205+
*/
206+
if (OidIsValid(xret1))
207+
fret = xret1;
208+
else
209+
fret = xret2;
210+
}
211+
Assert(OidIsValid(fret));
187212

188213
/*
189214
* If transition function 2 is defined, it must have an initial value,
190-
* whereas transition function 1 does not, which allows man and min
215+
* whereas transition function 1 need not, which allows max and min
191216
* aggregates to return NULL if they are evaluated on empty sets.
192217
*/
193218
if (OidIsValid(xfn2) && !agginitval2)
@@ -205,26 +230,10 @@ AggregateCreate(char *aggName,
205230
values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
206231
values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
207232
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
208-
209233
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
210-
if (!OidIsValid(xfn1))
211-
{
212-
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(InvalidOid);
213-
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
214-
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret2);
215-
}
216-
else if (!OidIsValid(xfn2))
217-
{
218-
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
219-
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(InvalidOid);
220-
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret1);
221-
}
222-
else
223-
{
224-
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
225-
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
226-
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
227-
}
234+
values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
235+
values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
236+
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
228237

229238
if (agginitval1)
230239
values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));

0 commit comments

Comments
 (0)