Line data Source code
1 : /*
2 : * PL/Python main entry points
3 : *
4 : * src/pl/plpython/plpy_main.c
5 : */
6 :
7 : #include "postgres.h"
8 :
9 : #include "access/htup_details.h"
10 : #include "catalog/pg_proc.h"
11 : #include "catalog/pg_type.h"
12 : #include "commands/event_trigger.h"
13 : #include "commands/trigger.h"
14 : #include "executor/spi.h"
15 : #include "miscadmin.h"
16 : #include "plpy_elog.h"
17 : #include "plpy_exec.h"
18 : #include "plpy_main.h"
19 : #include "plpy_plpymodule.h"
20 : #include "plpy_procedure.h"
21 : #include "plpy_subxactobject.h"
22 : #include "plpy_util.h"
23 : #include "utils/guc.h"
24 : #include "utils/memutils.h"
25 : #include "utils/rel.h"
26 : #include "utils/syscache.h"
27 :
28 : /*
29 : * exported functions
30 : */
31 :
32 46 : PG_MODULE_MAGIC_EXT(
33 : .name = "plpython",
34 : .version = PG_VERSION
35 : );
36 :
37 52 : PG_FUNCTION_INFO_V1(plpython3_validator);
38 52 : PG_FUNCTION_INFO_V1(plpython3_call_handler);
39 16 : PG_FUNCTION_INFO_V1(plpython3_inline_handler);
40 :
41 :
42 : static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
43 : static void plpython_error_callback(void *arg);
44 : static void plpython_inline_error_callback(void *arg);
45 : static void PLy_init_interp(void);
46 :
47 : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
48 : static void PLy_pop_execution_context(void);
49 :
50 : /* static state for Python library conflict detection */
51 : static int *plpython_version_bitmask_ptr = NULL;
52 : static int plpython_version_bitmask = 0;
53 :
54 : /* initialize global variables */
55 : PyObject *PLy_interp_globals = NULL;
56 :
57 : /* this doesn't need to be global; use PLy_current_execution_context() */
58 : static PLyExecutionContext *PLy_execution_contexts = NULL;
59 :
60 :
61 : void
62 46 : _PG_init(void)
63 : {
64 : int **bitmask_ptr;
65 :
66 : /*
67 : * Set up a shared bitmask variable telling which Python version(s) are
68 : * loaded into this process's address space. If there's more than one, we
69 : * cannot call into libpython for fear of causing crashes. But postpone
70 : * the actual failure for later, so that operations like pg_restore can
71 : * load more than one plpython library so long as they don't try to do
72 : * anything much with the language.
73 : *
74 : * While we only support Python 3 these days, somebody might create an
75 : * out-of-tree version adding back support for Python 2. Conflicts with
76 : * such an extension should be detected.
77 : */
78 46 : bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
79 46 : if (!(*bitmask_ptr)) /* am I the first? */
80 46 : *bitmask_ptr = &plpython_version_bitmask;
81 : /* Retain pointer to the agreed-on shared variable ... */
82 46 : plpython_version_bitmask_ptr = *bitmask_ptr;
83 : /* ... and announce my presence */
84 46 : *plpython_version_bitmask_ptr |= (1 << PY_MAJOR_VERSION);
85 :
86 : /*
87 : * This should be safe even in the presence of conflicting plpythons, and
88 : * it's necessary to do it before possibly throwing a conflict error, or
89 : * the error message won't get localized.
90 : */
91 46 : pg_bindtextdomain(TEXTDOMAIN);
92 46 : }
93 :
94 : /*
95 : * Perform one-time setup of PL/Python, after checking for a conflict
96 : * with other versions of Python.
97 : */
98 : static void
99 1944 : PLy_initialize(void)
100 : {
101 : static bool inited = false;
102 :
103 : /*
104 : * Check for multiple Python libraries before actively doing anything with
105 : * libpython. This must be repeated on each entry to PL/Python, in case a
106 : * conflicting library got loaded since we last looked.
107 : *
108 : * It is attractive to weaken this error from FATAL to ERROR, but there
109 : * would be corner cases, so it seems best to be conservative.
110 : */
111 1944 : if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
112 0 : ereport(FATAL,
113 : (errmsg("multiple Python libraries are present in session"),
114 : errdetail("Only one Python major version can be used in one session.")));
115 :
116 : /* The rest should only be done once per session */
117 1944 : if (inited)
118 1898 : return;
119 :
120 46 : PyImport_AppendInittab("plpy", PyInit_plpy);
121 46 : Py_Initialize();
122 46 : PyImport_ImportModule("plpy");
123 46 : PLy_init_interp();
124 46 : PLy_init_plpy();
125 46 : if (PyErr_Occurred())
126 0 : PLy_elog(FATAL, "untrapped error in initialization");
127 :
128 46 : init_procedure_caches();
129 :
130 46 : explicit_subtransactions = NIL;
131 :
132 46 : PLy_execution_contexts = NULL;
133 :
134 46 : inited = true;
135 : }
136 :
137 : /*
138 : * This should be called only once, from PLy_initialize. Initialize the Python
139 : * interpreter and global data.
140 : */
141 : static void
142 46 : PLy_init_interp(void)
143 : {
144 : static PyObject *PLy_interp_safe_globals = NULL;
145 : PyObject *mainmod;
146 :
147 46 : mainmod = PyImport_AddModule("__main__");
148 46 : if (mainmod == NULL || PyErr_Occurred())
149 0 : PLy_elog(ERROR, "could not import \"__main__\" module");
150 46 : Py_INCREF(mainmod);
151 46 : PLy_interp_globals = PyModule_GetDict(mainmod);
152 46 : PLy_interp_safe_globals = PyDict_New();
153 46 : if (PLy_interp_safe_globals == NULL)
154 0 : PLy_elog(ERROR, NULL);
155 46 : PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
156 46 : Py_DECREF(mainmod);
157 46 : if (PLy_interp_globals == NULL || PyErr_Occurred())
158 0 : PLy_elog(ERROR, "could not initialize globals");
159 46 : }
160 :
161 : Datum
162 502 : plpython3_validator(PG_FUNCTION_ARGS)
163 : {
164 502 : Oid funcoid = PG_GETARG_OID(0);
165 : HeapTuple tuple;
166 : Form_pg_proc procStruct;
167 : PLyTrigType is_trigger;
168 :
169 502 : if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
170 0 : PG_RETURN_VOID();
171 :
172 502 : if (!check_function_bodies)
173 2 : PG_RETURN_VOID();
174 :
175 : /* Do this only after making sure we need to do something */
176 500 : PLy_initialize();
177 :
178 : /* Get the new function's pg_proc entry */
179 500 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
180 500 : if (!HeapTupleIsValid(tuple))
181 0 : elog(ERROR, "cache lookup failed for function %u", funcoid);
182 500 : procStruct = (Form_pg_proc) GETSTRUCT(tuple);
183 :
184 500 : is_trigger = PLy_procedure_is_trigger(procStruct);
185 :
186 500 : ReleaseSysCache(tuple);
187 :
188 : /* We can't validate triggers against any particular table ... */
189 500 : PLy_procedure_get(funcoid, InvalidOid, is_trigger);
190 :
191 498 : PG_RETURN_VOID();
192 : }
193 :
194 : Datum
195 1402 : plpython3_call_handler(PG_FUNCTION_ARGS)
196 : {
197 : bool nonatomic;
198 : Datum retval;
199 : PLyExecutionContext *exec_ctx;
200 : ErrorContextCallback plerrcontext;
201 :
202 1402 : PLy_initialize();
203 :
204 2938 : nonatomic = fcinfo->context &&
205 1418 : IsA(fcinfo->context, CallContext) &&
206 16 : !castNode(CallContext, fcinfo->context)->atomic;
207 :
208 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
209 1402 : SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
210 :
211 : /*
212 : * Push execution context onto stack. It is important that this get
213 : * popped again, so avoid putting anything that could throw error between
214 : * here and the PG_TRY.
215 : */
216 1402 : exec_ctx = PLy_push_execution_context(!nonatomic);
217 :
218 1402 : PG_TRY();
219 : {
220 1402 : Oid funcoid = fcinfo->flinfo->fn_oid;
221 : PLyProcedure *proc;
222 :
223 : /*
224 : * Setup error traceback support for ereport(). Note that the PG_TRY
225 : * structure pops this for us again at exit, so we needn't do that
226 : * explicitly, nor do we risk the callback getting called after we've
227 : * destroyed the exec_ctx.
228 : */
229 1402 : plerrcontext.callback = plpython_error_callback;
230 1402 : plerrcontext.arg = exec_ctx;
231 1402 : plerrcontext.previous = error_context_stack;
232 1402 : error_context_stack = &plerrcontext;
233 :
234 1402 : if (CALLED_AS_TRIGGER(fcinfo))
235 80 : {
236 98 : Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
237 : HeapTuple trv;
238 :
239 98 : proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), PLPY_TRIGGER);
240 98 : exec_ctx->curr_proc = proc;
241 98 : trv = PLy_exec_trigger(fcinfo, proc);
242 80 : retval = PointerGetDatum(trv);
243 : }
244 1304 : else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
245 : {
246 20 : proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_EVENT_TRIGGER);
247 20 : exec_ctx->curr_proc = proc;
248 20 : PLy_exec_event_trigger(fcinfo, proc);
249 20 : retval = (Datum) 0;
250 : }
251 : else
252 : {
253 1284 : proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_NOT_TRIGGER);
254 1278 : exec_ctx->curr_proc = proc;
255 1278 : retval = PLy_exec_function(fcinfo, proc);
256 : }
257 : }
258 186 : PG_CATCH();
259 : {
260 186 : PLy_pop_execution_context();
261 186 : PyErr_Clear();
262 186 : PG_RE_THROW();
263 : }
264 1216 : PG_END_TRY();
265 :
266 : /* Destroy the execution context */
267 1216 : PLy_pop_execution_context();
268 :
269 1216 : return retval;
270 : }
271 :
272 : Datum
273 42 : plpython3_inline_handler(PG_FUNCTION_ARGS)
274 : {
275 42 : LOCAL_FCINFO(fake_fcinfo, 0);
276 42 : InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
277 : FmgrInfo flinfo;
278 : PLyProcedure proc;
279 : PLyExecutionContext *exec_ctx;
280 : ErrorContextCallback plerrcontext;
281 :
282 42 : PLy_initialize();
283 :
284 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
285 42 : SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
286 :
287 210 : MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
288 294 : MemSet(&flinfo, 0, sizeof(flinfo));
289 42 : fake_fcinfo->flinfo = &flinfo;
290 42 : flinfo.fn_oid = InvalidOid;
291 42 : flinfo.fn_mcxt = CurrentMemoryContext;
292 :
293 1764 : MemSet(&proc, 0, sizeof(PLyProcedure));
294 42 : proc.mcxt = AllocSetContextCreate(TopMemoryContext,
295 : "__plpython_inline_block",
296 : ALLOCSET_DEFAULT_SIZES);
297 42 : proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
298 42 : proc.langid = codeblock->langOid;
299 :
300 : /*
301 : * This is currently sufficient to get PLy_exec_function to work, but
302 : * someday we might need to be honest and use PLy_output_setup_func.
303 : */
304 42 : proc.result.typoid = VOIDOID;
305 :
306 : /*
307 : * Push execution context onto stack. It is important that this get
308 : * popped again, so avoid putting anything that could throw error between
309 : * here and the PG_TRY.
310 : */
311 42 : exec_ctx = PLy_push_execution_context(codeblock->atomic);
312 :
313 42 : PG_TRY();
314 : {
315 : /*
316 : * Setup error traceback support for ereport().
317 : * plpython_inline_error_callback doesn't currently need exec_ctx, but
318 : * for consistency with plpython3_call_handler we do it the same way.
319 : */
320 42 : plerrcontext.callback = plpython_inline_error_callback;
321 42 : plerrcontext.arg = exec_ctx;
322 42 : plerrcontext.previous = error_context_stack;
323 42 : error_context_stack = &plerrcontext;
324 :
325 42 : PLy_procedure_compile(&proc, codeblock->source_text);
326 42 : exec_ctx->curr_proc = &proc;
327 42 : PLy_exec_function(fake_fcinfo, &proc);
328 : }
329 22 : PG_CATCH();
330 : {
331 22 : PLy_pop_execution_context();
332 22 : PLy_procedure_delete(&proc);
333 22 : PyErr_Clear();
334 22 : PG_RE_THROW();
335 : }
336 20 : PG_END_TRY();
337 :
338 : /* Destroy the execution context */
339 20 : PLy_pop_execution_context();
340 :
341 : /* Now clean up the transient procedure we made */
342 20 : PLy_procedure_delete(&proc);
343 :
344 20 : PG_RETURN_VOID();
345 : }
346 :
347 : static PLyTrigType
348 500 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
349 : {
350 : PLyTrigType ret;
351 :
352 500 : switch (procStruct->prorettype)
353 : {
354 48 : case TRIGGEROID:
355 48 : ret = PLPY_TRIGGER;
356 48 : break;
357 2 : case EVENT_TRIGGEROID:
358 2 : ret = PLPY_EVENT_TRIGGER;
359 2 : break;
360 450 : default:
361 450 : ret = PLPY_NOT_TRIGGER;
362 450 : break;
363 : }
364 :
365 500 : return ret;
366 : }
367 :
368 : static void
369 932 : plpython_error_callback(void *arg)
370 : {
371 932 : PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
372 :
373 932 : if (exec_ctx->curr_proc)
374 : {
375 926 : if (exec_ctx->curr_proc->is_procedure)
376 8 : errcontext("PL/Python procedure \"%s\"",
377 : PLy_procedure_name(exec_ctx->curr_proc));
378 : else
379 918 : errcontext("PL/Python function \"%s\"",
380 : PLy_procedure_name(exec_ctx->curr_proc));
381 : }
382 932 : }
383 :
384 : static void
385 56 : plpython_inline_error_callback(void *arg)
386 : {
387 56 : errcontext("PL/Python anonymous code block");
388 56 : }
389 :
390 : PLyExecutionContext *
391 2856 : PLy_current_execution_context(void)
392 : {
393 2856 : if (PLy_execution_contexts == NULL)
394 0 : elog(ERROR, "no Python function is currently executing");
395 :
396 2856 : return PLy_execution_contexts;
397 : }
398 :
399 : MemoryContext
400 1586 : PLy_get_scratch_context(PLyExecutionContext *context)
401 : {
402 : /*
403 : * A scratch context might never be needed in a given plpython procedure,
404 : * so allocate it on first request.
405 : */
406 1586 : if (context->scratch_ctx == NULL)
407 884 : context->scratch_ctx =
408 884 : AllocSetContextCreate(TopTransactionContext,
409 : "PL/Python scratch context",
410 : ALLOCSET_DEFAULT_SIZES);
411 1586 : return context->scratch_ctx;
412 : }
413 :
414 : static PLyExecutionContext *
415 1444 : PLy_push_execution_context(bool atomic_context)
416 : {
417 : PLyExecutionContext *context;
418 :
419 : /* Pick a memory context similar to what SPI uses. */
420 : context = (PLyExecutionContext *)
421 1444 : MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
422 : sizeof(PLyExecutionContext));
423 1444 : context->curr_proc = NULL;
424 1444 : context->scratch_ctx = NULL;
425 1444 : context->next = PLy_execution_contexts;
426 1444 : PLy_execution_contexts = context;
427 1444 : return context;
428 : }
429 :
430 : static void
431 1444 : PLy_pop_execution_context(void)
432 : {
433 1444 : PLyExecutionContext *context = PLy_execution_contexts;
434 :
435 1444 : if (context == NULL)
436 0 : elog(ERROR, "no Python function is currently executing");
437 :
438 1444 : PLy_execution_contexts = context->next;
439 :
440 1444 : if (context->scratch_ctx)
441 850 : MemoryContextDelete(context->scratch_ctx);
442 1444 : pfree(context);
443 1444 : }
|