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