8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.59 2003/07/01 19:10:52 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
29
29
#include "utils/syscache.h"
30
30
31
31
32
+ static Oid lookup_agg_function (List * fnName , int nargs , Oid * input_types ,
33
+ Oid * rettype );
34
+
35
+
32
36
/*
33
37
* AggregateCreate
34
38
*/
@@ -48,9 +52,10 @@ AggregateCreate(const char *aggName,
48
52
Form_pg_proc proc ;
49
53
Oid transfn ;
50
54
Oid finalfn = InvalidOid ; /* can be omitted */
55
+ Oid rettype ;
51
56
Oid finaltype ;
52
57
Oid fnArgs [FUNC_MAX_ARGS ];
53
- int nargs ;
58
+ int nargs_transfn ;
54
59
Oid procOid ;
55
60
TupleDesc tupDesc ;
56
61
int i ;
@@ -64,28 +69,49 @@ AggregateCreate(const char *aggName,
64
69
if (!aggtransfnName )
65
70
elog (ERROR , "aggregate must have a transition function" );
66
71
72
+ /*
73
+ * If transtype is polymorphic, basetype must be polymorphic also;
74
+ * else we will have no way to deduce the actual transtype.
75
+ */
76
+ if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID ) &&
77
+ !(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID ))
78
+ elog (ERROR , "an aggregate using ANYARRAY or ANYELEMENT as trans type "
79
+ "must also have one of them as its base type" );
80
+
67
81
/* handle transfn */
68
82
MemSet (fnArgs , 0 , FUNC_MAX_ARGS * sizeof (Oid ));
69
83
fnArgs [0 ] = aggTransType ;
70
84
if (aggBaseType == ANYOID )
71
- nargs = 1 ;
85
+ nargs_transfn = 1 ;
72
86
else
73
87
{
74
88
fnArgs [1 ] = aggBaseType ;
75
- nargs = 2 ;
89
+ nargs_transfn = 2 ;
76
90
}
77
- transfn = LookupFuncName (aggtransfnName , nargs , fnArgs );
78
- if (!OidIsValid (transfn ))
79
- func_error ("AggregateCreate" , aggtransfnName , nargs , fnArgs , NULL );
91
+ transfn = lookup_agg_function (aggtransfnName , nargs_transfn , fnArgs ,
92
+ & rettype );
93
+
94
+ /*
95
+ * Return type of transfn (possibly after refinement by
96
+ * enforce_generic_type_consistency, if transtype isn't polymorphic)
97
+ * must exactly match declared transtype.
98
+ *
99
+ * In the non-polymorphic-transtype case, it might be okay to allow
100
+ * a rettype that's binary-coercible to transtype, but I'm not quite
101
+ * convinced that it's either safe or useful. When transtype is
102
+ * polymorphic we *must* demand exact equality.
103
+ */
104
+ if (rettype != aggTransType )
105
+ elog (ERROR , "return type of transition function %s is not %s" ,
106
+ NameListToString (aggtransfnName ), format_type_be (aggTransType ));
107
+
80
108
tup = SearchSysCache (PROCOID ,
81
109
ObjectIdGetDatum (transfn ),
82
110
0 , 0 , 0 );
83
111
if (!HeapTupleIsValid (tup ))
84
- func_error ("AggregateCreate" , aggtransfnName , nargs , fnArgs , NULL );
112
+ func_error ("AggregateCreate" , aggtransfnName ,
113
+ nargs_transfn , fnArgs , NULL );
85
114
proc = (Form_pg_proc ) GETSTRUCT (tup );
86
- if (proc -> prorettype != aggTransType )
87
- elog (ERROR , "return type of transition function %s is not %s" ,
88
- NameListToString (aggtransfnName ), format_type_be (aggTransType ));
89
115
90
116
/*
91
117
* If the transfn is strict and the initval is NULL, make sure input
@@ -105,17 +131,8 @@ AggregateCreate(const char *aggName,
105
131
{
106
132
MemSet (fnArgs , 0 , FUNC_MAX_ARGS * sizeof (Oid ));
107
133
fnArgs [0 ] = aggTransType ;
108
- finalfn = LookupFuncName (aggfinalfnName , 1 , fnArgs );
109
- if (!OidIsValid (finalfn ))
110
- func_error ("AggregateCreate" , aggfinalfnName , 1 , fnArgs , NULL );
111
- tup = SearchSysCache (PROCOID ,
112
- ObjectIdGetDatum (finalfn ),
113
- 0 , 0 , 0 );
114
- if (!HeapTupleIsValid (tup ))
115
- func_error ("AggregateCreate" , aggfinalfnName , 1 , fnArgs , NULL );
116
- proc = (Form_pg_proc ) GETSTRUCT (tup );
117
- finaltype = proc -> prorettype ;
118
- ReleaseSysCache (tup );
134
+ finalfn = lookup_agg_function (aggfinalfnName , 1 , fnArgs ,
135
+ & finaltype );
119
136
}
120
137
else
121
138
{
@@ -126,6 +143,19 @@ AggregateCreate(const char *aggName,
126
143
}
127
144
Assert (OidIsValid (finaltype ));
128
145
146
+ /*
147
+ * If finaltype (i.e. aggregate return type) is polymorphic,
148
+ * basetype must be polymorphic also, else parser will fail to deduce
149
+ * result type. (Note: given the previous test on transtype and basetype,
150
+ * this cannot happen, unless someone has snuck a finalfn definition
151
+ * into the catalogs that itself violates the rule against polymorphic
152
+ * result with no polymorphic input.)
153
+ */
154
+ if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID ) &&
155
+ !(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID ))
156
+ elog (ERROR , "an aggregate returning ANYARRAY or ANYELEMENT "
157
+ "must also have one of them as its base type" );
158
+
129
159
/*
130
160
* Everything looks okay. Try to create the pg_proc entry for the
131
161
* aggregate. (This could fail if there's already a conflicting
@@ -207,3 +237,71 @@ AggregateCreate(const char *aggName,
207
237
recordDependencyOn (& myself , & referenced , DEPENDENCY_NORMAL );
208
238
}
209
239
}
240
+
241
+ /*
242
+ * lookup_agg_function -- common code for finding both transfn and finalfn
243
+ */
244
+ static Oid
245
+ lookup_agg_function (List * fnName ,
246
+ int nargs ,
247
+ Oid * input_types ,
248
+ Oid * rettype )
249
+ {
250
+ Oid fnOid ;
251
+ bool retset ;
252
+ Oid * true_oid_array ;
253
+ FuncDetailCode fdresult ;
254
+
255
+ /*
256
+ * func_get_detail looks up the function in the catalogs, does
257
+ * disambiguation for polymorphic functions, handles inheritance, and
258
+ * returns the funcid and type and set or singleton status of the
259
+ * function's return value. it also returns the true argument types
260
+ * to the function.
261
+ */
262
+ fdresult = func_get_detail (fnName , NIL , nargs , input_types ,
263
+ & fnOid , rettype , & retset ,
264
+ & true_oid_array );
265
+
266
+ /* only valid case is a normal function not returning a set */
267
+ if (fdresult != FUNCDETAIL_NORMAL ||
268
+ !OidIsValid (fnOid ) ||
269
+ retset )
270
+ func_error ("AggregateCreate" , fnName , nargs , input_types , NULL );
271
+
272
+ /*
273
+ * If the given type(s) are all polymorphic, there's nothing we
274
+ * can check. Otherwise, enforce consistency, and possibly refine
275
+ * the result type.
276
+ */
277
+ if ((input_types [0 ] == ANYARRAYOID || input_types [0 ] == ANYELEMENTOID ) &&
278
+ (nargs == 1 ||
279
+ (input_types [1 ] == ANYARRAYOID || input_types [1 ] == ANYELEMENTOID )))
280
+ {
281
+ /* nothing to check here */
282
+ }
283
+ else
284
+ {
285
+ * rettype = enforce_generic_type_consistency (input_types ,
286
+ true_oid_array ,
287
+ nargs ,
288
+ * rettype );
289
+ }
290
+
291
+ /*
292
+ * func_get_detail will find functions requiring run-time argument type
293
+ * coercion, but nodeAgg.c isn't prepared to deal with that
294
+ */
295
+ if (true_oid_array [0 ] != ANYARRAYOID &&
296
+ true_oid_array [0 ] != ANYELEMENTOID &&
297
+ !IsBinaryCoercible (input_types [0 ], true_oid_array [0 ]))
298
+ func_error ("AggregateCreate" , fnName , nargs , input_types , NULL );
299
+
300
+ if (nargs == 2 &&
301
+ true_oid_array [1 ] != ANYARRAYOID &&
302
+ true_oid_array [1 ] != ANYELEMENTOID &&
303
+ !IsBinaryCoercible (input_types [1 ], true_oid_array [1 ]))
304
+ func_error ("AggregateCreate" , fnName , nargs , input_types , NULL );
305
+
306
+ return fnOid ;
307
+ }
0 commit comments