2 * PL/Python main entry points
4 * src/pl/plpython/plpy_main.c
9 #include "access/htup_details.h"
10 #include "catalog/pg_proc.h"
11 #include "catalog/pg_type.h"
12 #include "commands/trigger.h"
13 #include "executor/spi.h"
14 #include "miscadmin.h"
15 #include "utils/guc.h"
16 #include "utils/memutils.h"
17 #include "utils/rel.h"
18 #include "utils/syscache.h"
22 #include "plpy_main.h"
24 #include "plpy_elog.h"
25 #include "plpy_exec.h"
26 #include "plpy_plpymodule.h"
27 #include "plpy_procedure.h"
28 #include "plpy_subxactobject.h"
35 #if PY_MAJOR_VERSION >= 3
36 /* Use separate names to avoid clash in pg_pltemplate */
37 #define plpython_validator plpython3_validator
38 #define plpython_call_handler plpython3_call_handler
39 #define plpython_inline_handler plpython3_inline_handler
42 extern void _PG_init(void);
43 extern Datum plpython_validator(PG_FUNCTION_ARGS);
44 extern Datum plpython_call_handler(PG_FUNCTION_ARGS);
45 extern Datum plpython_inline_handler(PG_FUNCTION_ARGS);
47 #if PY_MAJOR_VERSION < 3
48 /* Define aliases plpython2_call_handler etc */
49 extern Datum plpython2_validator(PG_FUNCTION_ARGS);
50 extern Datum plpython2_call_handler(PG_FUNCTION_ARGS);
51 extern Datum plpython2_inline_handler(PG_FUNCTION_ARGS);
56 PG_FUNCTION_INFO_V1(plpython_validator);
57 PG_FUNCTION_INFO_V1(plpython_call_handler);
58 PG_FUNCTION_INFO_V1(plpython_inline_handler);
60 #if PY_MAJOR_VERSION < 3
61 PG_FUNCTION_INFO_V1(plpython2_validator);
62 PG_FUNCTION_INFO_V1(plpython2_call_handler);
63 PG_FUNCTION_INFO_V1(plpython2_inline_handler);
67 static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
68 static void plpython_error_callback(void *arg);
69 static void plpython_inline_error_callback(void *arg);
70 static void PLy_init_interp(void);
72 static PLyExecutionContext *PLy_push_execution_context(void);
73 static void PLy_pop_execution_context(void);
75 static const int plpython_python_version = PY_MAJOR_VERSION;
77 /* initialize global variables */
78 PyObject *PLy_interp_globals = NULL;
80 /* this doesn't need to be global; use PLy_current_execution_context() */
81 static PLyExecutionContext *PLy_execution_contexts = NULL;
87 /* Be sure we do initialization only once (should be redundant now) */
88 static bool inited = false;
89 const int **version_ptr;
94 /* Be sure we don't run Python 2 and 3 in the same session (might crash) */
95 version_ptr = (const int **) find_rendezvous_variable("plpython_python_version");
97 *version_ptr = &plpython_python_version;
100 if (**version_ptr != plpython_python_version)
102 (errmsg("Python major version mismatch in session"),
103 errdetail("This session has previously used Python major version %d, and it is now attempting to use Python major version %d.",
104 **version_ptr, plpython_python_version),
105 errhint("Start a new session to use a different Python major version.")));
108 pg_bindtextdomain(TEXTDOMAIN);
110 #if PY_MAJOR_VERSION >= 3
111 PyImport_AppendInittab("plpy", PyInit_plpy);
114 #if PY_MAJOR_VERSION >= 3
115 PyImport_ImportModule("plpy");
119 if (PyErr_Occurred())
120 PLy_elog(FATAL, "untrapped error in initialization");
122 init_procedure_caches();
124 explicit_subtransactions = NIL;
126 PLy_execution_contexts = NULL;
132 * This should only be called once from _PG_init. Initialize the Python
133 * interpreter and global data.
136 PLy_init_interp(void)
138 static PyObject *PLy_interp_safe_globals = NULL;
141 mainmod = PyImport_AddModule("__main__");
142 if (mainmod == NULL || PyErr_Occurred())
143 PLy_elog(ERROR, "could not import \"__main__\" module");
145 PLy_interp_globals = PyModule_GetDict(mainmod);
146 PLy_interp_safe_globals = PyDict_New();
147 if (PLy_interp_safe_globals == NULL)
148 PLy_elog(ERROR, "could not create globals");
149 PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
151 if (PLy_interp_globals == NULL || PyErr_Occurred())
152 PLy_elog(ERROR, "could not initialize globals");
156 plpython_validator(PG_FUNCTION_ARGS)
158 Oid funcoid = PG_GETARG_OID(0);
160 Form_pg_proc procStruct;
163 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
166 if (!check_function_bodies)
171 /* Get the new function's pg_proc entry */
172 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
173 if (!HeapTupleIsValid(tuple))
174 elog(ERROR, "cache lookup failed for function %u", funcoid);
175 procStruct = (Form_pg_proc) GETSTRUCT(tuple);
177 is_trigger = PLy_procedure_is_trigger(procStruct);
179 ReleaseSysCache(tuple);
181 /* We can't validate triggers against any particular table ... */
182 PLy_procedure_get(funcoid, InvalidOid, is_trigger);
187 #if PY_MAJOR_VERSION < 3
189 plpython2_validator(PG_FUNCTION_ARGS)
191 /* call plpython validator with our fcinfo so it gets our oid */
192 return plpython_validator(fcinfo);
194 #endif /* PY_MAJOR_VERSION < 3 */
197 plpython_call_handler(PG_FUNCTION_ARGS)
200 PLyExecutionContext *exec_ctx;
201 ErrorContextCallback plerrcontext;
203 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
204 if (SPI_connect() != SPI_OK_CONNECT)
205 elog(ERROR, "SPI_connect failed");
208 * Push execution context onto stack. It is important that this get
209 * popped again, so avoid putting anything that could throw error between
210 * here and the PG_TRY. (plpython_error_callback expects the stack entry
211 * to be there, so we have to make the context first.)
213 exec_ctx = PLy_push_execution_context();
216 * Setup error traceback support for ereport()
218 plerrcontext.callback = plpython_error_callback;
219 plerrcontext.previous = error_context_stack;
220 error_context_stack = &plerrcontext;
224 Oid funcoid = fcinfo->flinfo->fn_oid;
227 if (CALLED_AS_TRIGGER(fcinfo))
229 Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
232 proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
233 exec_ctx->curr_proc = proc;
234 trv = PLy_exec_trigger(fcinfo, proc);
235 retval = PointerGetDatum(trv);
239 proc = PLy_procedure_get(funcoid, InvalidOid, false);
240 exec_ctx->curr_proc = proc;
241 retval = PLy_exec_function(fcinfo, proc);
246 PLy_pop_execution_context();
252 /* Pop the error context stack */
253 error_context_stack = plerrcontext.previous;
254 /* ... and then the execution context */
255 PLy_pop_execution_context();
260 #if PY_MAJOR_VERSION < 3
262 plpython2_call_handler(PG_FUNCTION_ARGS)
264 return plpython_call_handler(fcinfo);
266 #endif /* PY_MAJOR_VERSION < 3 */
269 plpython_inline_handler(PG_FUNCTION_ARGS)
271 InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
272 FunctionCallInfoData fake_fcinfo;
275 PLyExecutionContext *exec_ctx;
276 ErrorContextCallback plerrcontext;
278 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
279 if (SPI_connect() != SPI_OK_CONNECT)
280 elog(ERROR, "SPI_connect failed");
282 MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
283 MemSet(&flinfo, 0, sizeof(flinfo));
284 fake_fcinfo.flinfo = &flinfo;
285 flinfo.fn_oid = InvalidOid;
286 flinfo.fn_mcxt = CurrentMemoryContext;
288 MemSet(&proc, 0, sizeof(PLyProcedure));
289 proc.pyname = PLy_strdup("__plpython_inline_block");
290 proc.result.out.d.typoid = VOIDOID;
293 * Push execution context onto stack. It is important that this get
294 * popped again, so avoid putting anything that could throw error between
295 * here and the PG_TRY. (plpython_inline_error_callback doesn't currently
296 * need the stack entry, but for consistency with plpython_call_handler we
297 * do it in this order.)
299 exec_ctx = PLy_push_execution_context();
302 * Setup error traceback support for ereport()
304 plerrcontext.callback = plpython_inline_error_callback;
305 plerrcontext.previous = error_context_stack;
306 error_context_stack = &plerrcontext;
310 PLy_procedure_compile(&proc, codeblock->source_text);
311 exec_ctx->curr_proc = &proc;
312 PLy_exec_function(&fake_fcinfo, &proc);
316 PLy_pop_execution_context();
317 PLy_procedure_delete(&proc);
323 /* Pop the error context stack */
324 error_context_stack = plerrcontext.previous;
325 /* ... and then the execution context */
326 PLy_pop_execution_context();
328 /* Now clean up the transient procedure we made */
329 PLy_procedure_delete(&proc);
334 #if PY_MAJOR_VERSION < 3
336 plpython2_inline_handler(PG_FUNCTION_ARGS)
338 return plpython_inline_handler(fcinfo);
340 #endif /* PY_MAJOR_VERSION < 3 */
343 PLy_procedure_is_trigger(Form_pg_proc procStruct)
345 return (procStruct->prorettype == TRIGGEROID ||
346 (procStruct->prorettype == OPAQUEOID &&
347 procStruct->pronargs == 0));
351 plpython_error_callback(void *arg)
353 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
355 if (exec_ctx->curr_proc)
356 errcontext("PL/Python function \"%s\"",
357 PLy_procedure_name(exec_ctx->curr_proc));
361 plpython_inline_error_callback(void *arg)
363 errcontext("PL/Python anonymous code block");
366 PLyExecutionContext *
367 PLy_current_execution_context(void)
369 if (PLy_execution_contexts == NULL)
370 elog(ERROR, "no Python function is currently executing");
372 return PLy_execution_contexts;
375 static PLyExecutionContext *
376 PLy_push_execution_context(void)
378 PLyExecutionContext *context = PLy_malloc(sizeof(PLyExecutionContext));
380 context->curr_proc = NULL;
381 context->scratch_ctx = AllocSetContextCreate(TopTransactionContext,
382 "PL/Python scratch context",
383 ALLOCSET_DEFAULT_MINSIZE,
384 ALLOCSET_DEFAULT_INITSIZE,
385 ALLOCSET_DEFAULT_MAXSIZE);
386 context->next = PLy_execution_contexts;
387 PLy_execution_contexts = context;
392 PLy_pop_execution_context(void)
394 PLyExecutionContext *context = PLy_execution_contexts;
397 elog(ERROR, "no Python function is currently executing");
399 PLy_execution_contexts = context->next;
401 MemoryContextDelete(context->scratch_ctx);