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(bool atomic_context);
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, NULL);
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 	bool		nonatomic;
223 	Datum		retval;
224 	PLyExecutionContext *exec_ctx;
225 	ErrorContextCallback plerrcontext;
226 
227 	PLy_initialize();
228 
229 	nonatomic = fcinfo->context &&
230 		IsA(fcinfo->context, CallContext) &&
231 		!castNode(CallContext, fcinfo->context)->atomic;
232 
233 	/* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
234 	if (SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0) != SPI_OK_CONNECT)
235 		elog(ERROR, "SPI_connect failed");
236 
237 	/*
238 	 * Push execution context onto stack.  It is important that this get
239 	 * popped again, so avoid putting anything that could throw error between
240 	 * here and the PG_TRY.
241 	 */
242 	exec_ctx = PLy_push_execution_context(!nonatomic);
243 
244 	PG_TRY();
245 	{
246 		Oid			funcoid = fcinfo->flinfo->fn_oid;
247 		PLyProcedure *proc;
248 
249 		/*
250 		 * Setup error traceback support for ereport().  Note that the PG_TRY
251 		 * structure pops this for us again at exit, so we needn't do that
252 		 * explicitly, nor do we risk the callback getting called after we've
253 		 * destroyed the exec_ctx.
254 		 */
255 		plerrcontext.callback = plpython_error_callback;
256 		plerrcontext.arg = exec_ctx;
257 		plerrcontext.previous = error_context_stack;
258 		error_context_stack = &plerrcontext;
259 
260 		if (CALLED_AS_TRIGGER(fcinfo))
261 		{
262 			Relation	tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
263 			HeapTuple	trv;
264 
265 			proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
266 			exec_ctx->curr_proc = proc;
267 			trv = PLy_exec_trigger(fcinfo, proc);
268 			retval = PointerGetDatum(trv);
269 		}
270 		else
271 		{
272 			proc = PLy_procedure_get(funcoid, InvalidOid, false);
273 			exec_ctx->curr_proc = proc;
274 			retval = PLy_exec_function(fcinfo, proc);
275 		}
276 	}
277 	PG_CATCH();
278 	{
279 		PLy_pop_execution_context();
280 		PyErr_Clear();
281 		PG_RE_THROW();
282 	}
283 	PG_END_TRY();
284 
285 	/* Destroy the execution context */
286 	PLy_pop_execution_context();
287 
288 	return retval;
289 }
290 
291 #if PY_MAJOR_VERSION < 3
292 Datum
plpython2_call_handler(PG_FUNCTION_ARGS)293 plpython2_call_handler(PG_FUNCTION_ARGS)
294 {
295 	return plpython_call_handler(fcinfo);
296 }
297 #endif							/* PY_MAJOR_VERSION < 3 */
298 
299 Datum
plpython_inline_handler(PG_FUNCTION_ARGS)300 plpython_inline_handler(PG_FUNCTION_ARGS)
301 {
302 	InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
303 	FunctionCallInfoData fake_fcinfo;
304 	FmgrInfo	flinfo;
305 	PLyProcedure proc;
306 	PLyExecutionContext *exec_ctx;
307 	ErrorContextCallback plerrcontext;
308 
309 	PLy_initialize();
310 
311 	/* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
312 	if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
313 		elog(ERROR, "SPI_connect failed");
314 
315 	MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
316 	MemSet(&flinfo, 0, sizeof(flinfo));
317 	fake_fcinfo.flinfo = &flinfo;
318 	flinfo.fn_oid = InvalidOid;
319 	flinfo.fn_mcxt = CurrentMemoryContext;
320 
321 	MemSet(&proc, 0, sizeof(PLyProcedure));
322 	proc.mcxt = AllocSetContextCreate(TopMemoryContext,
323 									  "__plpython_inline_block",
324 									  ALLOCSET_DEFAULT_SIZES);
325 	proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
326 	proc.langid = codeblock->langOid;
327 
328 	/*
329 	 * This is currently sufficient to get PLy_exec_function to work, but
330 	 * someday we might need to be honest and use PLy_output_setup_func.
331 	 */
332 	proc.result.typoid = VOIDOID;
333 
334 	/*
335 	 * Push execution context onto stack.  It is important that this get
336 	 * popped again, so avoid putting anything that could throw error between
337 	 * here and the PG_TRY.
338 	 */
339 	exec_ctx = PLy_push_execution_context(codeblock->atomic);
340 
341 	PG_TRY();
342 	{
343 		/*
344 		 * Setup error traceback support for ereport().
345 		 * plpython_inline_error_callback doesn't currently need exec_ctx, but
346 		 * for consistency with plpython_call_handler we do it the same way.
347 		 */
348 		plerrcontext.callback = plpython_inline_error_callback;
349 		plerrcontext.arg = exec_ctx;
350 		plerrcontext.previous = error_context_stack;
351 		error_context_stack = &plerrcontext;
352 
353 		PLy_procedure_compile(&proc, codeblock->source_text);
354 		exec_ctx->curr_proc = &proc;
355 		PLy_exec_function(&fake_fcinfo, &proc);
356 	}
357 	PG_CATCH();
358 	{
359 		PLy_pop_execution_context();
360 		PLy_procedure_delete(&proc);
361 		PyErr_Clear();
362 		PG_RE_THROW();
363 	}
364 	PG_END_TRY();
365 
366 	/* Destroy the execution context */
367 	PLy_pop_execution_context();
368 
369 	/* Now clean up the transient procedure we made */
370 	PLy_procedure_delete(&proc);
371 
372 	PG_RETURN_VOID();
373 }
374 
375 #if PY_MAJOR_VERSION < 3
376 Datum
plpython2_inline_handler(PG_FUNCTION_ARGS)377 plpython2_inline_handler(PG_FUNCTION_ARGS)
378 {
379 	return plpython_inline_handler(fcinfo);
380 }
381 #endif							/* PY_MAJOR_VERSION < 3 */
382 
383 static bool
PLy_procedure_is_trigger(Form_pg_proc procStruct)384 PLy_procedure_is_trigger(Form_pg_proc procStruct)
385 {
386 	return (procStruct->prorettype == TRIGGEROID ||
387 			(procStruct->prorettype == OPAQUEOID &&
388 			 procStruct->pronargs == 0));
389 }
390 
391 static void
plpython_error_callback(void * arg)392 plpython_error_callback(void *arg)
393 {
394 	PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
395 
396 	if (exec_ctx->curr_proc)
397 	{
398 		if (exec_ctx->curr_proc->is_procedure)
399 			errcontext("PL/Python procedure \"%s\"",
400 					   PLy_procedure_name(exec_ctx->curr_proc));
401 		else
402 			errcontext("PL/Python function \"%s\"",
403 					   PLy_procedure_name(exec_ctx->curr_proc));
404 	}
405 }
406 
407 static void
plpython_inline_error_callback(void * arg)408 plpython_inline_error_callback(void *arg)
409 {
410 	errcontext("PL/Python anonymous code block");
411 }
412 
413 PLyExecutionContext *
PLy_current_execution_context(void)414 PLy_current_execution_context(void)
415 {
416 	if (PLy_execution_contexts == NULL)
417 		elog(ERROR, "no Python function is currently executing");
418 
419 	return PLy_execution_contexts;
420 }
421 
422 MemoryContext
PLy_get_scratch_context(PLyExecutionContext * context)423 PLy_get_scratch_context(PLyExecutionContext *context)
424 {
425 	/*
426 	 * A scratch context might never be needed in a given plpython procedure,
427 	 * so allocate it on first request.
428 	 */
429 	if (context->scratch_ctx == NULL)
430 		context->scratch_ctx =
431 			AllocSetContextCreate(TopTransactionContext,
432 								  "PL/Python scratch context",
433 								  ALLOCSET_DEFAULT_SIZES);
434 	return context->scratch_ctx;
435 }
436 
437 static PLyExecutionContext *
PLy_push_execution_context(bool atomic_context)438 PLy_push_execution_context(bool atomic_context)
439 {
440 	PLyExecutionContext *context;
441 
442 	/* Pick a memory context similar to what SPI uses. */
443 	context = (PLyExecutionContext *)
444 		MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
445 						   sizeof(PLyExecutionContext));
446 	context->curr_proc = NULL;
447 	context->scratch_ctx = NULL;
448 	context->next = PLy_execution_contexts;
449 	PLy_execution_contexts = context;
450 	return context;
451 }
452 
453 static void
PLy_pop_execution_context(void)454 PLy_pop_execution_context(void)
455 {
456 	PLyExecutionContext *context = PLy_execution_contexts;
457 
458 	if (context == NULL)
459 		elog(ERROR, "no Python function is currently executing");
460 
461 	PLy_execution_contexts = context->next;
462 
463 	if (context->scratch_ctx)
464 		MemoryContextDelete(context->scratch_ctx);
465 	pfree(context);
466 }
467