7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.31 1998/11/27 19:52:13 vadim Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.32 1998/12/08 06:18:56 thomas Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
25
25
#include "catalog/pg_inherits.h"
26
26
#include "catalog/pg_proc.h"
27
27
#include "catalog/pg_type.h"
28
+ #include "catalog/pg_aggregate.h"
28
29
#include "fmgr.h"
29
30
#include "lib/dllist.h"
30
31
#include "miscadmin.h"
@@ -76,6 +77,8 @@ static List *setup_tlist(char *attname, Oid relid);
76
77
static List * setup_base_tlist (Oid typeid );
77
78
static Oid * func_select_candidate (int nargs , Oid * input_typeids ,
78
79
CandidateList candidates );
80
+ static int agg_get_candidates (char * aggname , Oid typeId , CandidateList * candidates );
81
+ static Oid agg_select_candidate (Oid typeid , CandidateList candidates );
79
82
80
83
#define ISCOMPLEX (type ) (typeidTypeRelid(type) ? true : false)
81
84
@@ -130,6 +133,108 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
130
133
return retval ;
131
134
}
132
135
136
+ static int
137
+ agg_get_candidates (char * aggname ,
138
+ Oid typeId ,
139
+ CandidateList * candidates )
140
+ {
141
+ CandidateList current_candidate ;
142
+ Relation pg_aggregate_desc ;
143
+ HeapScanDesc pg_aggregate_scan ;
144
+ HeapTuple tup ;
145
+ Form_pg_aggregate agg ;
146
+ int ncandidates = 0 ;
147
+
148
+ static ScanKeyData aggKey [1 ] = {
149
+ {0 , Anum_pg_aggregate_aggname , F_NAMEEQ }};
150
+
151
+ * candidates = NULL ;
152
+
153
+ fmgr_info (F_NAMEEQ , (FmgrInfo * ) & aggKey [0 ].sk_func );
154
+ aggKey [0 ].sk_argument = NameGetDatum (aggname );
155
+
156
+ pg_aggregate_desc = heap_openr (AggregateRelationName );
157
+ pg_aggregate_scan = heap_beginscan (pg_aggregate_desc ,
158
+ 0 ,
159
+ SnapshotSelf , /* ??? */
160
+ 1 ,
161
+ aggKey );
162
+
163
+ while (HeapTupleIsValid (tup = heap_getnext (pg_aggregate_scan , 0 )))
164
+ {
165
+ current_candidate = (CandidateList ) palloc (sizeof (struct _CandidateList ));
166
+ current_candidate -> args = (Oid * ) palloc (sizeof (Oid ));
167
+
168
+ agg = (Form_pg_aggregate ) GETSTRUCT (tup );
169
+ current_candidate -> args [0 ] = agg -> aggbasetype ;
170
+ current_candidate -> next = * candidates ;
171
+ * candidates = current_candidate ;
172
+ ncandidates ++ ;
173
+ }
174
+
175
+ heap_endscan (pg_aggregate_scan );
176
+ heap_close (pg_aggregate_desc );
177
+
178
+ return ncandidates ;
179
+ } /* agg_get_candidates() */
180
+
181
+ /* agg_select_candidate()
182
+ * Try to choose only one candidate aggregate function from a list of possibles.
183
+ */
184
+ static Oid
185
+ agg_select_candidate (Oid typeid , CandidateList candidates )
186
+ {
187
+ CandidateList current_candidate ;
188
+ CandidateList last_candidate ;
189
+ Oid current_typeid ;
190
+ int ncandidates ;
191
+ CATEGORY category ,
192
+ current_category ;
193
+
194
+ /*
195
+ * Look for candidates which allow coersion and have a preferred type.
196
+ * Keep all candidates if none match.
197
+ */
198
+ category = TypeCategory (typeid );
199
+ ncandidates = 0 ;
200
+ last_candidate = NULL ;
201
+ for (current_candidate = candidates ;
202
+ current_candidate != NULL ;
203
+ current_candidate = current_candidate -> next )
204
+ {
205
+ current_typeid = current_candidate -> args [0 ];
206
+ current_category = TypeCategory (current_typeid );
207
+
208
+ if ((current_category == category )
209
+ && IsPreferredType (current_category , current_typeid )
210
+ && can_coerce_type (1 , & typeid , & current_typeid ))
211
+ {
212
+ /* only one so far? then keep it... */
213
+ if (last_candidate == NULL )
214
+ {
215
+ candidates = current_candidate ;
216
+ last_candidate = current_candidate ;
217
+ ncandidates = 1 ;
218
+ }
219
+ /* otherwise, keep this one too... */
220
+ else
221
+ {
222
+ last_candidate -> next = current_candidate ;
223
+ last_candidate = current_candidate ;
224
+ ncandidates ++ ;
225
+ }
226
+ }
227
+ /* otherwise, don't bother keeping this one around... */
228
+ else
229
+ {
230
+ last_candidate -> next = NULL ;
231
+ }
232
+ }
233
+
234
+ return ((ncandidates == 1 ) ? candidates -> args [0 ] : 0 );
235
+ } /* agg_select_candidate() */
236
+
237
+
133
238
/*
134
239
* parse function
135
240
*/
@@ -250,8 +355,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
250
355
/*
251
356
* Parsing aggregates.
252
357
*/
253
- Type tp ;
254
- Oid basetype ;
358
+ Type tp ;
359
+ Oid basetype ;
360
+ int ncandidates ;
361
+ CandidateList candidates ;
362
+
255
363
256
364
/*
257
365
* the aggregate COUNT is a special case, ignore its base
@@ -261,23 +369,56 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
261
369
basetype = 0 ;
262
370
else
263
371
basetype = exprType (lfirst (fargs ));
372
+
373
+ /* try for exact match first... */
264
374
if (SearchSysCacheTuple (AGGNAME ,
265
375
PointerGetDatum (funcname ),
266
376
ObjectIdGetDatum (basetype ),
267
377
0 , 0 ))
268
378
return (Node * ) ParseAgg (pstate , funcname , basetype ,
269
379
fargs , precedence );
270
380
381
+ /*
382
+ * No exact match yet, so see if there is another entry
383
+ * in the aggregate table which is compatible.
384
+ * - thomas 1998-12-05
385
+ */
386
+ ncandidates = agg_get_candidates (funcname , basetype , & candidates );
387
+ if (ncandidates > 0 )
388
+ {
389
+ Oid type ;
390
+
391
+ type = agg_select_candidate (basetype , candidates );
392
+ if (OidIsValid (type ))
393
+ {
394
+ lfirst (fargs ) = coerce_type (pstate , lfirst (fargs ), basetype , type );
395
+ basetype = type ;
396
+
397
+ return (Node * ) ParseAgg (pstate , funcname , basetype ,
398
+ fargs , precedence );
399
+ }
400
+ else
401
+ {
402
+ elog (ERROR ,"Unable to select an aggregate function for type %s" ,
403
+ typeidTypeName (basetype ));
404
+ }
405
+ }
406
+
271
407
/*
272
408
* See if this is a single argument function with the function
273
409
* name also a type name and the input argument and type name
274
410
* binary compatible...
411
+ * This means that you are trying for a type conversion which does not
412
+ * need to take place, so we'll just pass through the argument itself.
413
+ * (make this clearer with some extra brackets - thomas 1998-12-05)
275
414
*/
276
415
if ((HeapTupleIsValid (tp = SearchSysCacheTuple (TYPNAME ,
277
- PointerGetDatum (funcname ),
416
+ PointerGetDatum (funcname ),
278
417
0 , 0 , 0 )))
279
418
&& IS_BINARY_COMPATIBLE (typeTypeId (tp ), basetype ))
419
+ {
280
420
return ((Node * ) lfirst (fargs ));
421
+ }
281
422
}
282
423
}
283
424
0 commit comments