1 /*-------------------------------------------------------------------------
3 * pl_handler.c - Handler for the PL/pgSQL
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.29 2006/05/30 22:12:16 tgl Exp $
13 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/pg_proc.h"
21 #include "catalog/pg_type.h"
23 #include "utils/builtins.h"
24 #include "utils/lsyscache.h"
25 #include "utils/syscache.h"
27 extern DLLIMPORT bool check_function_bodies;
31 static bool plpgsql_firstcall = true;
33 static void plpgsql_init_all(void);
37 * plpgsql_init() - postmaster-startup safe initialization
39 * DO NOT make this static --- it has to be callable by preload
44 /* Do initialization only once */
45 if (!plpgsql_firstcall)
48 plpgsql_HashTableInit();
49 RegisterXactCallback(plpgsql_xact_cb, NULL);
50 plpgsql_firstcall = false;
54 * plpgsql_init_all() - Initialize all
57 plpgsql_init_all(void)
59 /* Execute any postmaster-startup safe initialization */
63 * Any other initialization that must be done each time a new backend
64 * starts -- currently none
69 * plpgsql_call_handler
71 * The PostgreSQL function manager and trigger manager
72 * call this function for execution of PL/pgSQL procedures.
75 PG_FUNCTION_INFO_V1(plpgsql_call_handler);
78 plpgsql_call_handler(PG_FUNCTION_ARGS)
80 PLpgSQL_function *func;
84 /* perform initialization */
88 * Connect to SPI manager
90 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
91 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
93 /* Find or compile the function */
94 func = plpgsql_compile(fcinfo, false);
97 * Determine if called as function or trigger and call appropriate
100 if (CALLED_AS_TRIGGER(fcinfo))
101 retval = PointerGetDatum(plpgsql_exec_trigger(func,
102 (TriggerData *) fcinfo->context));
104 retval = plpgsql_exec_function(func, fcinfo);
107 * Disconnect from SPI manager
109 if ((rc = SPI_finish()) != SPI_OK_FINISH)
110 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
118 * This function attempts to validate a PL/pgSQL function at
119 * CREATE FUNCTION time.
122 PG_FUNCTION_INFO_V1(plpgsql_validator);
125 plpgsql_validator(PG_FUNCTION_ARGS)
127 Oid funcoid = PG_GETARG_OID(0);
135 bool istrigger = false;
138 /* perform initialization */
141 /* Get the new function's pg_proc entry */
142 tuple = SearchSysCache(PROCOID,
143 ObjectIdGetDatum(funcoid),
145 if (!HeapTupleIsValid(tuple))
146 elog(ERROR, "cache lookup failed for function %u", funcoid);
147 proc = (Form_pg_proc) GETSTRUCT(tuple);
149 functyptype = get_typtype(proc->prorettype);
151 /* Disallow pseudotype result */
152 /* except for TRIGGER, RECORD, VOID, ANYARRAY, or ANYELEMENT */
153 if (functyptype == 'p')
155 /* we assume OPAQUE with no arguments means a trigger */
156 if (proc->prorettype == TRIGGEROID ||
157 (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
159 else if (proc->prorettype != RECORDOID &&
160 proc->prorettype != VOIDOID &&
161 proc->prorettype != ANYARRAYOID &&
162 proc->prorettype != ANYELEMENTOID)
164 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
165 errmsg("plpgsql functions cannot return type %s",
166 format_type_be(proc->prorettype))));
169 /* Disallow pseudotypes in arguments (either IN or OUT) */
170 /* except for ANYARRAY or ANYELEMENT */
171 numargs = get_func_arg_info(tuple,
172 &argtypes, &argnames, &argmodes);
173 for (i = 0; i < numargs; i++)
175 if (get_typtype(argtypes[i]) == 'p')
177 if (argtypes[i] != ANYARRAYOID &&
178 argtypes[i] != ANYELEMENTOID)
180 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
181 errmsg("plpgsql functions cannot take type %s",
182 format_type_be(argtypes[i]))));
186 /* Postpone body checks if !check_function_bodies */
187 if (check_function_bodies)
189 FunctionCallInfoData fake_fcinfo;
191 TriggerData trigdata;
195 * Connect to SPI manager (is this needed for compilation?)
197 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
198 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
201 * Set up a fake fcinfo with just enough info to satisfy
204 MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
205 MemSet(&flinfo, 0, sizeof(flinfo));
206 fake_fcinfo.flinfo = &flinfo;
207 flinfo.fn_oid = funcoid;
208 flinfo.fn_mcxt = CurrentMemoryContext;
211 MemSet(&trigdata, 0, sizeof(trigdata));
212 trigdata.type = T_TriggerData;
213 fake_fcinfo.context = (Node *) &trigdata;
216 /* Test-compile the function */
217 plpgsql_compile(&fake_fcinfo, true);
220 * Disconnect from SPI manager
222 if ((rc = SPI_finish()) != SPI_OK_FINISH)
223 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
226 ReleaseSysCache(tuple);