]> granicus.if.org Git - postgresql/blob - src/pl/plpython/plpy_main.c
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / pl / plpython / plpy_main.c
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
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
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
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
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
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
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
293 plpython2_call_handler(PG_FUNCTION_ARGS)
294 {
295         return plpython_call_handler(fcinfo);
296 }
297 #endif                                                  /* PY_MAJOR_VERSION < 3 */
298
299 Datum
300 plpython_inline_handler(PG_FUNCTION_ARGS)
301 {
302         LOCAL_FCINFO(fake_fcinfo, 0);
303         InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
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(fcinfo, 0, SizeForFunctionCallInfo(0));
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
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
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
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
408 plpython_inline_error_callback(void *arg)
409 {
410         errcontext("PL/Python anonymous code block");
411 }
412
413 PLyExecutionContext *
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
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 *
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
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 }