1 /*-------------------------------------------------------------------------
3 * pl_handler.c - Handler for the PL/pgSQL
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/pl/plpgsql/src/pl_handler.c
13 *-------------------------------------------------------------------------
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.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"
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},
37 int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
39 /* Hook for plugins */
40 PLpgSQL_plugin **plugin_ptr = NULL;
44 * _PG_init() - library load-time initialization
46 * DO NOT make this static nor change its name!
51 /* Be sure we do initialization only once (should be redundant now) */
52 static bool inited = false;
57 pg_bindtextdomain(TEXTDOMAIN);
59 DefineCustomEnumVariable("plpgsql.variable_conflict",
60 gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
62 &plpgsql_variable_conflict,
63 PLPGSQL_RESOLVE_ERROR,
64 variable_conflict_options,
68 EmitWarningsOnPlaceholders("plpgsql");
70 plpgsql_HashTableInit();
71 RegisterXactCallback(plpgsql_xact_cb, NULL);
72 RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
74 /* Set up a rendezvous point with optional instrumentation plugin */
75 plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
81 * plpgsql_call_handler
83 * The PostgreSQL function manager and trigger manager
84 * call this function for execution of PL/pgSQL procedures.
87 PG_FUNCTION_INFO_V1(plpgsql_call_handler);
90 plpgsql_call_handler(PG_FUNCTION_ARGS)
92 PLpgSQL_function *func;
93 PLpgSQL_execstate *save_cur_estate;
98 * Connect to SPI manager
100 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
101 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
103 /* Find or compile the function */
104 func = plpgsql_compile(fcinfo, false);
106 /* Must save and restore prior value of cur_estate */
107 save_cur_estate = func->cur_estate;
109 /* Mark the function as busy, so it can't be deleted from under us */
115 * Determine if called as function or trigger and call appropriate
118 if (CALLED_AS_TRIGGER(fcinfo))
119 retval = PointerGetDatum(plpgsql_exec_trigger(func,
120 (TriggerData *) fcinfo->context));
122 retval = plpgsql_exec_function(func, fcinfo);
126 /* Decrement use-count, restore cur_estate, and propagate error */
128 func->cur_estate = save_cur_estate;
135 func->cur_estate = save_cur_estate;
138 * Disconnect from SPI manager
140 if ((rc = SPI_finish()) != SPI_OK_FINISH)
141 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
147 * plpgsql_inline_handler
149 * Called by PostgreSQL to execute an anonymous code block
152 PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
155 plpgsql_inline_handler(PG_FUNCTION_ARGS)
157 InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
158 PLpgSQL_function *func;
159 FunctionCallInfoData fake_fcinfo;
164 Assert(IsA(codeblock, InlineCodeBlock));
167 * Connect to SPI manager
169 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
170 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
172 /* Compile the anonymous code block */
173 func = plpgsql_compile_inline(codeblock->source_text);
175 /* Mark the function as busy, just pro forma */
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.
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;
189 retval = plpgsql_exec_function(func, &fake_fcinfo);
191 /* Function should now have no remaining use-counts ... */
193 Assert(func->use_count == 0);
195 /* ... so we can free subsidiary storage */
196 plpgsql_free_function_memory(func);
199 * Disconnect from SPI manager
201 if ((rc = SPI_finish()) != SPI_OK_FINISH)
202 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
210 * This function attempts to validate a PL/pgSQL function at
211 * CREATE FUNCTION time.
214 PG_FUNCTION_INFO_V1(plpgsql_validator);
217 plpgsql_validator(PG_FUNCTION_ARGS)
219 Oid funcoid = PG_GETARG_OID(0);
227 bool istrigger = false;
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);
236 functyptype = get_typtype(proc->prorettype);
238 /* Disallow pseudotype result */
239 /* except for TRIGGER, RECORD, VOID, or polymorphic */
240 if (functyptype == TYPTYPE_PSEUDO)
242 /* we assume OPAQUE with no arguments means a trigger */
243 if (proc->prorettype == TRIGGEROID ||
244 (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
246 else if (proc->prorettype != RECORDOID &&
247 proc->prorettype != VOIDOID &&
248 !IsPolymorphicType(proc->prorettype))
250 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
251 errmsg("PL/pgSQL functions cannot return type %s",
252 format_type_be(proc->prorettype))));
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++)
261 if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
263 if (!IsPolymorphicType(argtypes[i]))
265 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
266 errmsg("PL/pgSQL functions cannot accept type %s",
267 format_type_be(argtypes[i]))));
271 /* Postpone body checks if !check_function_bodies */
272 if (check_function_bodies)
274 FunctionCallInfoData fake_fcinfo;
276 TriggerData trigdata;
280 * Connect to SPI manager (is this needed for compilation?)
282 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
283 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
286 * Set up a fake fcinfo with just enough info to satisfy
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;
296 MemSet(&trigdata, 0, sizeof(trigdata));
297 trigdata.type = T_TriggerData;
298 fake_fcinfo.context = (Node *) &trigdata;
301 /* Test-compile the function */
302 plpgsql_compile(&fake_fcinfo, true);
305 * Disconnect from SPI manager
307 if ((rc = SPI_finish()) != SPI_OK_FINISH)
308 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
311 ReleaseSysCache(tuple);