]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_handler.c
e6e71432ff9ae72e43c402a4873446234dc7d7da
[postgresql] / src / pl / plpgsql / src / pl_handler.c
1 /*-------------------------------------------------------------------------
2  *
3  * pl_handler.c         - Handler for the PL/pgSQL
4  *                        procedural language
5  *
6  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/pl/plpgsql/src/pl_handler.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "plpgsql.h"
17
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "funcapi.h"
21 #include "miscadmin.h"
22 #include "utils/builtins.h"
23 #include "utils/guc.h"
24 #include "utils/lsyscache.h"
25 #include "utils/syscache.h"
26
27 PG_MODULE_MAGIC;
28
29 /* Custom GUC variable */
30 static const struct config_enum_entry variable_conflict_options[] = {
31         {"error", PLPGSQL_RESOLVE_ERROR, false},
32         {"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
33         {"use_column", PLPGSQL_RESOLVE_COLUMN, false},
34         {NULL, 0, false}
35 };
36
37 int                     plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
38
39 /* Hook for plugins */
40 PLpgSQL_plugin **plugin_ptr = NULL;
41
42
43 /*
44  * _PG_init()                   - library load-time initialization
45  *
46  * DO NOT make this static nor change its name!
47  */
48 void
49 _PG_init(void)
50 {
51         /* Be sure we do initialization only once (should be redundant now) */
52         static bool inited = false;
53
54         if (inited)
55                 return;
56
57         pg_bindtextdomain(TEXTDOMAIN);
58
59         DefineCustomEnumVariable("plpgsql.variable_conflict",
60                                                          gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
61                                                          NULL,
62                                                          &plpgsql_variable_conflict,
63                                                          PLPGSQL_RESOLVE_ERROR,
64                                                          variable_conflict_options,
65                                                          PGC_SUSET, 0,
66                                                          NULL, NULL, NULL);
67
68         EmitWarningsOnPlaceholders("plpgsql");
69
70         plpgsql_HashTableInit();
71         RegisterXactCallback(plpgsql_xact_cb, NULL);
72         RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
73
74         /* Set up a rendezvous point with optional instrumentation plugin */
75         plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
76
77         inited = true;
78 }
79
80 /* ----------
81  * plpgsql_call_handler
82  *
83  * The PostgreSQL function manager and trigger manager
84  * call this function for execution of PL/pgSQL procedures.
85  * ----------
86  */
87 PG_FUNCTION_INFO_V1(plpgsql_call_handler);
88
89 Datum
90 plpgsql_call_handler(PG_FUNCTION_ARGS)
91 {
92         PLpgSQL_function *func;
93         PLpgSQL_execstate *save_cur_estate;
94         Datum           retval;
95         int                     rc;
96
97         /*
98          * Connect to SPI manager
99          */
100         if ((rc = SPI_connect()) != SPI_OK_CONNECT)
101                 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
102
103         /* Find or compile the function */
104         func = plpgsql_compile(fcinfo, false);
105
106         /* Must save and restore prior value of cur_estate */
107         save_cur_estate = func->cur_estate;
108
109         /* Mark the function as busy, so it can't be deleted from under us */
110         func->use_count++;
111
112         PG_TRY();
113         {
114                 /*
115                  * Determine if called as function or trigger and call appropriate
116                  * subhandler
117                  */
118                 if (CALLED_AS_TRIGGER(fcinfo))
119                         retval = PointerGetDatum(plpgsql_exec_trigger(func,
120                                                                                    (TriggerData *) fcinfo->context));
121                 else
122                         retval = plpgsql_exec_function(func, fcinfo);
123         }
124         PG_CATCH();
125         {
126                 /* Decrement use-count, restore cur_estate, and propagate error */
127                 func->use_count--;
128                 func->cur_estate = save_cur_estate;
129                 PG_RE_THROW();
130         }
131         PG_END_TRY();
132
133         func->use_count--;
134
135         func->cur_estate = save_cur_estate;
136
137         /*
138          * Disconnect from SPI manager
139          */
140         if ((rc = SPI_finish()) != SPI_OK_FINISH)
141                 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
142
143         return retval;
144 }
145
146 /* ----------
147  * plpgsql_inline_handler
148  *
149  * Called by PostgreSQL to execute an anonymous code block
150  * ----------
151  */
152 PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
153
154 Datum
155 plpgsql_inline_handler(PG_FUNCTION_ARGS)
156 {
157         InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
158         PLpgSQL_function *func;
159         FunctionCallInfoData fake_fcinfo;
160         FmgrInfo        flinfo;
161         Datum           retval;
162         int                     rc;
163
164         Assert(IsA(codeblock, InlineCodeBlock));
165
166         /*
167          * Connect to SPI manager
168          */
169         if ((rc = SPI_connect()) != SPI_OK_CONNECT)
170                 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
171
172         /* Compile the anonymous code block */
173         func = plpgsql_compile_inline(codeblock->source_text);
174
175         /* Mark the function as busy, just pro forma */
176         func->use_count++;
177
178         /*
179          * Set up a fake fcinfo with just enough info to satisfy
180          * plpgsql_exec_function().  In particular note that this sets things up
181          * with no arguments passed.
182          */
183         MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
184         MemSet(&flinfo, 0, sizeof(flinfo));
185         fake_fcinfo.flinfo = &flinfo;
186         flinfo.fn_oid = InvalidOid;
187         flinfo.fn_mcxt = CurrentMemoryContext;
188
189         retval = plpgsql_exec_function(func, &fake_fcinfo);
190
191         /* Function should now have no remaining use-counts ... */
192         func->use_count--;
193         Assert(func->use_count == 0);
194
195         /* ... so we can free subsidiary storage */
196         plpgsql_free_function_memory(func);
197
198         /*
199          * Disconnect from SPI manager
200          */
201         if ((rc = SPI_finish()) != SPI_OK_FINISH)
202                 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
203
204         return retval;
205 }
206
207 /* ----------
208  * plpgsql_validator
209  *
210  * This function attempts to validate a PL/pgSQL function at
211  * CREATE FUNCTION time.
212  * ----------
213  */
214 PG_FUNCTION_INFO_V1(plpgsql_validator);
215
216 Datum
217 plpgsql_validator(PG_FUNCTION_ARGS)
218 {
219         Oid                     funcoid = PG_GETARG_OID(0);
220         HeapTuple       tuple;
221         Form_pg_proc proc;
222         char            functyptype;
223         int                     numargs;
224         Oid                *argtypes;
225         char      **argnames;
226         char       *argmodes;
227         bool            istrigger = false;
228         int                     i;
229
230         /* Get the new function's pg_proc entry */
231         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
232         if (!HeapTupleIsValid(tuple))
233                 elog(ERROR, "cache lookup failed for function %u", funcoid);
234         proc = (Form_pg_proc) GETSTRUCT(tuple);
235
236         functyptype = get_typtype(proc->prorettype);
237
238         /* Disallow pseudotype result */
239         /* except for TRIGGER, RECORD, VOID, or polymorphic */
240         if (functyptype == TYPTYPE_PSEUDO)
241         {
242                 /* we assume OPAQUE with no arguments means a trigger */
243                 if (proc->prorettype == TRIGGEROID ||
244                         (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
245                         istrigger = true;
246                 else if (proc->prorettype != RECORDOID &&
247                                  proc->prorettype != VOIDOID &&
248                                  !IsPolymorphicType(proc->prorettype))
249                         ereport(ERROR,
250                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
251                                          errmsg("PL/pgSQL functions cannot return type %s",
252                                                         format_type_be(proc->prorettype))));
253         }
254
255         /* Disallow pseudotypes in arguments (either IN or OUT) */
256         /* except for polymorphic */
257         numargs = get_func_arg_info(tuple,
258                                                                 &argtypes, &argnames, &argmodes);
259         for (i = 0; i < numargs; i++)
260         {
261                 if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
262                 {
263                         if (!IsPolymorphicType(argtypes[i]))
264                                 ereport(ERROR,
265                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
266                                                  errmsg("PL/pgSQL functions cannot accept type %s",
267                                                                 format_type_be(argtypes[i]))));
268                 }
269         }
270
271         /* Postpone body checks if !check_function_bodies */
272         if (check_function_bodies)
273         {
274                 FunctionCallInfoData fake_fcinfo;
275                 FmgrInfo        flinfo;
276                 TriggerData trigdata;
277                 int                     rc;
278
279                 /*
280                  * Connect to SPI manager (is this needed for compilation?)
281                  */
282                 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
283                         elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
284
285                 /*
286                  * Set up a fake fcinfo with just enough info to satisfy
287                  * plpgsql_compile().
288                  */
289                 MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
290                 MemSet(&flinfo, 0, sizeof(flinfo));
291                 fake_fcinfo.flinfo = &flinfo;
292                 flinfo.fn_oid = funcoid;
293                 flinfo.fn_mcxt = CurrentMemoryContext;
294                 if (istrigger)
295                 {
296                         MemSet(&trigdata, 0, sizeof(trigdata));
297                         trigdata.type = T_TriggerData;
298                         fake_fcinfo.context = (Node *) &trigdata;
299                 }
300
301                 /* Test-compile the function */
302                 plpgsql_compile(&fake_fcinfo, true);
303
304                 /*
305                  * Disconnect from SPI manager
306                  */
307                 if ((rc = SPI_finish()) != SPI_OK_FINISH)
308                         elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
309         }
310
311         ReleaseSysCache(tuple);
312
313         PG_RETURN_VOID();
314 }