PostgreSQL Source Code: src/pl/plpython/plpy_main.c Source File

PostgreSQL Source Code git master
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
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 PG_MODULE_MAGIC_EXT(
33 .name = "plpython",
34 .version = PG_VERSION
35);
36
37 PG_FUNCTION_INFO_V1(plpython3_validator);
38 PG_FUNCTION_INFO_V1(plpython3_call_handler);
39 PG_FUNCTION_INFO_V1(plpython3_inline_handler);
40
41
42static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
43static void plpython_error_callback(void *arg);
44static void plpython_inline_error_callback(void *arg);
45static void PLy_init_interp(void);
46
47static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
48static 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
61void
62 _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 bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
79 if (!(*bitmask_ptr)) /* am I the first? */
80 *bitmask_ptr = &plpython_version_bitmask;
81 /* Retain pointer to the agreed-on shared variable ... */
82 plpython_version_bitmask_ptr = *bitmask_ptr;
83 /* ... and announce my presence */
84 *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 pg_bindtextdomain(TEXTDOMAIN);
92}
93
94/*
95 * Perform one-time setup of PL/Python, after checking for a conflict
96 * with other versions of Python.
97 */
98static void
99 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 if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
112 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 if (inited)
118 return;
119
120 PyImport_AppendInittab("plpy", PyInit_plpy);
121 Py_Initialize();
122 PyImport_ImportModule("plpy");
123 PLy_init_interp();
124 PLy_init_plpy();
125 if (PyErr_Occurred())
126 PLy_elog(FATAL, "untrapped error in initialization");
127
128 init_procedure_caches();
129
130 explicit_subtransactions = NIL;
131
132 PLy_execution_contexts = NULL;
133
134 inited = true;
135}
136
137/*
138 * This should be called only once, from PLy_initialize. Initialize the Python
139 * interpreter and global data.
140 */
141static void
142 PLy_init_interp(void)
143{
144 static PyObject *PLy_interp_safe_globals = NULL;
145 PyObject *mainmod;
146
147 mainmod = PyImport_AddModule("__main__");
148 if (mainmod == NULL || PyErr_Occurred())
149 PLy_elog(ERROR, "could not import \"__main__\" module");
150 Py_INCREF(mainmod);
151 PLy_interp_globals = PyModule_GetDict(mainmod);
152 PLy_interp_safe_globals = PyDict_New();
153 if (PLy_interp_safe_globals == NULL)
154 PLy_elog(ERROR, NULL);
155 PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
156 Py_DECREF(mainmod);
157 if (PLy_interp_globals == NULL || PyErr_Occurred())
158 PLy_elog(ERROR, "could not initialize globals");
159}
160
161Datum
162 plpython3_validator(PG_FUNCTION_ARGS)
163{
164 Oid funcoid = PG_GETARG_OID(0);
165 HeapTuple tuple;
166 Form_pg_proc procStruct;
167 PLyTrigType is_trigger;
168
169 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
170 PG_RETURN_VOID();
171
172 if (!check_function_bodies)
173 PG_RETURN_VOID();
174
175 /* Do this only after making sure we need to do something */
176 PLy_initialize();
177
178 /* Get the new function's pg_proc entry */
179 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
180 if (!HeapTupleIsValid(tuple))
181 elog(ERROR, "cache lookup failed for function %u", funcoid);
182 procStruct = (Form_pg_proc) GETSTRUCT(tuple);
183
184 is_trigger = PLy_procedure_is_trigger(procStruct);
185
186 ReleaseSysCache(tuple);
187
188 /* We can't validate triggers against any particular table ... */
189 PLy_procedure_get(funcoid, InvalidOid, is_trigger);
190
191 PG_RETURN_VOID();
192}
193
194Datum
195 plpython3_call_handler(PG_FUNCTION_ARGS)
196{
197 bool nonatomic;
198 Datum retval;
199 PLyExecutionContext *exec_ctx;
200 ErrorContextCallback plerrcontext;
201
202 PLy_initialize();
203
204 nonatomic = fcinfo->context &&
205 IsA(fcinfo->context, CallContext) &&
206 !castNode(CallContext, fcinfo->context)->atomic;
207
208 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
209 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 exec_ctx = PLy_push_execution_context(!nonatomic);
217
218 PG_TRY();
219 {
220 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 plerrcontext.callback = plpython_error_callback;
230 plerrcontext.arg = exec_ctx;
231 plerrcontext.previous = error_context_stack;
232 error_context_stack = &plerrcontext;
233
234 if (CALLED_AS_TRIGGER(fcinfo))
235 {
236 Relation tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
237 HeapTuple trv;
238
239 proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), PLPY_TRIGGER);
240 exec_ctx->curr_proc = proc;
241 trv = PLy_exec_trigger(fcinfo, proc);
242 retval = PointerGetDatum(trv);
243 }
244 else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
245 {
246 proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_EVENT_TRIGGER);
247 exec_ctx->curr_proc = proc;
248 PLy_exec_event_trigger(fcinfo, proc);
249 retval = (Datum) 0;
250 }
251 else
252 {
253 proc = PLy_procedure_get(funcoid, InvalidOid, PLPY_NOT_TRIGGER);
254 exec_ctx->curr_proc = proc;
255 retval = PLy_exec_function(fcinfo, proc);
256 }
257 }
258 PG_CATCH();
259 {
260 PLy_pop_execution_context();
261 PyErr_Clear();
262 PG_RE_THROW();
263 }
264 PG_END_TRY();
265
266 /* Destroy the execution context */
267 PLy_pop_execution_context();
268
269 return retval;
270}
271
272Datum
273 plpython3_inline_handler(PG_FUNCTION_ARGS)
274{
275 LOCAL_FCINFO(fake_fcinfo, 0);
276 InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
277 FmgrInfo flinfo;
278 PLyProcedure proc;
279 PLyExecutionContext *exec_ctx;
280 ErrorContextCallback plerrcontext;
281
282 PLy_initialize();
283
284 /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
285 SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
286
287 MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
288 MemSet(&flinfo, 0, sizeof(flinfo));
289 fake_fcinfo->flinfo = &flinfo;
290 flinfo.fn_oid = InvalidOid;
291 flinfo.fn_mcxt = CurrentMemoryContext;
292
293 MemSet(&proc, 0, sizeof(PLyProcedure));
294 proc.mcxt = AllocSetContextCreate(TopMemoryContext,
295 "__plpython_inline_block",
296 ALLOCSET_DEFAULT_SIZES);
297 proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
298 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 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 exec_ctx = PLy_push_execution_context(codeblock->atomic);
312
313 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 plerrcontext.callback = plpython_inline_error_callback;
321 plerrcontext.arg = exec_ctx;
322 plerrcontext.previous = error_context_stack;
323 error_context_stack = &plerrcontext;
324
325 PLy_procedure_compile(&proc, codeblock->source_text);
326 exec_ctx->curr_proc = &proc;
327 PLy_exec_function(fake_fcinfo, &proc);
328 }
329 PG_CATCH();
330 {
331 PLy_pop_execution_context();
332 PLy_procedure_delete(&proc);
333 PyErr_Clear();
334 PG_RE_THROW();
335 }
336 PG_END_TRY();
337
338 /* Destroy the execution context */
339 PLy_pop_execution_context();
340
341 /* Now clean up the transient procedure we made */
342 PLy_procedure_delete(&proc);
343
344 PG_RETURN_VOID();
345}
346
347static PLyTrigType
348 PLy_procedure_is_trigger(Form_pg_proc procStruct)
349{
350 PLyTrigType ret;
351
352 switch (procStruct->prorettype)
353 {
354 case TRIGGEROID:
355 ret = PLPY_TRIGGER;
356 break;
357 case EVENT_TRIGGEROID:
358 ret = PLPY_EVENT_TRIGGER;
359 break;
360 default:
361 ret = PLPY_NOT_TRIGGER;
362 break;
363 }
364
365 return ret;
366}
367
368static void
369 plpython_error_callback(void *arg)
370{
371 PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
372
373 if (exec_ctx->curr_proc)
374 {
375 if (exec_ctx->curr_proc->is_procedure)
376 errcontext("PL/Python procedure \"%s\"",
377 PLy_procedure_name(exec_ctx->curr_proc));
378 else
379 errcontext("PL/Python function \"%s\"",
380 PLy_procedure_name(exec_ctx->curr_proc));
381 }
382}
383
384static void
385 plpython_inline_error_callback(void *arg)
386{
387 errcontext("PL/Python anonymous code block");
388}
389
390PLyExecutionContext *
391 PLy_current_execution_context(void)
392{
393 if (PLy_execution_contexts == NULL)
394 elog(ERROR, "no Python function is currently executing");
395
396 return PLy_execution_contexts;
397}
398
399MemoryContext
400 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 if (context->scratch_ctx == NULL)
407 context->scratch_ctx =
408 AllocSetContextCreate(TopTransactionContext,
409 "PL/Python scratch context",
410 ALLOCSET_DEFAULT_SIZES);
411 return context->scratch_ctx;
412}
413
414static PLyExecutionContext *
415 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 MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
422 sizeof(PLyExecutionContext));
423 context->curr_proc = NULL;
424 context->scratch_ctx = NULL;
425 context->next = PLy_execution_contexts;
426 PLy_execution_contexts = context;
427 return context;
428}
429
430static void
431 PLy_pop_execution_context(void)
432{
433 PLyExecutionContext *context = PLy_execution_contexts;
434
435 if (context == NULL)
436 elog(ERROR, "no Python function is currently executing");
437
438 PLy_execution_contexts = context->next;
439
440 if (context->scratch_ctx)
441 MemoryContextDelete(context->scratch_ctx);
442 pfree(context);
443}
#define MemSet(start, val, len)
Definition: c.h:1019
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:664
int errdetail(const char *fmt,...)
Definition: elog.c:1207
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:198
#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:153
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:49
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2109
#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:529
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define PLy_elog
Definition: jsonb_plpython.c:61
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
MemoryContext TopTransactionContext
Definition: mcxt.c:171
void pfree(void *pointer)
Definition: mcxt.c:1594
MemoryContext TopMemoryContext
Definition: mcxt.c:166
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
MemoryContext PortalContext
Definition: mcxt.c:175
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1888
#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
void PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:435
Datum PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:54
HeapTuple PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
Definition: plpy_exec.c:320
static int plpython_version_bitmask
Definition: plpy_main.c:52
Datum plpython3_validator(PG_FUNCTION_ARGS)
Definition: plpy_main.c:162
PyObject * PLy_interp_globals
Definition: plpy_main.c:55
static int * plpython_version_bitmask_ptr
Definition: plpy_main.c:51
static void PLy_initialize(void)
Definition: plpy_main.c:99
void _PG_init(void)
Definition: plpy_main.c:62
PG_FUNCTION_INFO_V1(plpython3_validator)
static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct)
Definition: plpy_main.c:348
static void plpython_inline_error_callback(void *arg)
Definition: plpy_main.c:385
static PLyExecutionContext * PLy_execution_contexts
Definition: plpy_main.c:58
Datum plpython3_inline_handler(PG_FUNCTION_ARGS)
Definition: plpy_main.c:273
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:391
static void plpython_error_callback(void *arg)
Definition: plpy_main.c:369
MemoryContext PLy_get_scratch_context(PLyExecutionContext *context)
Definition: plpy_main.c:400
PG_MODULE_MAGIC_EXT(.name="plpython",.version=PG_VERSION)
static PLyExecutionContext * PLy_push_execution_context(bool atomic_context)
Definition: plpy_main.c:415
static void PLy_pop_execution_context(void)
Definition: plpy_main.c:431
static void PLy_init_interp(void)
Definition: plpy_main.c:142
Datum plpython3_call_handler(PG_FUNCTION_ARGS)
Definition: plpy_main.c:195
PyMODINIT_FUNC PyInit_plpy(void)
void PLy_init_plpy(void)
char * PLy_procedure_name(PLyProcedure *proc)
Definition: plpy_procedure.c:46
void init_procedure_caches(void)
Definition: plpy_procedure.c:30
PLyProcedure * PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
Definition: plpy_procedure.c:66
void PLy_procedure_compile(PLyProcedure *proc, const char *src)
void PLy_procedure_delete(PLyProcedure *proc)
PLyTrigType
Definition: plpy_procedure.h:18
@ PLPY_EVENT_TRIGGER
Definition: plpy_procedure.h:20
@ PLPY_TRIGGER
Definition: plpy_procedure.h:19
@ PLPY_NOT_TRIGGER
Definition: plpy_procedure.h:21
List * explicit_subtransactions
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetRelid(relation)
Definition: rel.h:514
int SPI_connect_ext(int options)
Definition: spi.c:100
#define SPI_OPT_NONATOMIC
Definition: spi.h:102
struct ErrorContextCallback * previous
Definition: elog.h:297
void * arg
Definition: elog.h:299
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:3621
struct PLyExecutionContext * next
Definition: plpy_main.h:22
PLyProcedure * curr_proc
Definition: plpy_main.h:20
MemoryContext scratch_ctx
Definition: plpy_main.h:21
bool is_procedure
Definition: plpy_procedure.h:45
char * pyname
Definition: plpy_procedure.h:40
PLyObToDatum result
Definition: plpy_procedure.h:47
MemoryContext mcxt
Definition: plpy_procedure.h:37
Definition: rel.h:56
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26
const char * name

AltStyle によって変換されたページ (->オリジナル) /