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