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