88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.29 2000/01 /2605:56:10 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.30 2000/03 /2619:43:58 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
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,
8585if (!aggtransfn1Name && !aggtransfn2Name )
8686elog (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) */
8892tup = SearchSysCacheTuple (TYPENAME ,
8993PointerGetDatum (aggbasetypeName ),
90940 ,0 ,0 );
9195if (!HeapTupleIsValid (tup ))
9296elog (ERROR ,"AggregateCreate: Type '%s' undefined" ,aggbasetypeName );
9397xbase = 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 */
95110if (aggtransfn1Name )
96111{
97112tup = SearchSysCacheTuple (TYPENAME ,
@@ -114,14 +129,14 @@ AggregateCreate(char *aggName,
114129aggtransfn1Name ,aggtransfn1typeName ,aggbasetypeName );
115130if (((Form_pg_proc )GETSTRUCT (tup ))-> prorettype != xret1 )
116131elog (ERROR ,"AggregateCreate: return type of '%s' is not '%s'" ,
117- aggtransfn1Name ,
118- aggtransfn1typeName );
132+ aggtransfn1Name ,aggtransfn1typeName );
119133xfn1 = tup -> t_data -> t_oid ;
120134if (!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 */
125140if (aggtransfn2Name )
126141{
127142tup = SearchSysCacheTuple (TYPENAME ,
@@ -147,47 +162,57 @@ AggregateCreate(char *aggName,
147162aggtransfn2Name ,aggtransfn2typeName );
148163xfn2 = tup -> t_data -> t_oid ;
149164if (!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 */
169169if (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 */
173178tup = SearchSysCacheTuple (PROCNAME ,
174179PointerGetDatum (aggfinalfnName ),
175- Int32GetDatum (2 ),
180+ Int32GetDatum (nargs ),
176181PointerGetDatum (fnArgs ),
1771820 );
178183if (!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+ }
181195ffn = tup -> t_data -> t_oid ;
182196proc = (Form_pg_proc )GETSTRUCT (tup );
183197fret = proc -> prorettype ;
184198if (!OidIsValid (ffn )|| !OidIsValid (fret ))
185199elog (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 1does not, which allowsman and min
215+ * whereas transition function 1need not, which allowsmax and min
191216 * aggregates to return NULL if they are evaluated on empty sets.
192217 */
193218if (OidIsValid (xfn2 )&& !agginitval2 )
@@ -205,26 +230,10 @@ AggregateCreate(char *aggName,
205230values [Anum_pg_aggregate_aggtransfn1 - 1 ]= ObjectIdGetDatum (xfn1 );
206231values [Anum_pg_aggregate_aggtransfn2 - 1 ]= ObjectIdGetDatum (xfn2 );
207232values [Anum_pg_aggregate_aggfinalfn - 1 ]= ObjectIdGetDatum (ffn );
208-
209233values [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
229238if (agginitval1 )
230239values [Anum_pg_aggregate_agginitval1 - 1 ]= PointerGetDatum (textin (agginitval1 ));