PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
plpy_main.c
Go to the documentation of this file.
1/*
2 * PL/Python main entry points
3 *
4 * src/pl/plpython/plpy_main.c
5 */
6
7#include "postgres.h"
8
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
32 .name = "plpython",
33 .version = PG_VERSION
34);
35
39
40
41static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
42static void plpython_error_callback(void *arg);
43static void plpython_inline_error_callback(void *arg);
44static void PLy_init_interp(void);
45
46static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
47static void PLy_pop_execution_context(void);
48
49/* static state for Python library conflict detection */
52
53/* initialize global variables */
54PyObject *PLy_interp_globals = NULL;
55
56/* this doesn't need to be global; use PLy_current_execution_context() */
58
59
60void
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 bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
78 if (!(*bitmask_ptr)) /* am I the first? */
79 *bitmask_ptr = &plpython_version_bitmask;
80 /* Retain pointer to the agreed-on shared variable ... */
81 plpython_version_bitmask_ptr = *bitmask_ptr;
82 /* ... and announce my presence */
83 *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 */
91}
92
93/*
94 * Perform one-time setup of PL/Python, after checking for a conflict
95 * with other versions of Python.
96 */
97static 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 if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
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 if (inited)
117 return;
118
119 PyImport_AppendInittab("plpy", PyInit_plpy);
120 Py_Initialize();
121 PyImport_ImportModule("plpy");
124 if (PyErr_Occurred())
125 PLy_elog(FATAL, "untrapped error in initialization");
126
128
130
132
133 inited = true;
134}
135
136/*
137 * This should be called only once, from PLy_initialize. Initialize the Python
138 * interpreter and global data.
139 */
140static void
142{
143 static PyObject *PLy_interp_safe_globals = NULL;
144 PyObject *mainmod;
145
146 mainmod = PyImport_AddModule("__main__");
147 if (mainmod == NULL || PyErr_Occurred())
148 PLy_elog(ERROR, "could not import \"__main__\" module");
149 Py_INCREF(mainmod);
150 PLy_interp_globals = PyModule_GetDict(mainmod);
151 PLy_interp_safe_globals = PyDict_New();
152 if (PLy_interp_safe_globals == NULL)
153 PLy_elog(ERROR, NULL);
154 PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
155 Py_DECREF(mainmod);
156 if (PLy_interp_globals == NULL || PyErr_Occurred())
157 PLy_elog(ERROR, "could not initialize globals");
158}
159
160Datum
162{
163 Oid funcoid = PG_GETARG_OID(0);
164 HeapTuple tuple;
165 Form_pg_proc procStruct;
166 bool is_trigger;
167
168 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
170
173
174 /* Do this only after making sure we need to do something */
176
177 /* Get the new function's pg_proc entry */
178 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
179 if (!HeapTupleIsValid(tuple))
180 elog(ERROR, "cache lookup failed for function %u", funcoid);
181 procStruct = (Form_pg_proc) GETSTRUCT(tuple);
182
183 is_trigger = PLy_procedure_is_trigger(procStruct);
184
185 ReleaseSysCache(tuple);
186
187 /* We can't validate triggers against any particular table ... */
188 PLy_procedure_get(funcoid, InvalidOid, is_trigger);
189
191}
192
193Datum
195{
196 bool nonatomic;
197 Datum retval;
198 PLyExecutionContext *exec_ctx;
199 ErrorContextCallback plerrcontext;
200
202
203 nonatomic = fcinfo->context &&
204 IsA(fcinfo->context, CallContext) &&
205 !castNode(CallContext, fcinfo->context)->atomic;
206
207 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
208 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 exec_ctx = PLy_push_execution_context(!nonatomic);
216
217 PG_TRY();
218 {
219 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 plerrcontext.callback = plpython_error_callback;
229 plerrcontext.arg = exec_ctx;
230 plerrcontext.previous = error_context_stack;
231 error_context_stack = &plerrcontext;
232
233 if (CALLED_AS_TRIGGER(fcinfo))
234 {
235 Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
236 HeapTuple trv;
237
238 proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
239 exec_ctx->curr_proc = proc;
240 trv = PLy_exec_trigger(fcinfo, proc);
241 retval = PointerGetDatum(trv);
242 }
243 else
244 {
245 proc = PLy_procedure_get(funcoid, InvalidOid, false);
246 exec_ctx->curr_proc = proc;
247 retval = PLy_exec_function(fcinfo, proc);
248 }
249 }
250 PG_CATCH();
251 {
253 PyErr_Clear();
254 PG_RE_THROW();
255 }
256 PG_END_TRY();
257
258 /* Destroy the execution context */
260
261 return retval;
262}
263
264Datum
266{
267 LOCAL_FCINFO(fake_fcinfo, 0);
269 FmgrInfo flinfo;
270 PLyProcedure proc;
271 PLyExecutionContext *exec_ctx;
272 ErrorContextCallback plerrcontext;
273
275
276 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
277 SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
278
279 MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
280 MemSet(&flinfo, 0, sizeof(flinfo));
281 fake_fcinfo->flinfo = &flinfo;
282 flinfo.fn_oid = InvalidOid;
284
285 MemSet(&proc, 0, sizeof(PLyProcedure));
287 "__plpython_inline_block",
289 proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
290 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 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 exec_ctx = PLy_push_execution_context(codeblock->atomic);
304
305 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 */
313 plerrcontext.arg = exec_ctx;
314 plerrcontext.previous = error_context_stack;
315 error_context_stack = &plerrcontext;
316
317 PLy_procedure_compile(&proc, codeblock->source_text);
318 exec_ctx->curr_proc = &proc;
319 PLy_exec_function(fake_fcinfo, &proc);
320 }
321 PG_CATCH();
322 {
325 PyErr_Clear();
326 PG_RE_THROW();
327 }
328 PG_END_TRY();
329
330 /* Destroy the execution context */
332
333 /* Now clean up the transient procedure we made */
335
337}
338
339static bool
341{
342 return (procStruct->prorettype == TRIGGEROID);
343}
344
345static void
347{
349
350 if (exec_ctx->curr_proc)
351 {
352 if (exec_ctx->curr_proc->is_procedure)
353 errcontext("PL/Python procedure \"%s\"",
354 PLy_procedure_name(exec_ctx->curr_proc));
355 else
356 errcontext("PL/Python function \"%s\"",
357 PLy_procedure_name(exec_ctx->curr_proc));
358 }
359}
360
361static void
363{
364 errcontext("PL/Python anonymous code block");
365}
366
369{
370 if (PLy_execution_contexts == NULL)
371 elog(ERROR, "no Python function is currently executing");
372
374}
375
378{
379 /*
380 * A scratch context might never be needed in a given plpython procedure,
381 * so allocate it on first request.
382 */
383 if (context->scratch_ctx == NULL)
384 context->scratch_ctx =
386 "PL/Python scratch context",
388 return context->scratch_ctx;
389}
390
391static PLyExecutionContext *
392PLy_push_execution_context(bool atomic_context)
393{
394 PLyExecutionContext *context;
395
396 /* Pick a memory context similar to what SPI uses. */
397 context = (PLyExecutionContext *)
399 sizeof(PLyExecutionContext));
400 context->curr_proc = NULL;
401 context->scratch_ctx = NULL;
402 context->next = PLy_execution_contexts;
403 PLy_execution_contexts = context;
404 return context;
405}
406
407static void
409{
411
412 if (context == NULL)
413 elog(ERROR, "no Python function is currently executing");
414
415 PLy_execution_contexts = context->next;
416
417 if (context->scratch_ctx)
419 pfree(context);
420}
#define MemSet(start, val, len)
Definition: c.h:991
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:657
int errdetail(const char *fmt,...)
Definition: elog.c:1204
ErrorContextCallback * error_context_stack
Definition: elog.c:95
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define PG_RE_THROW()
Definition: elog.h:405
#define errcontext
Definition: elog.h:197
#define FATAL
Definition: elog.h:41
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:382
#define TEXTDOMAIN
Definition: elog.h:152
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2145
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
bool check_function_bodies
Definition: guc_tables.c:528
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define PLy_elog
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:2312
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1260
MemoryContext TopTransactionContext
Definition: mcxt.c:170
void pfree(void *pointer)
Definition: mcxt.c:2150
MemoryContext TopMemoryContext
Definition: mcxt.c:165
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
MemoryContext PortalContext
Definition: mcxt.c:174
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1939
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
void * arg
#define NIL
Definition: pg_list.h:68
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:53
HeapTuple PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:319
static int plpython_version_bitmask
Definition: plpy_main.c:51
Datum plpython3_validator(PG_FUNCTION_ARGS)
Definition: plpy_main.c:161
PyObject * PLy_interp_globals
Definition: plpy_main.c:54
static int * plpython_version_bitmask_ptr
Definition: plpy_main.c:50
static void PLy_initialize(void)
Definition: plpy_main.c:98
void _PG_init(void)
Definition: plpy_main.c:61
PG_FUNCTION_INFO_V1(plpython3_validator)
static void plpython_inline_error_callback(void *arg)
Definition: plpy_main.c:362
static PLyExecutionContext * PLy_execution_contexts
Definition: plpy_main.c:57
Datum plpython3_inline_handler(PG_FUNCTION_ARGS)
Definition: plpy_main.c:265
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:368
static bool PLy_procedure_is_trigger(Form_pg_proc procStruct)
Definition: plpy_main.c:340
static void plpython_error_callback(void *arg)
Definition: plpy_main.c:346
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:377
PG_MODULE_MAGIC_EXT(.name="plpython",.version=PG_VERSION)
static PLyExecutionContext * PLy_push_execution_context(bool atomic_context)
Definition: plpy_main.c:392
static void PLy_pop_execution_context(void)
Definition: plpy_main.c:408
static void PLy_init_interp(void)
Definition: plpy_main.c:141
Datum plpython3_call_handler(PG_FUNCTION_ARGS)
Definition: plpy_main.c:194
PyMODINIT_FUNC PyInit_plpy(void)
void PLy_init_plpy(void)
char * PLy_procedure_name(PLyProcedure *proc)
void init_procedure_caches(void)
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
void PLy_procedure_delete(PLyProcedure *proc)
PLyProcedure * PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
List * explicit_subtransactions
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
#define RelationGetRelid(relation)
Definition: rel.h:516
int SPI_connect_ext(int options)
Definition: spi.c:101
#define SPI_OPT_NONATOMIC
Definition: spi.h:102
struct ErrorContextCallback * previous
Definition: elog.h:297
void(* callback)(void *arg)
Definition: elog.h:298
Definition: fmgr.h:57
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid fn_oid
Definition: fmgr.h:59
char * source_text
Definition: parsenodes.h:3581
struct PLyExecutionContext * next
Definition: plpy_main.h:22
PLyProcedure * curr_proc
Definition: plpy_main.h:20
MemoryContext scratch_ctx
Definition: plpy_main.h:21
PLyObToDatum result
MemoryContext mcxt
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26
const char * name