Line data Source code
1 : /*
2 : * PL/Python main entry points
3 : *
4 : * src/pl/plpython/plpy_main.c
5 : */
6 :
7 : #include "postgres.h"
8 :
9 : #include "catalog/pg_proc.h"
10 : #include "commands/event_trigger.h"
11 : #include "commands/trigger.h"
12 : #include "executor/spi.h"
13 : #include "miscadmin.h"
14 : #include "plpy_elog.h"
15 : #include "plpy_exec.h"
16 : #include "plpy_main.h"
17 : #include "plpy_plpymodule.h"
18 : #include "plpy_subxactobject.h"
19 : #include "plpy_util.h"
20 : #include "utils/guc.h"
21 : #include "utils/memutils.h"
22 : #include "utils/syscache.h"
23 :
24 : /*
25 : * exported functions
26 : */
27 :
28 23 : PG_MODULE_MAGIC_EXT(
29 : .name = "plpython",
30 : .version = PG_VERSION
31 : );
32 :
33 26 : PG_FUNCTION_INFO_V1(plpython3_validator);
34 26 : PG_FUNCTION_INFO_V1(plpython3_call_handler);
35 8 : PG_FUNCTION_INFO_V1(plpython3_inline_handler);
36 :
37 :
38 : static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
39 : static void plpython_error_callback(void *arg);
40 : static void plpython_inline_error_callback(void *arg);
41 :
42 : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
43 : static void PLy_pop_execution_context(void);
44 :
45 : /* initialize global variables */
46 : PyObject *PLy_interp_globals = NULL;
47 :
48 : /* this doesn't need to be global; use PLy_current_execution_context() */
49 : static PLyExecutionContext *PLy_execution_contexts = NULL;
50 :
51 :
52 : void
53 23 : _PG_init(void)
54 : {
55 : PyObject *main_mod;
56 : PyObject *main_dict;
57 : PyObject *GD;
58 : PyObject *plpy_mod;
59 :
60 23 : pg_bindtextdomain(TEXTDOMAIN);
61 :
62 : /* Add plpy to table of built-in modules. */
63 23 : PyImport_AppendInittab("plpy", PyInit_plpy);
64 :
65 : /* Initialize Python interpreter. */
66 23 : Py_Initialize();
67 :
68 23 : main_mod = PyImport_AddModule("__main__");
69 23 : if (main_mod == NULL || PyErr_Occurred())
70 0 : PLy_elog(ERROR, "could not import \"%s\" module", "__main__");
71 : Py_INCREF(main_mod);
72 :
73 23 : main_dict = PyModule_GetDict(main_mod);
74 23 : if (main_dict == NULL)
75 0 : PLy_elog(ERROR, NULL);
76 :
77 : /*
78 : * Set up GD.
79 : */
80 23 : GD = PyDict_New();
81 23 : if (GD == NULL)
82 0 : PLy_elog(ERROR, NULL);
83 23 : PyDict_SetItemString(main_dict, "GD", GD);
84 :
85 : /*
86 : * Import plpy.
87 : */
88 23 : plpy_mod = PyImport_ImportModule("plpy");
89 23 : if (plpy_mod == NULL)
90 0 : PLy_elog(ERROR, "could not import \"%s\" module", "plpy");
91 23 : if (PyDict_SetItemString(main_dict, "plpy", plpy_mod) == -1)
92 0 : PLy_elog(ERROR, NULL);
93 :
94 23 : if (PyErr_Occurred())
95 0 : PLy_elog(FATAL, "untrapped error in initialization");
96 :
97 : Py_INCREF(main_dict);
98 23 : PLy_interp_globals = main_dict;
99 :
100 : Py_DECREF(main_mod);
101 :
102 23 : explicit_subtransactions = NIL;
103 :
104 23 : PLy_execution_contexts = NULL;
105 23 : }
106 :
107 : Datum
108 253 : plpython3_validator(PG_FUNCTION_ARGS)
109 : {
110 253 : LOCAL_FCINFO(fake_fcinfo, 0);
111 253 : Oid funcoid = PG_GETARG_OID(0);
112 : HeapTuple tuple;
113 : Form_pg_proc procStruct;
114 : PLyTrigType is_trigger;
115 : TriggerData trigdata;
116 : EventTriggerData etrigdata;
117 : FmgrInfo flinfo;
118 : PLyProcedureCache *pcache;
119 :
120 253 : if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
121 0 : PG_RETURN_VOID();
122 :
123 253 : if (!check_function_bodies)
124 1 : PG_RETURN_VOID();
125 :
126 : /* Get the new function's pg_proc entry */
127 252 : tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
128 252 : if (!HeapTupleIsValid(tuple))
129 0 : elog(ERROR, "cache lookup failed for function %u", funcoid);
130 252 : procStruct = (Form_pg_proc) GETSTRUCT(tuple);
131 :
132 252 : is_trigger = PLy_procedure_is_trigger(procStruct);
133 :
134 252 : ReleaseSysCache(tuple);
135 :
136 : /*
137 : * Set up a fake flinfo/fcinfo with just enough info to satisfy
138 : * PLy_procedure_get(). That function derives the call context (plain
139 : * function, DML trigger, or event trigger) from the fcinfo, so we have to
140 : * construct matching context here.
141 : */
142 1260 : MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
143 1764 : MemSet(&flinfo, 0, sizeof(flinfo));
144 252 : fake_fcinfo->flinfo = &flinfo;
145 252 : flinfo.fn_oid = funcoid;
146 252 : flinfo.fn_mcxt = CurrentMemoryContext;
147 :
148 252 : if (is_trigger == PLPY_TRIGGER)
149 : {
150 264 : MemSet(&trigdata, 0, sizeof(trigdata));
151 24 : trigdata.type = T_TriggerData;
152 : /* We can't validate triggers against any particular table ... */
153 24 : fake_fcinfo->context = (Node *) &trigdata;
154 : }
155 228 : else if (is_trigger == PLPY_EVENT_TRIGGER)
156 : {
157 5 : MemSet(&etrigdata, 0, sizeof(etrigdata));
158 1 : etrigdata.type = T_EventTriggerData;
159 1 : fake_fcinfo->context = (Node *) &etrigdata;
160 : }
161 :
162 252 : pcache = PLy_procedure_get(fake_fcinfo, true);
163 :
164 : /*
165 : * Release the reference count that PLy_procedure_get acquired; the
166 : * PLyProcedure object remains valid for possible future use. (We could
167 : * leave this to be done when the calling memory context is cleaned up,
168 : * but it seems neater to do it right away. Note we mustn't release the
169 : * pcache object, since the memory-context reset callback has a reference
170 : * to it.)
171 : */
172 : Assert(pcache->proc->cfunc.use_count > 0);
173 251 : pcache->proc->cfunc.use_count--;
174 251 : pcache->proc = NULL;
175 :
176 251 : PG_RETURN_VOID();
177 : }
178 :
179 : Datum
180 714 : plpython3_call_handler(PG_FUNCTION_ARGS)
181 : {
182 : bool nonatomic;
183 : Datum retval;
184 : PLyExecutionContext *exec_ctx;
185 : ErrorContextCallback plerrcontext;
186 :
187 1495 : nonatomic = fcinfo->context &&
188 722 : IsA(fcinfo->context, CallContext) &&
189 8 : !castNode(CallContext, fcinfo->context)->atomic;
190 :
191 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
192 714 : SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
193 :
194 : /*
195 : * Push execution context onto stack. It is important that this get
196 : * popped again, so avoid putting anything that could throw error between
197 : * here and the PG_TRY.
198 : */
199 714 : exec_ctx = PLy_push_execution_context(!nonatomic);
200 :
201 714 : PG_TRY();
202 : {
203 : PLyProcedureCache *pcache;
204 :
205 : /*
206 : * Setup error traceback support for ereport(). Note that the PG_TRY
207 : * structure pops this for us again at exit, so we needn't do that
208 : * explicitly, nor do we risk the callback getting called after we've
209 : * destroyed the exec_ctx.
210 : */
211 714 : plerrcontext.callback = plpython_error_callback;
212 714 : plerrcontext.arg = exec_ctx;
213 714 : plerrcontext.previous = error_context_stack;
214 714 : error_context_stack = &plerrcontext;
215 :
216 : /*
217 : * Look up (and if necessary compile) the procedure. This can throw
218 : * an error, so it must happen inside the PG_TRY so that the execution
219 : * context gets popped on the way out.
220 : */
221 714 : pcache = PLy_procedure_get(fcinfo, false);
222 711 : exec_ctx->curr_proc = pcache->proc;
223 :
224 711 : if (CALLED_AS_TRIGGER(fcinfo))
225 40 : {
226 : HeapTuple trv;
227 :
228 49 : trv = PLy_exec_trigger(fcinfo, pcache->proc);
229 40 : retval = PointerGetDatum(trv);
230 : }
231 662 : else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
232 : {
233 10 : PLy_exec_event_trigger(fcinfo, pcache->proc);
234 10 : retval = (Datum) 0;
235 : }
236 : else
237 652 : retval = PLy_exec_function(fcinfo, pcache);
238 : }
239 93 : PG_CATCH();
240 : {
241 : /* Destroy the execution context */
242 93 : PLy_pop_execution_context();
243 93 : PyErr_Clear();
244 :
245 93 : PG_RE_THROW();
246 : }
247 621 : PG_END_TRY();
248 :
249 : /* Destroy the execution context */
250 621 : PLy_pop_execution_context();
251 :
252 621 : return retval;
253 : }
254 :
255 : Datum
256 21 : plpython3_inline_handler(PG_FUNCTION_ARGS)
257 : {
258 21 : LOCAL_FCINFO(fake_fcinfo, 0);
259 21 : InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
260 : FmgrInfo flinfo;
261 : PLyProcedure proc;
262 : PLyProcedureCache pcache;
263 : PLyExecutionContext *exec_ctx;
264 : ErrorContextCallback plerrcontext;
265 :
266 : /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
267 21 : SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
268 :
269 105 : MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
270 147 : MemSet(&flinfo, 0, sizeof(flinfo));
271 21 : fake_fcinfo->flinfo = &flinfo;
272 21 : flinfo.fn_oid = InvalidOid;
273 21 : flinfo.fn_mcxt = CurrentMemoryContext;
274 :
275 945 : MemSet(&proc, 0, sizeof(PLyProcedure));
276 21 : proc.mcxt = AllocSetContextCreate(TopMemoryContext,
277 : "__plpython_inline_block",
278 : ALLOCSET_DEFAULT_SIZES);
279 21 : proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
280 21 : proc.langid = codeblock->langOid;
281 :
282 : /*
283 : * This is currently sufficient to get PLy_exec_function to work, but
284 : * someday we might need to be honest and use PLy_output_setup_func.
285 : */
286 21 : proc.result.typoid = VOIDOID;
287 :
288 : /* Set up a minimal PLyProcedureCache for the inline block */
289 168 : MemSet(&pcache, 0, sizeof(PLyProcedureCache));
290 21 : pcache.proc = &proc;
291 21 : pcache.fcontext = CurrentMemoryContext;
292 :
293 : /*
294 : * Push execution context onto stack. It is important that this get
295 : * popped again, so avoid putting anything that could throw error between
296 : * here and the PG_TRY.
297 : */
298 21 : exec_ctx = PLy_push_execution_context(codeblock->atomic);
299 :
300 21 : PG_TRY();
301 : {
302 : /*
303 : * Setup error traceback support for ereport().
304 : * plpython_inline_error_callback doesn't currently need exec_ctx, but
305 : * for consistency with plpython3_call_handler we do it the same way.
306 : */
307 21 : plerrcontext.callback = plpython_inline_error_callback;
308 21 : plerrcontext.arg = exec_ctx;
309 21 : plerrcontext.previous = error_context_stack;
310 21 : error_context_stack = &plerrcontext;
311 :
312 21 : PLy_procedure_compile(&proc, codeblock->source_text);
313 21 : exec_ctx->curr_proc = &proc;
314 21 : PLy_exec_function(fake_fcinfo, &pcache);
315 : }
316 11 : PG_CATCH();
317 : {
318 11 : PLy_pop_execution_context();
319 11 : PLy_procedure_delete(&proc);
320 11 : PyErr_Clear();
321 11 : PG_RE_THROW();
322 : }
323 10 : PG_END_TRY();
324 :
325 : /* Destroy the execution context */
326 10 : PLy_pop_execution_context();
327 :
328 : /* Now clean up the transient procedure we made */
329 10 : PLy_procedure_delete(&proc);
330 :
331 10 : PG_RETURN_VOID();
332 : }
333 :
334 : /*
335 : * Determine whether a function is a (DML or event) trigger from its pg_proc
336 : * result type. This is used by the validator, which has no call context to
337 : * inspect; the call handler instead relies on the fcinfo's call context.
338 : */
339 : static PLyTrigType
340 252 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
341 : {
342 : PLyTrigType ret;
343 :
344 252 : switch (procStruct->prorettype)
345 : {
346 24 : case TRIGGEROID:
347 24 : ret = PLPY_TRIGGER;
348 24 : break;
349 1 : case EVENT_TRIGGEROID:
350 1 : ret = PLPY_EVENT_TRIGGER;
351 1 : break;
352 227 : default:
353 227 : ret = PLPY_NOT_TRIGGER;
354 227 : break;
355 : }
356 :
357 252 : return ret;
358 : }
359 :
360 : static void
361 466 : plpython_error_callback(void *arg)
362 : {
363 466 : PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
364 :
365 466 : if (exec_ctx->curr_proc)
366 : {
367 463 : if (exec_ctx->curr_proc->is_procedure)
368 4 : errcontext("PL/Python procedure \"%s\"",
369 : PLy_procedure_name(exec_ctx->curr_proc));
370 : else
371 459 : errcontext("PL/Python function \"%s\"",
372 : PLy_procedure_name(exec_ctx->curr_proc));
373 : }
374 466 : }
375 :
376 : static void
377 28 : plpython_inline_error_callback(void *arg)
378 : {
379 28 : errcontext("PL/Python anonymous code block");
380 28 : }
381 :
382 : PLyExecutionContext *
383 1444 : PLy_current_execution_context(void)
384 : {
385 1444 : if (PLy_execution_contexts == NULL)
386 0 : elog(ERROR, "no Python function is currently executing");
387 :
388 1444 : return PLy_execution_contexts;
389 : }
390 :
391 : MemoryContext
392 803 : PLy_get_scratch_context(PLyExecutionContext *context)
393 : {
394 : /*
395 : * A scratch context might never be needed in a given plpython procedure,
396 : * so allocate it on first request.
397 : */
398 803 : if (context->scratch_ctx == NULL)
399 446 : context->scratch_ctx =
400 446 : AllocSetContextCreate(TopTransactionContext,
401 : "PL/Python scratch context",
402 : ALLOCSET_DEFAULT_SIZES);
403 803 : return context->scratch_ctx;
404 : }
405 :
406 : static PLyExecutionContext *
407 735 : PLy_push_execution_context(bool atomic_context)
408 : {
409 : PLyExecutionContext *context;
410 :
411 : /* Pick a memory context similar to what SPI uses. */
412 : context = (PLyExecutionContext *)
413 735 : MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
414 : sizeof(PLyExecutionContext));
415 735 : context->curr_proc = NULL;
416 735 : context->scratch_ctx = NULL;
417 735 : context->next = PLy_execution_contexts;
418 735 : PLy_execution_contexts = context;
419 735 : return context;
420 : }
421 :
422 : static void
423 735 : PLy_pop_execution_context(void)
424 : {
425 735 : PLyExecutionContext *context = PLy_execution_contexts;
426 :
427 735 : if (context == NULL)
428 0 : elog(ERROR, "no Python function is currently executing");
429 :
430 735 : PLy_execution_contexts = context->next;
431 :
432 735 : if (context->scratch_ctx)
433 429 : MemoryContextDelete(context->scratch_ctx);
434 735 : pfree(context);
435 735 : }
|