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