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