]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_aggregate.c
Change #include's to use <> and "" as appropriate.
[postgresql] / src / backend / catalog / pg_aggregate.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_aggregate.c
4  *        routines to support manipulation of the pg_aggregate relation
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.22 1999/07/15 23:03:04 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "access/heapam.h"
17 #include "utils/builtins.h"
18 #include "catalog/catname.h"
19 #include "utils/syscache.h"
20 #include "catalog/pg_proc.h"
21 #include "catalog/pg_type.h"
22 #include "catalog/pg_aggregate.h"
23 #include "miscadmin.h"
24 #ifndef HAVE_MEMMOVE
25 #else
26 #include <string.h>
27 #endif
28
29 /* ----------------
30  * AggregateCreate
31  *
32  * aggregates overloading has been added.  Instead of the full
33  * overload support we have for functions, aggregate overloading only
34  * applies to exact basetype matches.  That is, we don't check the
35  * the inheritance hierarchy
36  *
37  * OLD COMMENTS:
38  *              Currently, redefining aggregates using the same name is not
39  *              supported.      In such a case, a warning is printed that the
40  *              aggregate already exists.  If such is not the case, a new tuple
41  *              is created and inserted in the aggregate relation.      The fields
42  *              of this tuple are aggregate name, owner id, 2 transition functions
43  *              (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
44  *              type of data on which aggtransfn1 operates (aggbasetype), return
45  *              types of the two transition functions (aggtranstype1 and
46  *              aggtranstype2), final return type (aggfinaltype), and initial values
47  *              for the two state transition functions (agginitval1 and agginitval2).
48  *              All types and functions must have been defined
49  *              prior to defining the aggregate.
50  *
51  * ---------------
52  */
53 void
54 AggregateCreate(char *aggName,
55                                 char *aggtransfn1Name,
56                                 char *aggtransfn2Name,
57                                 char *aggfinalfnName,
58                                 char *aggbasetypeName,
59                                 char *aggtransfn1typeName,
60                                 char *aggtransfn2typeName,
61                                 char *agginitval1,
62                                 char *agginitval2)
63 {
64         int                     i;
65         Relation        aggdesc;
66         HeapTuple       tup;
67         char            nulls[Natts_pg_aggregate];
68         Datum           values[Natts_pg_aggregate];
69         Form_pg_proc proc;
70         Oid                     xfn1 = InvalidOid;
71         Oid                     xfn2 = InvalidOid;
72         Oid                     ffn = InvalidOid;
73         Oid                     xbase = InvalidOid;
74         Oid                     xret1 = InvalidOid;
75         Oid                     xret2 = InvalidOid;
76         Oid                     fret = InvalidOid;
77         Oid                     fnArgs[8];
78         NameData        aname;
79         TupleDesc       tupDesc;
80
81         MemSet(fnArgs, 0, 8 * sizeof(Oid));
82
83         /* sanity checks */
84         if (!aggName)
85                 elog(ERROR, "AggregateCreate: no aggregate name supplied");
86
87         if (!aggtransfn1Name && !aggtransfn2Name)
88                 elog(ERROR, "AggregateCreate: aggregate must have at least one transition function");
89
90         tup = SearchSysCacheTuple(TYPNAME,
91                                                           PointerGetDatum(aggbasetypeName),
92                                                           0, 0, 0);
93         if (!HeapTupleIsValid(tup))
94                 elog(ERROR, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
95         xbase = tup->t_data->t_oid;
96
97         if (aggtransfn1Name)
98         {
99                 tup = SearchSysCacheTuple(TYPNAME,
100                                                                   PointerGetDatum(aggtransfn1typeName),
101                                                                   0, 0, 0);
102                 if (!HeapTupleIsValid(tup))
103                         elog(ERROR, "AggregateCreate: Type '%s' undefined",
104                                  aggtransfn1typeName);
105                 xret1 = tup->t_data->t_oid;
106
107                 fnArgs[0] = xret1;
108                 fnArgs[1] = xbase;
109                 tup = SearchSysCacheTuple(PRONAME,
110                                                                   PointerGetDatum(aggtransfn1Name),
111                                                                   Int32GetDatum(2),
112                                                                   PointerGetDatum(fnArgs),
113                                                                   0);
114                 if (!HeapTupleIsValid(tup))
115                         elog(ERROR, "AggregateCreate: '%s('%s', '%s') does not exist",
116                                  aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
117                 if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
118                         elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
119                                  aggtransfn1Name,
120                                  aggtransfn1typeName);
121                 xfn1 = tup->t_data->t_oid;
122                 if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
123                         !OidIsValid(xbase))
124                         elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
125         }
126
127         if (aggtransfn2Name)
128         {
129                 tup = SearchSysCacheTuple(TYPNAME,
130                                                                   PointerGetDatum(aggtransfn2typeName),
131                                                                   0, 0, 0);
132                 if (!HeapTupleIsValid(tup))
133                         elog(ERROR, "AggregateCreate: Type '%s' undefined",
134                                  aggtransfn2typeName);
135                 xret2 = tup->t_data->t_oid;
136
137                 fnArgs[0] = xret2;
138                 fnArgs[1] = 0;
139                 tup = SearchSysCacheTuple(PRONAME,
140                                                                   PointerGetDatum(aggtransfn2Name),
141                                                                   Int32GetDatum(1),
142                                                                   PointerGetDatum(fnArgs),
143                                                                   0);
144                 if (!HeapTupleIsValid(tup))
145                         elog(ERROR, "AggregateCreate: '%s'('%s') does not exist",
146                                  aggtransfn2Name, aggtransfn2typeName);
147                 if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
148                         elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
149                                  aggtransfn2Name, aggtransfn2typeName);
150                 xfn2 = tup->t_data->t_oid;
151                 if (!OidIsValid(xfn2) || !OidIsValid(xret2))
152                         elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
153         }
154
155         tup = SearchSysCacheTuple(AGGNAME,
156                                                           PointerGetDatum(aggName),
157                                                           ObjectIdGetDatum(xbase),
158                                                           0, 0);
159         if (HeapTupleIsValid(tup))
160                 elog(ERROR,
161                          "AggregateCreate: aggregate '%s' with base type '%s' already exists",
162                          aggName, aggbasetypeName);
163
164         /* more sanity checks */
165         if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
166                 elog(ERROR, "AggregateCreate: Aggregate must have final function with both transition functions");
167
168         if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
169                 elog(ERROR, "AggregateCreate: Aggregate cannot have final function without both transition functions");
170
171         if (aggfinalfnName)
172         {
173                 fnArgs[0] = xret1;
174                 fnArgs[1] = xret2;
175                 tup = SearchSysCacheTuple(PRONAME,
176                                                                   PointerGetDatum(aggfinalfnName),
177                                                                   Int32GetDatum(2),
178                                                                   PointerGetDatum(fnArgs),
179                                                                   0);
180                 if (!HeapTupleIsValid(tup))
181                         elog(ERROR, "AggregateCreate: '%s'('%s','%s') does not exist",
182                            aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
183                 ffn = tup->t_data->t_oid;
184                 proc = (Form_pg_proc) GETSTRUCT(tup);
185                 fret = proc->prorettype;
186                 if (!OidIsValid(ffn) || !OidIsValid(fret))
187                         elog(ERROR, "AggregateCreate: bogus function '%s'", aggfinalfnName);
188         }
189
190         /*
191          * If transition function 2 is defined, it must have an initial value,
192          * whereas transition function 1 does not, which allows man and min
193          * aggregates to return NULL if they are evaluated on empty sets.
194          */
195         if (OidIsValid(xfn2) && !agginitval2)
196                 elog(ERROR, "AggregateCreate: transition function 2 MUST have an initial value");
197
198         /* initialize nulls and values */
199         for (i = 0; i < Natts_pg_aggregate; i++)
200         {
201                 nulls[i] = ' ';
202                 values[i] = (Datum) NULL;
203         }
204         namestrcpy(&aname, aggName);
205         values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
206         values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
207         values[Anum_pg_aggregate_aggtransfn1 - 1] = ObjectIdGetDatum(xfn1);
208         values[Anum_pg_aggregate_aggtransfn2 - 1] = ObjectIdGetDatum(xfn2);
209         values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(ffn);
210
211         values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(xbase);
212         if (!OidIsValid(xfn1))
213         {
214                 values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(InvalidOid);
215                 values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
216                 values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret2);
217         }
218         else if (!OidIsValid(xfn2))
219         {
220                 values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
221                 values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(InvalidOid);
222                 values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(xret1);
223         }
224         else
225         {
226                 values[Anum_pg_aggregate_aggtranstype1 - 1] = ObjectIdGetDatum(xret1);
227                 values[Anum_pg_aggregate_aggtranstype2 - 1] = ObjectIdGetDatum(xret2);
228                 values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(fret);
229         }
230
231         if (agginitval1)
232                 values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));
233         else
234                 nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
235
236         if (agginitval2)
237                 values[Anum_pg_aggregate_agginitval2 - 1] = PointerGetDatum(textin(agginitval2));
238         else
239                 nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
240
241         if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
242                 elog(ERROR, "AggregateCreate: could not open '%s'",
243                          AggregateRelationName);
244
245         tupDesc = aggdesc->rd_att;
246         if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
247                                                                                            values,
248                                                                                            nulls)))
249                 elog(ERROR, "AggregateCreate: heap_formtuple failed");
250         if (!OidIsValid(heap_insert(aggdesc, tup)))
251                 elog(ERROR, "AggregateCreate: heap_insert failed");
252         heap_close(aggdesc);
253
254 }
255
256 char *
257 AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
258 {
259         HeapTuple       tup;
260         Relation        aggRel;
261         int                     initValAttno;
262         Oid                     transtype;
263         text       *textInitVal;
264         char       *strInitVal,
265                            *initVal;
266
267         Assert(PointerIsValid(aggName));
268         Assert(PointerIsValid(isNull));
269         Assert(xfuncno == 1 || xfuncno == 2);
270
271         tup = SearchSysCacheTuple(AGGNAME,
272                                                           PointerGetDatum(aggName),
273                                                           ObjectIdGetDatum(basetype),
274                                                           0, 0);
275         if (!HeapTupleIsValid(tup))
276                 elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
277                          aggName);
278         if (xfuncno == 1)
279         {
280                 transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
281                 initValAttno = Anum_pg_aggregate_agginitval1;
282         }
283         else
284                 /* can only be 1 or 2 */
285         {
286                 transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
287                 initValAttno = Anum_pg_aggregate_agginitval2;
288         }
289
290         aggRel = heap_openr(AggregateRelationName);
291         if (!RelationIsValid(aggRel))
292                 elog(ERROR, "AggNameGetInitVal: could not open \"%-.*s\"",
293                          AggregateRelationName);
294
295         /*
296          * must use fastgetattr in case one or other of the init values is
297          * NULL
298          */
299         textInitVal = (text *) fastgetattr(tup, initValAttno,
300                                                                            RelationGetDescr(aggRel),
301                                                                            isNull);
302         if (!PointerIsValid(textInitVal))
303                 *isNull = true;
304         if (*isNull)
305         {
306                 heap_close(aggRel);
307                 return (char *) NULL;
308         }
309         strInitVal = textout(textInitVal);
310         heap_close(aggRel);
311
312         tup = SearchSysCacheTuple(TYPOID,
313                                                           ObjectIdGetDatum(transtype),
314                                                           0, 0, 0);
315         if (!HeapTupleIsValid(tup))
316         {
317                 pfree(strInitVal);
318                 elog(ERROR, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
319         }
320         initVal = fmgr(((Form_pg_type) GETSTRUCT(tup))->typinput, strInitVal, -1);
321         pfree(strInitVal);
322         return initVal;
323 }