8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
30
30
* aggregates overloading has been added. Instead of the full
31
31
* overload support we have for functions, aggregate overloading only
32
32
* applies to exact basetype matches. That is, we don't check the
33
- * the inheritance hierarchy
33
+ * inheritance hierarchy
34
34
*
35
35
* OLD COMMENTS:
36
36
* Currently, redefining aggregates using the same name is not
@@ -85,13 +85,28 @@ AggregateCreate(char *aggName,
85
85
if (!aggtransfn1Name && !aggtransfn2Name )
86
86
elog (ERROR , "AggregateCreate: aggregate must have at least one transition function" );
87
87
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) */
88
92
tup = SearchSysCacheTuple (TYPENAME ,
89
93
PointerGetDatum (aggbasetypeName ),
90
94
0 , 0 , 0 );
91
95
if (!HeapTupleIsValid (tup ))
92
96
elog (ERROR , "AggregateCreate: Type '%s' undefined" , aggbasetypeName );
93
97
xbase = tup -> t_data -> t_oid ;
94
98
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 */
95
110
if (aggtransfn1Name )
96
111
{
97
112
tup = SearchSysCacheTuple (TYPENAME ,
@@ -114,14 +129,14 @@ AggregateCreate(char *aggName,
114
129
aggtransfn1Name , aggtransfn1typeName , aggbasetypeName );
115
130
if (((Form_pg_proc ) GETSTRUCT (tup ))-> prorettype != xret1 )
116
131
elog (ERROR , "AggregateCreate: return type of '%s' is not '%s'" ,
117
- aggtransfn1Name ,
118
- aggtransfn1typeName );
132
+ aggtransfn1Name , aggtransfn1typeName );
119
133
xfn1 = tup -> t_data -> t_oid ;
120
134
if (!OidIsValid (xfn1 ) || !OidIsValid (xret1 ) ||
121
135
!OidIsValid (xbase ))
122
- elog (ERROR , "AggregateCreate: bogus function '%s'" , aggfinalfnName );
136
+ elog (ERROR , "AggregateCreate: bogus function '%s'" , aggtransfn1Name );
123
137
}
124
138
139
+ /* handle transfn2 and transtype2 */
125
140
if (aggtransfn2Name )
126
141
{
127
142
tup = SearchSysCacheTuple (TYPENAME ,
@@ -147,47 +162,57 @@ AggregateCreate(char *aggName,
147
162
aggtransfn2Name , aggtransfn2typeName );
148
163
xfn2 = tup -> t_data -> t_oid ;
149
164
if (!OidIsValid (xfn2 ) || !OidIsValid (xret2 ))
150
- elog (ERROR , "AggregateCreate: bogus function '%s'" , aggfinalfnName );
165
+ elog (ERROR , "AggregateCreate: bogus function '%s'" , aggtransfn2Name );
151
166
}
152
167
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 */
169
169
if (aggfinalfnName )
170
170
{
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 */
173
178
tup = SearchSysCacheTuple (PROCNAME ,
174
179
PointerGetDatum (aggfinalfnName ),
175
- Int32GetDatum (2 ),
180
+ Int32GetDatum (nargs ),
176
181
PointerGetDatum (fnArgs ),
177
182
0 );
178
183
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
+ }
181
195
ffn = tup -> t_data -> t_oid ;
182
196
proc = (Form_pg_proc ) GETSTRUCT (tup );
183
197
fret = proc -> prorettype ;
184
198
if (!OidIsValid (ffn ) || !OidIsValid (fret ))
185
199
elog (ERROR , "AggregateCreate: bogus function '%s'" , aggfinalfnName );
186
200
}
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 ));
187
212
188
213
/*
189
214
* 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
191
216
* aggregates to return NULL if they are evaluated on empty sets.
192
217
*/
193
218
if (OidIsValid (xfn2 ) && !agginitval2 )
@@ -205,26 +230,10 @@ AggregateCreate(char *aggName,
205
230
values [Anum_pg_aggregate_aggtransfn1 - 1 ] = ObjectIdGetDatum (xfn1 );
206
231
values [Anum_pg_aggregate_aggtransfn2 - 1 ] = ObjectIdGetDatum (xfn2 );
207
232
values [Anum_pg_aggregate_aggfinalfn - 1 ] = ObjectIdGetDatum (ffn );
208
-
209
233
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 );
228
237
229
238
if (agginitval1 )
230
239
values [Anum_pg_aggregate_agginitval1 - 1 ] = PointerGetDatum (textin (agginitval1 ));
0 commit comments