]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/sets.c
0cd3b766472945004a7500be0fa490d48615a34e
[postgresql] / src / backend / utils / adt / sets.c
1 /*-------------------------------------------------------------------------
2  *
3  * sets.c
4  *        Functions for sets, which are defined by queries.
5  *        Example:       a set is defined as being the result of the query
6  *                      retrieve (X.all)
7  *
8  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.39 2001/10/02 21:39:35 tgl Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17
18 #include "postgres.h"
19
20 #include "access/heapam.h"
21 #include "catalog/catname.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_proc.h"
24 #include "executor/executor.h"
25 #include "utils/fcache.h"
26 #include "utils/sets.h"
27 #include "utils/syscache.h"
28
29
30 /*
31  *        SetDefine                - converts query string defining set to an oid
32  *
33  *        We create an SQL function having the given querystring as its body.
34  *        The name of the function is then changed to use the OID of its tuple
35  *        in pg_proc.
36  */
37 Oid
38 SetDefine(char *querystr, char *typename)
39 {
40         Oid                     setoid;
41         char       *procname = GENERICSETNAME;
42         char       *fileName = "-";
43         char            realprocname[NAMEDATALEN];
44         HeapTuple       tup,
45                                 newtup = NULL;
46         Form_pg_proc proc;
47         Relation        procrel;
48         int                     i;
49         Datum           replValue[Natts_pg_proc];
50         char            replNull[Natts_pg_proc];
51         char            repl[Natts_pg_proc];
52
53         setoid = ProcedureCreate(procname,      /* changed below, after oid known */
54                                                          false,         /* don't replace */
55                                                          true,          /* returnsSet */
56                                                          typename,      /* returnTypeName */
57                                                          "sql",         /* languageName */
58                                                          querystr,      /* sourceCode */
59                                                          fileName,      /* fileName */
60                                                          true,          /* trusted */
61                                                          false,         /* canCache (assume unsafe) */
62                                                          false,         /* isStrict (irrelevant, no args) */
63                                                          100,           /* byte_pct */
64                                                          0, /* perbyte_cpu */
65                                                          0, /* percall_cpu */
66                                                          100,           /* outin_ratio */
67                                                          NIL);          /* argList */
68
69         /*
70          * Since we're still inside this command of the transaction, we can't
71          * see the results of the procedure definition unless we pretend we've
72          * started the next command.  (Postgres's solution to the Halloween
73          * problem is to not allow you to see the results of your command
74          * until you start the next command.)
75          */
76         CommandCounterIncrement();
77
78         procrel = heap_openr(ProcedureRelationName, RowExclusiveLock);
79
80         tup = SearchSysCache(PROCOID,
81                                                  ObjectIdGetDatum(setoid),
82                                                  0, 0, 0);
83         if (!HeapTupleIsValid(tup))
84                 elog(ERROR, "SetDefine: unable to define set %s", querystr);
85
86         /*
87          * We can tell whether the set was already defined by checking the
88          * name.   If it's GENERICSETNAME, the set is new.  If it's "set<some
89          * oid>" it's already defined.
90          */
91         proc = (Form_pg_proc) GETSTRUCT(tup);
92         if (strcmp(procname, NameStr(proc->proname)) == 0)
93         {
94                 /* make the real proc name */
95                 sprintf(realprocname, "set%u", setoid);
96
97                 /* set up the attributes to be modified or kept the same */
98                 repl[0] = 'r';
99                 for (i = 1; i < Natts_pg_proc; i++)
100                         repl[i] = ' ';
101                 replValue[0] = (Datum) realprocname;
102                 for (i = 1; i < Natts_pg_proc; i++)
103                         replValue[i] = (Datum) 0;
104                 for (i = 0; i < Natts_pg_proc; i++)
105                         replNull[i] = ' ';
106
107                 /* change the pg_proc tuple */
108                 newtup = heap_modifytuple(tup,
109                                                                   procrel,
110                                                                   replValue,
111                                                                   replNull,
112                                                                   repl);
113
114                 simple_heap_update(procrel, &newtup->t_self, newtup);
115
116                 setoid = newtup->t_data->t_oid;
117
118                 if (RelationGetForm(procrel)->relhasindex)
119                 {
120                         Relation        idescs[Num_pg_proc_indices];
121
122                         CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
123                         CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
124                         CatalogCloseIndices(Num_pg_proc_indices, idescs);
125                 }
126                 heap_freetuple(newtup);
127         }
128
129         ReleaseSysCache(tup);
130
131         heap_close(procrel, RowExclusiveLock);
132
133         return setoid;
134 }
135
136 /*
137  * This function executes set evaluation.  The parser sets up a set reference
138  * as a call to this function with the OID of the set to evaluate as argument.
139  *
140  * We build a new fcache for execution of the set's function and run the
141  * function until it says "no mas".  The fn_extra field of the call's
142  * FmgrInfo record is a handy place to hold onto the fcache.  (Since this
143  * is a built-in function, there is no competing use of fn_extra.)
144  */
145 Datum
146 seteval(PG_FUNCTION_ARGS)
147 {
148         Oid                     funcoid = PG_GETARG_OID(0);
149         FunctionCachePtr fcache;
150         Datum           result;
151         bool            isNull;
152         ExprDoneCond isDone;
153
154         /*
155          * If this is the first call, we need to set up the fcache for the
156          * target set's function.
157          */
158         fcache = (FunctionCachePtr) fcinfo->flinfo->fn_extra;
159         if (fcache == NULL)
160         {
161                 fcache = init_fcache(funcoid, 0, fcinfo->flinfo->fn_mcxt);
162                 fcinfo->flinfo->fn_extra = (void *) fcache;
163         }
164
165         /*
166          * Evaluate the function.  NOTE: we need no econtext because there are
167          * no arguments to evaluate.
168          */
169
170         /* ExecMakeFunctionResult assumes these are initialized at call: */
171         isNull = false;
172         isDone = ExprSingleResult;
173
174         result = ExecMakeFunctionResult(fcache,
175                                                                         NIL,
176                                                                         NULL,           /* no econtext, see above */
177                                                                         &isNull,
178                                                                         &isDone);
179
180         /*
181          * If we're done with the results of this set function, get rid of its
182          * func cache so that we will start from the top next time. (Can you
183          * say "memory leak"?  This feature is a crock anyway...)
184          */
185         if (isDone != ExprMultipleResult)
186         {
187                 pfree(fcache);
188                 fcinfo->flinfo->fn_extra = NULL;
189         }
190
191         /*
192          * Return isNull/isDone status.
193          */
194         fcinfo->isnull = isNull;
195
196         if (isDone != ExprSingleResult)
197         {
198                 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
199
200                 if (rsi && IsA(rsi, ReturnSetInfo))
201                         rsi->isDone = isDone;
202                 else
203                         elog(ERROR, "Set-valued function called in context that cannot accept a set");
204         }
205
206         PG_RETURN_DATUM(result);
207 }