1 /*-------------------------------------------------------------------------
4 * Functions for sets, which are defined by queries.
5 * Example: a set is defined as being the result of the query
8 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.51 2002/08/09 16:45:14 tgl Exp $
15 *-------------------------------------------------------------------------
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"
34 * SetDefine - converts query string defining set to an oid
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
41 SetDefine(char *querystr, Oid elemType)
44 char *procname = GENERICSETNAME;
46 char realprocname[NAMEDATALEN];
52 Datum replValue[Natts_pg_proc];
53 char replNull[Natts_pg_proc];
54 char repl[Natts_pg_proc];
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 */
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 */
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.)
79 CommandCounterIncrement();
81 procrel = heap_openr(ProcedureRelationName, RowExclusiveLock);
83 tup = SearchSysCache(PROCOID,
84 ObjectIdGetDatum(setoid),
86 if (!HeapTupleIsValid(tup))
87 elog(ERROR, "SetDefine: unable to define set %s", querystr);
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.
94 proc = (Form_pg_proc) GETSTRUCT(tup);
95 if (strcmp(procname, NameStr(proc->proname)) == 0)
97 /* make the real proc name */
98 sprintf(realprocname, "set%u", setoid);
100 /* set up the attributes to be modified or kept the same */
102 for (i = 1; i < Natts_pg_proc; 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++)
110 /* change the pg_proc tuple */
111 newtup = heap_modifytuple(tup,
117 simple_heap_update(procrel, &newtup->t_self, newtup);
119 AssertTupleDescHasOid(procrel->rd_att);
120 setoid = HeapTupleGetOid(newtup);
122 CatalogUpdateIndexes(procrel, newtup);
124 heap_freetuple(newtup);
127 ReleaseSysCache(tup);
129 heap_close(procrel, RowExclusiveLock);
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.
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.)
144 seteval(PG_FUNCTION_ARGS)
146 Oid funcoid = PG_GETARG_OID(0);
147 FunctionCachePtr fcache;
153 * If this is the first call, we need to set up the fcache for the
154 * target set's function.
156 fcache = (FunctionCachePtr) fcinfo->flinfo->fn_extra;
159 fcache = init_fcache(funcoid, 0, fcinfo->flinfo->fn_mcxt);
160 fcinfo->flinfo->fn_extra = (void *) fcache;
164 * Evaluate the function. NOTE: we need no econtext because there are
165 * no arguments to evaluate.
168 /* ExecMakeFunctionResult assumes these are initialized at call: */
170 isDone = ExprSingleResult;
172 result = ExecMakeFunctionResult(fcache,
174 NULL, /* no econtext, see above */
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...)
183 if (isDone != ExprMultipleResult)
186 fcinfo->flinfo->fn_extra = NULL;
190 * Return isNull/isDone status.
192 fcinfo->isnull = isNull;
194 if (isDone != ExprSingleResult)
196 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
198 if (rsi && IsA(rsi, ReturnSetInfo))
199 rsi->isDone = isDone;
201 elog(ERROR, "Set-valued function called in context that cannot accept a set");
204 PG_RETURN_DATUM(result);