Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * executing Python code
3 : : *
4 : : * src/pl/plpython/plpy_exec.c
5 : : */
6 : :
7 : : #include "postgres.h"
8 : :
9 : : #include "access/htup_details.h"
10 : : #include "access/xact.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 "funcapi.h"
16 : : #include "plpy_elog.h"
17 : : #include "plpy_exec.h"
18 : : #include "plpy_main.h"
19 : : #include "plpy_procedure.h"
20 : : #include "plpy_subxactobject.h"
21 : : #include "plpy_util.h"
22 : : #include "utils/fmgrprotos.h"
23 : : #include "utils/rel.h"
24 : :
25 : : /* saved state for a set-returning function */
26 : : typedef struct PLySRFState
27 : : {
28 : : PyObject *iter; /* Python iterator producing results */
29 : : PLySavedArgs *savedargs; /* function argument values */
30 : : MemoryContextCallback callback; /* for releasing refcounts when done */
31 : : } PLySRFState;
32 : :
33 : : static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc);
34 : : static PLySavedArgs *PLy_function_save_args(PLyProcedure *proc);
35 : : static void PLy_function_restore_args(PLyProcedure *proc, PLySavedArgs *savedargs);
36 : : static void PLy_function_drop_args(PLySavedArgs *savedargs);
37 : : static void PLy_global_args_push(PLyProcedure *proc);
38 : : static void PLy_global_args_pop(PLyProcedure *proc);
39 : : static void plpython_srf_cleanup_callback(void *arg);
40 : : static void plpython_return_error_callback(void *arg);
41 : :
42 : : static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc,
43 : : HeapTuple *rv);
44 : : static HeapTuple PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd,
45 : : TriggerData *tdata, HeapTuple otup);
46 : : static void plpython_trigger_error_callback(void *arg);
47 : :
48 : : static PyObject *PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs);
49 : : static void PLy_abort_open_subtransactions(int save_subxact_level);
50 : :
51 : :
52 : : /* function subhandler */
53 : : Datum
5277 peter_e@gmx.net 54 :CBC 660 : PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
55 : : {
3203 56 : 660 : bool is_setof = proc->is_setof;
57 : : Datum rv;
5277 58 : 660 : PyObject *volatile plargs = NULL;
59 : 660 : PyObject *volatile plrv = NULL;
3707 tgl@sss.pgh.pa.us 60 : 660 : FuncCallContext *volatile funcctx = NULL;
61 : 660 : PLySRFState *volatile srfstate = NULL;
62 : : ErrorContextCallback plerrcontext;
63 : :
64 : : /*
65 : : * If the function is called recursively, we must push outer-level
66 : : * arguments into the stack. This must be immediately before the PG_TRY
67 : : * to ensure that the corresponding pop happens.
68 : : */
69 : 660 : PLy_global_args_push(proc);
70 : :
5277 peter_e@gmx.net 71 [ + + ]: 660 : PG_TRY();
72 : : {
3203 73 [ + + ]: 660 : if (is_setof)
74 : : {
75 : : /* First Call setup */
3707 tgl@sss.pgh.pa.us 76 [ + + ]: 200 : if (SRF_IS_FIRSTCALL())
77 : : {
78 : 53 : funcctx = SRF_FIRSTCALL_INIT();
79 : 53 : srfstate = (PLySRFState *)
80 : 53 : MemoryContextAllocZero(funcctx->multi_call_memory_ctx,
81 : : sizeof(PLySRFState));
82 : : /* Immediately register cleanup callback */
83 : 53 : srfstate->callback.func = plpython_srf_cleanup_callback;
548 peter@eisentraut.org 84 : 53 : srfstate->callback.arg = srfstate;
3707 tgl@sss.pgh.pa.us 85 : 53 : MemoryContextRegisterResetCallback(funcctx->multi_call_memory_ctx,
86 : 53 : &srfstate->callback);
548 peter@eisentraut.org 87 : 53 : funcctx->user_fctx = srfstate;
88 : : }
89 : : /* Every call setup */
3707 tgl@sss.pgh.pa.us 90 : 200 : funcctx = SRF_PERCALL_SETUP();
91 [ - + ]: 200 : Assert(funcctx != NULL);
92 : 200 : srfstate = (PLySRFState *) funcctx->user_fctx;
3203 peter_e@gmx.net 93 [ - + ]: 200 : Assert(srfstate != NULL);
94 : : }
95 : :
3707 tgl@sss.pgh.pa.us 96 [ + + + + ]: 660 : if (srfstate == NULL || srfstate->iter == NULL)
97 : : {
98 : : /*
99 : : * Non-SETOF function or first time for SETOF function: build
100 : : * args, then actually execute the function.
101 : : */
5277 peter_e@gmx.net 102 : 513 : plargs = PLy_function_build_args(fcinfo, proc);
103 : 513 : plrv = PLy_procedure_call(proc, "args", plargs);
104 [ - + ]: 459 : Assert(plrv != NULL);
105 : : }
106 : : else
107 : : {
108 : : /*
109 : : * Second or later call for a SETOF function: restore arguments in
110 : : * globals dict to what they were when we left off. We must do
111 : : * this in case multiple evaluations of the same SETOF function
112 : : * are interleaved. It's a bit annoying, since the iterator may
113 : : * not look at the arguments at all, but we have no way to know
114 : : * that. Fortunately this isn't terribly expensive.
115 : : */
3707 tgl@sss.pgh.pa.us 116 [ + - ]: 147 : if (srfstate->savedargs)
117 : 147 : PLy_function_restore_args(proc, srfstate->savedargs);
118 : 147 : srfstate->savedargs = NULL; /* deleted by restore_args */
119 : : }
120 : :
121 : : /*
122 : : * If it returns a set, call the iterator to get the next return item.
123 : : * We stay in the SPI context while doing this, because PyIter_Next()
124 : : * calls back into Python code which might contain SPI calls.
125 : : */
3203 peter_e@gmx.net 126 [ + + ]: 606 : if (is_setof)
127 : : {
3707 tgl@sss.pgh.pa.us 128 [ + + ]: 199 : if (srfstate->iter == NULL)
129 : : {
130 : : /* first time -- do checks and setup */
131 : 52 : ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
132 : :
5277 peter_e@gmx.net 133 [ + - + - ]: 52 : if (!rsi || !IsA(rsi, ReturnSetInfo) ||
134 [ - + ]: 52 : (rsi->allowedModes & SFRM_ValuePerCall) == 0)
135 : : {
5277 peter_e@gmx.net 136 [ # # ]:UBC 0 : ereport(ERROR,
137 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
138 : : errmsg("unsupported set function return mode"),
139 : : errdetail("PL/Python set-returning functions only support returning one value per call.")));
140 : : }
5277 peter_e@gmx.net 141 :CBC 52 : rsi->returnMode = SFRM_ValuePerCall;
142 : :
143 : : /* Make iterator out of returned object */
3707 tgl@sss.pgh.pa.us 144 : 52 : srfstate->iter = PyObject_GetIter(plrv);
145 : :
5277 peter_e@gmx.net 146 : 52 : Py_DECREF(plrv);
147 : 52 : plrv = NULL;
148 : :
3707 tgl@sss.pgh.pa.us 149 [ + + ]: 52 : if (srfstate->iter == NULL)
5277 peter_e@gmx.net 150 [ + - ]: 1 : ereport(ERROR,
151 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
152 : : errmsg("returned object cannot be iterated"),
153 : : errdetail("PL/Python set-returning functions must return an iterable object.")));
154 : : }
155 : :
156 : : /* Fetch next from iterator */
3707 tgl@sss.pgh.pa.us 157 : 198 : plrv = PyIter_Next(srfstate->iter);
158 [ + + ]: 198 : if (plrv == NULL)
159 : : {
160 : : /* Iterator is exhausted or error happened */
161 : 49 : bool has_error = (PyErr_Occurred() != NULL);
162 : :
163 : 49 : Py_DECREF(srfstate->iter);
164 : 49 : srfstate->iter = NULL;
165 : :
5277 peter_e@gmx.net 166 [ + + ]: 49 : if (has_error)
167 : 1 : PLy_elog(ERROR, "error fetching next item from iterator");
168 : :
169 : : /* Pass a null through the data-returning steps below */
170 : : Py_INCREF(Py_None);
3707 tgl@sss.pgh.pa.us 171 : 48 : plrv = Py_None;
172 : : }
173 : : else
174 : : {
175 : : /*
176 : : * This won't be last call, so save argument values. We do
177 : : * this again each time in case the iterator is changing those
178 : : * values.
179 : : */
180 : 149 : srfstate->savedargs = PLy_function_save_args(proc);
181 : : }
182 : : }
183 : :
184 : : /*
185 : : * Disconnect from SPI manager and then create the return values datum
186 : : * (if the input function does a palloc for it this must not be
187 : : * allocated in the SPI memory context because SPI_finish would free
188 : : * it).
189 : : */
5277 peter_e@gmx.net 190 [ - + ]: 604 : if (SPI_finish() != SPI_OK_FINISH)
5277 peter_e@gmx.net 191 [ # # ]:UBC 0 : elog(ERROR, "SPI_finish failed");
192 : :
5277 peter_e@gmx.net 193 :CBC 604 : plerrcontext.callback = plpython_return_error_callback;
194 : 604 : plerrcontext.previous = error_context_stack;
195 : 604 : error_context_stack = &plerrcontext;
196 : :
197 : : /*
198 : : * For a procedure or function declared to return void, the Python
199 : : * return value must be None. For void-returning functions, we also
200 : : * treat a None return value as a special "void datum" rather than
201 : : * NULL (as is the case for non-void-returning functions).
202 : : */
2999 203 [ + + ]: 604 : if (proc->result.typoid == VOIDOID)
204 : : {
3103 205 [ + + ]: 29 : if (plrv != Py_None)
206 : : {
2999 207 [ + + ]: 2 : if (proc->is_procedure)
208 [ + - ]: 1 : ereport(ERROR,
209 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
210 : : errmsg("PL/Python procedure did not return None")));
211 : : else
212 [ + - ]: 1 : ereport(ERROR,
213 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
214 : : errmsg("PL/Python function with return type \"void\" did not return None")));
215 : : }
216 : :
5277 217 : 27 : fcinfo->isnull = false;
218 : 27 : rv = (Datum) 0;
219 : : }
3117 tgl@sss.pgh.pa.us 220 [ + + + + ]: 575 : else if (plrv == Py_None &&
221 [ + + ]: 55 : srfstate && srfstate->iter == NULL)
222 : : {
223 : : /*
224 : : * In a SETOF function, the iteration-ending null isn't a real
225 : : * value; don't pass it through the input function, which might
226 : : * complain.
227 : : */
228 : 48 : fcinfo->isnull = true;
229 : 48 : rv = (Datum) 0;
230 : : }
231 : : else
232 : : {
233 : : /*
234 : : * Normal conversion of result. However, if the result is of type
235 : : * RECORD, we have to set up for that each time through, since it
236 : : * might be different from last time.
237 : : */
751 238 [ + + ]: 527 : if (proc->result.typoid == RECORDOID)
239 : : {
240 : : TupleDesc desc;
241 : :
242 [ - + ]: 134 : if (get_call_result_type(fcinfo, NULL, &desc) != TYPEFUNC_COMPOSITE)
751 tgl@sss.pgh.pa.us 243 [ # # ]:UBC 0 : ereport(ERROR,
244 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
245 : : errmsg("function returning record called in context "
246 : : "that cannot accept type record")));
751 tgl@sss.pgh.pa.us 247 :CBC 134 : PLy_output_setup_record(&proc->result, desc, proc);
248 : : }
249 : :
3117 250 : 527 : rv = PLy_output_convert(&proc->result, plrv,
251 : : &fcinfo->isnull);
252 : : }
253 : : }
5277 peter_e@gmx.net 254 : 92 : PG_CATCH();
255 : : {
256 : : /* Pop old arguments from the stack if they were pushed above */
3707 tgl@sss.pgh.pa.us 257 : 92 : PLy_global_args_pop(proc);
258 : :
5277 peter_e@gmx.net 259 : 92 : Py_XDECREF(plargs);
260 : 92 : Py_XDECREF(plrv);
261 : :
262 : : /*
263 : : * If there was an error within a SRF, the iterator might not have
264 : : * been exhausted yet. Clear it so the next invocation of the
265 : : * function will start the iteration again. (This code is probably
266 : : * unnecessary now; plpython_srf_cleanup_callback should take care of
267 : : * cleanup. But it doesn't hurt anything to do it here.)
268 : : */
3707 tgl@sss.pgh.pa.us 269 [ + + ]: 92 : if (srfstate)
270 : : {
271 : 5 : Py_XDECREF(srfstate->iter);
272 : 5 : srfstate->iter = NULL;
273 : : /* And drop any saved args; we won't need them */
274 [ + + ]: 5 : if (srfstate->savedargs)
275 : 2 : PLy_function_drop_args(srfstate->savedargs);
276 : 5 : srfstate->savedargs = NULL;
277 : : }
278 : :
5277 peter_e@gmx.net 279 : 92 : PG_RE_THROW();
280 : : }
281 [ - + ]: 568 : PG_END_TRY();
282 : :
283 : 568 : error_context_stack = plerrcontext.previous;
284 : :
285 : : /* Pop old arguments from the stack if they were pushed above */
3707 tgl@sss.pgh.pa.us 286 : 568 : PLy_global_args_pop(proc);
287 : :
5277 peter_e@gmx.net 288 : 568 : Py_XDECREF(plargs);
289 : 568 : Py_DECREF(plrv);
290 : :
3707 tgl@sss.pgh.pa.us 291 [ + + ]: 568 : if (srfstate)
292 : : {
293 : : /* We're in a SRF, exit appropriately */
294 [ + + ]: 195 : if (srfstate->iter == NULL)
295 : : {
296 : : /* Iterator exhausted, so we're done */
297 : 48 : SRF_RETURN_DONE(funcctx);
298 : : }
299 [ + + ]: 147 : else if (fcinfo->isnull)
300 : 7 : SRF_RETURN_NEXT_NULL(funcctx);
301 : : else
302 : 140 : SRF_RETURN_NEXT(funcctx, rv);
303 : : }
304 : :
305 : : /* Plain function, just return the Datum value (possibly null) */
5277 peter_e@gmx.net 306 : 373 : return rv;
307 : : }
308 : :
309 : : /*
310 : : * trigger subhandler
311 : : *
312 : : * the python function is expected to return Py_None if the tuple is
313 : : * acceptable and unmodified. Otherwise it should return a PyUnicode
314 : : * object who's value is SKIP, or MODIFY. SKIP means don't perform
315 : : * this action. MODIFY means the tuple has been modified, so update
316 : : * tuple and perform action. SKIP and MODIFY assume the trigger fires
317 : : * BEFORE the event and is ROW level. postgres expects the function
318 : : * to take no arguments and return an argument of type trigger.
319 : : */
320 : : HeapTuple
321 : 49 : PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
322 : : {
323 : 49 : HeapTuple rv = NULL;
324 : 49 : PyObject *volatile plargs = NULL;
325 : 49 : PyObject *volatile plrv = NULL;
326 : : TriggerData *tdata;
327 : : TupleDesc rel_descr;
328 : :
329 [ + - - + ]: 49 : Assert(CALLED_AS_TRIGGER(fcinfo));
3117 tgl@sss.pgh.pa.us 330 : 49 : tdata = (TriggerData *) fcinfo->context;
331 : :
332 : : /*
333 : : * Input/output conversion for trigger tuples. We use the result and
334 : : * result_in fields to store the tuple conversion info. We do this over
335 : : * again on each call to cover the possibility that the relation's tupdesc
336 : : * changed since the trigger was last called. The PLy_xxx_setup_func
337 : : * calls should only happen once, but PLy_input_setup_tuple and
338 : : * PLy_output_setup_tuple are responsible for not doing repetitive work.
339 : : */
340 : 49 : rel_descr = RelationGetDescr(tdata->tg_relation);
341 [ + + ]: 49 : if (proc->result.typoid != rel_descr->tdtypeid)
342 : 26 : PLy_output_setup_func(&proc->result, proc->mcxt,
343 : : rel_descr->tdtypeid,
344 : : rel_descr->tdtypmod,
345 : : proc);
346 [ + + ]: 49 : if (proc->result_in.typoid != rel_descr->tdtypeid)
347 : 26 : PLy_input_setup_func(&proc->result_in, proc->mcxt,
348 : : rel_descr->tdtypeid,
349 : : rel_descr->tdtypmod,
350 : : proc);
351 : 49 : PLy_output_setup_tuple(&proc->result, rel_descr, proc);
352 : 49 : PLy_input_setup_tuple(&proc->result_in, rel_descr, proc);
353 : :
354 : : /*
355 : : * If the trigger is called recursively, we must push outer-level
356 : : * arguments into the stack. This must be immediately before the PG_TRY
357 : : * to ensure that the corresponding pop happens.
358 : : */
753 359 : 49 : PLy_global_args_push(proc);
360 : :
5277 peter_e@gmx.net 361 [ + + ]: 49 : PG_TRY();
362 : : {
363 : : int rc PG_USED_FOR_ASSERTS_ONLY;
364 : :
3343 kgrittn@postgresql.o 365 : 49 : rc = SPI_register_trigger_data(tdata);
366 [ - + ]: 49 : Assert(rc >= 0);
367 : :
5277 peter_e@gmx.net 368 : 49 : plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
369 : 49 : plrv = PLy_procedure_call(proc, "TD", plargs);
370 : :
371 [ - + ]: 49 : Assert(plrv != NULL);
372 : :
373 : : /*
374 : : * Disconnect from SPI manager
375 : : */
376 [ - + ]: 49 : if (SPI_finish() != SPI_OK_FINISH)
5277 peter_e@gmx.net 377 [ # # ]:UBC 0 : elog(ERROR, "SPI_finish failed");
378 : :
379 : : /*
380 : : * return of None means we're happy with the tuple
381 : : */
5277 peter_e@gmx.net 382 [ + + ]:CBC 49 : if (plrv != Py_None)
383 : : {
384 : : char *srv;
385 : :
1545 andres@anarazel.de 386 [ + + ]: 25 : if (PyUnicode_Check(plrv))
5277 peter_e@gmx.net 387 : 24 : srv = PLyUnicode_AsString(plrv);
388 : : else
389 : : {
390 [ + - ]: 1 : ereport(ERROR,
391 : : (errcode(ERRCODE_DATA_EXCEPTION),
392 : : errmsg("unexpected return value from trigger procedure"),
393 : : errdetail("Expected None or a string.")));
394 : : srv = NULL; /* keep compiler quiet */
395 : : }
396 : :
397 [ + + ]: 24 : if (pg_strcasecmp(srv, "SKIP") == 0)
398 : 1 : rv = NULL;
399 [ + + ]: 23 : else if (pg_strcasecmp(srv, "MODIFY") == 0)
400 : : {
401 [ + + ]: 21 : if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event) ||
402 [ + + ]: 9 : TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
403 : 20 : rv = PLy_modify_tuple(proc, plargs, tdata, rv);
404 : : else
405 [ + - ]: 1 : ereport(WARNING,
406 : : (errmsg("PL/Python trigger function returned \"MODIFY\" in a DELETE trigger -- ignored")));
407 : : }
408 [ + - ]: 2 : else if (pg_strcasecmp(srv, "OK") != 0)
409 : : {
410 : : /*
411 : : * accept "OK" as an alternative to None; otherwise, raise an
412 : : * error
413 : : */
414 [ + - ]: 2 : ereport(ERROR,
415 : : (errcode(ERRCODE_DATA_EXCEPTION),
416 : : errmsg("unexpected return value from trigger procedure"),
417 : : errdetail("Expected None, \"OK\", \"SKIP\", or \"MODIFY\".")));
418 : : }
419 : : }
420 : : }
2402 peter@eisentraut.org 421 : 9 : PG_FINALLY();
422 : : {
753 tgl@sss.pgh.pa.us 423 : 49 : PLy_global_args_pop(proc);
5277 peter_e@gmx.net 424 : 49 : Py_XDECREF(plargs);
425 : 49 : Py_XDECREF(plrv);
426 : : }
427 [ + + ]: 49 : PG_END_TRY();
428 : :
429 : 40 : return rv;
430 : : }
431 : :
432 : : /*
433 : : * event trigger subhandler
434 : : */
435 : : void
282 peter@eisentraut.org 436 :GNC 10 : PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
437 : : {
438 : : EventTriggerData *tdata;
439 : 10 : PyObject *volatile pltdata = NULL;
440 : :
441 [ + - - + ]: 10 : Assert(CALLED_AS_EVENT_TRIGGER(fcinfo));
442 : 10 : tdata = (EventTriggerData *) fcinfo->context;
443 : :
444 [ + - ]: 10 : PG_TRY();
445 : : {
446 : : PyObject *pltevent,
447 : : *plttag;
448 : :
449 : 10 : pltdata = PyDict_New();
450 [ - + ]: 10 : if (!pltdata)
282 peter@eisentraut.org 451 :UNC 0 : PLy_elog(ERROR, NULL);
452 : :
282 peter@eisentraut.org 453 :GNC 10 : pltevent = PLyUnicode_FromString(tdata->event);
454 : 10 : PyDict_SetItemString(pltdata, "event", pltevent);
455 : : Py_DECREF(pltevent);
456 : :
457 : 10 : plttag = PLyUnicode_FromString(GetCommandTagName(tdata->tag));
458 : 10 : PyDict_SetItemString(pltdata, "tag", plttag);
459 : : Py_DECREF(plttag);
460 : :
461 : 10 : PLy_procedure_call(proc, "TD", pltdata);
462 : :
463 [ - + ]: 10 : if (SPI_finish() != SPI_OK_FINISH)
282 peter@eisentraut.org 464 [ # # ]:UNC 0 : elog(ERROR, "SPI_finish() failed");
465 : : }
466 : 0 : PG_FINALLY();
467 : : {
282 peter@eisentraut.org 468 :GNC 10 : Py_XDECREF(pltdata);
469 : : }
470 [ - + ]: 10 : PG_END_TRY();
471 : 10 : }
472 : :
473 : : /* helper functions for Python code execution */
474 : :
475 : : static PyObject *
5277 peter_e@gmx.net 476 :CBC 513 : PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
477 : : {
478 : 513 : PyObject *volatile arg = NULL;
479 : : PyObject *args;
480 : : int i;
481 : :
482 : : /*
483 : : * Make any Py*_New() calls before the PG_TRY block so that we can quickly
484 : : * return NULL on failure. We can't return within the PG_TRY block, else
485 : : * we'd miss unwinding the exception stack.
486 : : */
1123 nathan@postgresql.or 487 : 513 : args = PyList_New(proc->nargs);
488 [ - + ]: 513 : if (!args)
1123 nathan@postgresql.or 489 :UBC 0 : return NULL;
490 : :
5277 peter_e@gmx.net 491 [ + - ]:CBC 513 : PG_TRY();
492 : : {
493 [ + + ]: 1228 : for (i = 0; i < proc->nargs; i++)
494 : : {
3117 tgl@sss.pgh.pa.us 495 : 715 : PLyDatumToOb *arginfo = &proc->args[i];
496 : :
2681 andres@anarazel.de 497 [ + + ]: 715 : if (fcinfo->args[i].isnull)
3117 tgl@sss.pgh.pa.us 498 : 121 : arg = NULL;
499 : : else
2681 andres@anarazel.de 500 : 594 : arg = PLy_input_convert(arginfo, fcinfo->args[i].value);
501 : :
5277 peter_e@gmx.net 502 [ + + ]: 715 : if (arg == NULL)
503 : : {
504 : : Py_INCREF(Py_None);
505 : 121 : arg = Py_None;
506 : : }
507 : :
508 [ - + ]: 715 : if (PyList_SetItem(args, i, arg) == -1)
5277 peter_e@gmx.net 509 :UBC 0 : PLy_elog(ERROR, "PyList_SetItem() failed, while setting up arguments");
510 : :
5277 peter_e@gmx.net 511 [ + - + + ]:CBC 715 : if (proc->argnames && proc->argnames[i] &&
3265 tgl@sss.pgh.pa.us 512 [ - + ]: 712 : PyDict_SetItemString(proc->globals, proc->argnames[i], arg) == -1)
5277 peter_e@gmx.net 513 :UBC 0 : PLy_elog(ERROR, "PyDict_SetItemString() failed, while setting up arguments");
5277 peter_e@gmx.net 514 :CBC 715 : arg = NULL;
515 : : }
516 : : }
5277 peter_e@gmx.net 517 :UBC 0 : PG_CATCH();
518 : : {
519 : 0 : Py_XDECREF(arg);
520 : 0 : Py_XDECREF(args);
521 : :
522 : 0 : PG_RE_THROW();
523 : : }
5277 peter_e@gmx.net 524 [ - + ]:CBC 513 : PG_END_TRY();
525 : :
526 : 513 : return args;
527 : : }
528 : :
529 : : /*
530 : : * Construct a PLySavedArgs struct representing the current values of the
531 : : * procedure's arguments in its globals dict. This can be used to restore
532 : : * those values when exiting a recursive call level or returning control to a
533 : : * set-returning function.
534 : : *
535 : : * This would not be necessary except for an ancient decision to make args
536 : : * available via the proc's globals :-( ... but we're stuck with that now.
537 : : */
538 : : static PLySavedArgs *
3707 tgl@sss.pgh.pa.us 539 : 160 : PLy_function_save_args(PLyProcedure *proc)
540 : : {
541 : : PLySavedArgs *result;
542 : :
543 : : /* saved args are always allocated in procedure's context */
544 : : result = (PLySavedArgs *)
545 : 160 : MemoryContextAllocZero(proc->mcxt,
546 : 160 : offsetof(PLySavedArgs, namedargs) +
547 : 160 : proc->nargs * sizeof(PyObject *));
548 : 160 : result->nargs = proc->nargs;
549 : :
550 : : /* Fetch the "args" list */
551 : 160 : result->args = PyDict_GetItemString(proc->globals, "args");
552 : 160 : Py_XINCREF(result->args);
553 : :
554 : : /* If it's a trigger, also save "TD" */
282 peter@eisentraut.org 555 [ + + ]:GNC 160 : if (proc->is_trigger == PLPY_TRIGGER)
556 : : {
753 tgl@sss.pgh.pa.us 557 :CBC 1 : result->td = PyDict_GetItemString(proc->globals, "TD");
558 : 1 : Py_XINCREF(result->td);
559 : : }
560 : :
561 : : /* Fetch all the named arguments */
3707 562 [ + + ]: 160 : if (proc->argnames)
563 : : {
564 : : int i;
565 : :
566 [ + + ]: 313 : for (i = 0; i < result->nargs; i++)
567 : : {
568 [ + - ]: 216 : if (proc->argnames[i])
569 : : {
570 : 432 : result->namedargs[i] = PyDict_GetItemString(proc->globals,
3265 571 : 216 : proc->argnames[i]);
3707 572 : 216 : Py_XINCREF(result->namedargs[i]);
573 : : }
574 : : }
575 : : }
576 : :
577 : 160 : return result;
578 : : }
579 : :
580 : : /*
581 : : * Restore procedure's arguments from a PLySavedArgs struct,
582 : : * then free the struct.
583 : : */
584 : : static void
585 : 158 : PLy_function_restore_args(PLyProcedure *proc, PLySavedArgs *savedargs)
586 : : {
587 : : /* Restore named arguments into their slots in the globals dict */
588 [ + + ]: 158 : if (proc->argnames)
589 : : {
590 : : int i;
591 : :
592 [ + + ]: 313 : for (i = 0; i < savedargs->nargs; i++)
593 : : {
594 [ + - + - ]: 216 : if (proc->argnames[i] && savedargs->namedargs[i])
595 : : {
596 : 216 : PyDict_SetItemString(proc->globals, proc->argnames[i],
597 : : savedargs->namedargs[i]);
598 : 216 : Py_DECREF(savedargs->namedargs[i]);
599 : : }
600 : : }
601 : : }
602 : :
603 : : /* Restore the "args" object, too */
604 [ + + ]: 158 : if (savedargs->args)
605 : : {
606 : 157 : PyDict_SetItemString(proc->globals, "args", savedargs->args);
607 : 157 : Py_DECREF(savedargs->args);
608 : : }
609 : :
610 : : /* Restore the "TD" object, too */
753 611 [ + + ]: 158 : if (savedargs->td)
612 : : {
613 : 1 : PyDict_SetItemString(proc->globals, "TD", savedargs->td);
614 : 1 : Py_DECREF(savedargs->td);
615 : : }
616 : :
617 : : /* And free the PLySavedArgs struct */
3707 618 : 158 : pfree(savedargs);
619 : 158 : }
620 : :
621 : : /*
622 : : * Free a PLySavedArgs struct without restoring the values.
623 : : */
624 : : static void
625 : 2 : PLy_function_drop_args(PLySavedArgs *savedargs)
626 : : {
627 : : int i;
628 : :
629 : : /* Drop references for named args */
630 [ - + ]: 2 : for (i = 0; i < savedargs->nargs; i++)
631 : : {
3707 tgl@sss.pgh.pa.us 632 :UBC 0 : Py_XDECREF(savedargs->namedargs[i]);
633 : : }
634 : :
635 : : /* Drop refs to the "args" and "TD" objects, too */
3707 tgl@sss.pgh.pa.us 636 :CBC 2 : Py_XDECREF(savedargs->args);
753 637 : 2 : Py_XDECREF(savedargs->td);
638 : :
639 : : /* And free the PLySavedArgs struct */
3707 640 : 2 : pfree(savedargs);
641 : 2 : }
642 : :
643 : : /*
644 : : * Save away any existing arguments for the given procedure, so that we can
645 : : * install new values for a recursive call. This should be invoked before
646 : : * doing PLy_function_build_args() or PLy_trigger_build_args().
647 : : *
648 : : * NB: callers must ensure that PLy_global_args_pop gets invoked once, and
649 : : * only once, per successful completion of PLy_global_args_push. Otherwise
650 : : * we'll end up out-of-sync between the actual call stack and the contents
651 : : * of proc->argstack.
652 : : */
653 : : static void
654 : 709 : PLy_global_args_push(PLyProcedure *proc)
655 : : {
656 : : /* We only need to push if we are already inside some active call */
657 [ + + ]: 709 : if (proc->calldepth > 0)
658 : : {
659 : : PLySavedArgs *node;
660 : :
661 : : /* Build a struct containing current argument values */
662 : 11 : node = PLy_function_save_args(proc);
663 : :
664 : : /*
665 : : * Push the saved argument values into the procedure's stack. Once we
666 : : * modify either proc->argstack or proc->calldepth, we had better
667 : : * return without the possibility of error.
668 : : */
669 : 11 : node->next = proc->argstack;
670 : 11 : proc->argstack = node;
671 : : }
672 : 709 : proc->calldepth++;
673 : 709 : }
674 : :
675 : : /*
676 : : * Pop old arguments when exiting a recursive call.
677 : : *
678 : : * Note: the idea here is to adjust the proc's callstack state before doing
679 : : * anything that could possibly fail. In event of any error, we want the
680 : : * callstack to look like we've done the pop. Leaking a bit of memory is
681 : : * tolerable.
682 : : */
683 : : static void
684 : 709 : PLy_global_args_pop(PLyProcedure *proc)
685 : : {
686 [ - + ]: 709 : Assert(proc->calldepth > 0);
687 : : /* We only need to pop if we were already inside some active call */
688 [ + + ]: 709 : if (proc->calldepth > 1)
689 : : {
690 : 11 : PLySavedArgs *ptr = proc->argstack;
691 : :
692 : : /* Pop the callstack */
693 [ - + ]: 11 : Assert(ptr != NULL);
694 : 11 : proc->argstack = ptr->next;
695 : 11 : proc->calldepth--;
696 : :
697 : : /* Restore argument values, then free ptr */
698 : 11 : PLy_function_restore_args(proc, ptr);
699 : : }
700 : : else
701 : : {
702 : : /* Exiting call depth 1 */
703 [ - + ]: 698 : Assert(proc->argstack == NULL);
704 : 698 : proc->calldepth--;
705 : :
706 : : /*
707 : : * We used to delete the named arguments (but not "args") from the
708 : : * proc's globals dict when exiting the outermost call level for a
709 : : * function. This seems rather pointless though: nothing can see the
710 : : * dict until the function is called again, at which time we'll
711 : : * overwrite those dict entries. So don't bother with that.
712 : : */
713 : : }
714 : 709 : }
715 : :
716 : : /*
717 : : * Memory context deletion callback for cleaning up a PLySRFState.
718 : : * We need this in case execution of the SRF is terminated early,
719 : : * due to error or the caller simply not running it to completion.
720 : : */
721 : : static void
722 : 53 : plpython_srf_cleanup_callback(void *arg)
723 : : {
724 : 53 : PLySRFState *srfstate = (PLySRFState *) arg;
725 : :
726 : : /* Release refcount on the iter, if we still have one */
727 : 53 : Py_XDECREF(srfstate->iter);
728 : 53 : srfstate->iter = NULL;
729 : : /* And drop any saved args; we won't need them */
730 [ - + ]: 53 : if (srfstate->savedargs)
3707 tgl@sss.pgh.pa.us 731 :UBC 0 : PLy_function_drop_args(srfstate->savedargs);
3707 tgl@sss.pgh.pa.us 732 :CBC 53 : srfstate->savedargs = NULL;
5277 peter_e@gmx.net 733 : 53 : }
734 : :
735 : : static void
736 : 37 : plpython_return_error_callback(void *arg)
737 : : {
5191 tgl@sss.pgh.pa.us 738 : 37 : PLyExecutionContext *exec_ctx = PLy_current_execution_context();
739 : :
3103 peter_e@gmx.net 740 [ + - ]: 37 : if (exec_ctx->curr_proc &&
741 [ + + ]: 37 : !exec_ctx->curr_proc->is_procedure)
5277 742 : 36 : errcontext("while creating return value");
743 : 37 : }
744 : :
745 : : static PyObject *
746 : 49 : PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
747 : : {
748 : 49 : TriggerData *tdata = (TriggerData *) fcinfo->context;
3117 tgl@sss.pgh.pa.us 749 : 49 : TupleDesc rel_descr = RelationGetDescr(tdata->tg_relation);
750 : : PyObject *pltname,
751 : : *pltevent,
752 : : *pltwhen,
753 : : *pltlevel,
754 : : *pltrelid,
755 : : *plttablename,
756 : : *plttableschema,
757 : : *pltargs,
758 : : *pytnew,
759 : : *pytold,
760 : : *pltdata;
761 : : char *stroid;
762 : :
763 : : /*
764 : : * Make any Py*_New() calls before the PG_TRY block so that we can quickly
765 : : * return NULL on failure. We can't return within the PG_TRY block, else
766 : : * we'd miss unwinding the exception stack.
767 : : */
1123 nathan@postgresql.or 768 : 49 : pltdata = PyDict_New();
769 [ - + ]: 49 : if (!pltdata)
1123 nathan@postgresql.or 770 :UBC 0 : return NULL;
771 : :
1123 nathan@postgresql.or 772 [ + + ]:CBC 49 : if (tdata->tg_trigger->tgnargs)
773 : : {
774 : 16 : pltargs = PyList_New(tdata->tg_trigger->tgnargs);
775 [ - + ]: 16 : if (!pltargs)
776 : : {
777 : : Py_DECREF(pltdata);
3133 peter_e@gmx.net 778 :UBC 0 : return NULL;
779 : : }
780 : : }
781 : : else
782 : : {
783 : : Py_INCREF(Py_None);
789 tgl@sss.pgh.pa.us 784 :CBC 33 : pltargs = Py_None;
785 : : }
786 : :
1123 nathan@postgresql.or 787 [ + - ]: 49 : PG_TRY();
788 : : {
1545 andres@anarazel.de 789 : 49 : pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
5277 peter_e@gmx.net 790 : 49 : PyDict_SetItemString(pltdata, "name", pltname);
791 : : Py_DECREF(pltname);
792 : :
793 : 49 : stroid = DatumGetCString(DirectFunctionCall1(oidout,
794 : : ObjectIdGetDatum(tdata->tg_relation->rd_id)));
1545 andres@anarazel.de 795 : 49 : pltrelid = PLyUnicode_FromString(stroid);
5277 peter_e@gmx.net 796 : 49 : PyDict_SetItemString(pltdata, "relid", pltrelid);
797 : : Py_DECREF(pltrelid);
798 : 49 : pfree(stroid);
799 : :
800 : 49 : stroid = SPI_getrelname(tdata->tg_relation);
1545 andres@anarazel.de 801 : 49 : plttablename = PLyUnicode_FromString(stroid);
5277 peter_e@gmx.net 802 : 49 : PyDict_SetItemString(pltdata, "table_name", plttablename);
803 : : Py_DECREF(plttablename);
804 : 49 : pfree(stroid);
805 : :
806 : 49 : stroid = SPI_getnspname(tdata->tg_relation);
1545 andres@anarazel.de 807 : 49 : plttableschema = PLyUnicode_FromString(stroid);
5277 peter_e@gmx.net 808 : 49 : PyDict_SetItemString(pltdata, "table_schema", plttableschema);
809 : : Py_DECREF(plttableschema);
810 : 49 : pfree(stroid);
811 : :
812 [ + + ]: 49 : if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
1545 andres@anarazel.de 813 : 36 : pltwhen = PLyUnicode_FromString("BEFORE");
5277 peter_e@gmx.net 814 [ + + ]: 13 : else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
1545 andres@anarazel.de 815 : 10 : pltwhen = PLyUnicode_FromString("AFTER");
5277 peter_e@gmx.net 816 [ + - ]: 3 : else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
1545 andres@anarazel.de 817 : 3 : pltwhen = PLyUnicode_FromString("INSTEAD OF");
818 : : else
819 : : {
5277 peter_e@gmx.net 820 [ # # ]:UBC 0 : elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
821 : : pltwhen = NULL; /* keep compiler quiet */
822 : : }
5277 peter_e@gmx.net 823 :CBC 49 : PyDict_SetItemString(pltdata, "when", pltwhen);
824 : : Py_DECREF(pltwhen);
825 : :
826 [ + + ]: 49 : if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
827 : : {
1545 andres@anarazel.de 828 : 44 : pltlevel = PLyUnicode_FromString("ROW");
5277 peter_e@gmx.net 829 : 44 : PyDict_SetItemString(pltdata, "level", pltlevel);
830 : : Py_DECREF(pltlevel);
831 : :
832 : : /*
833 : : * Note: In BEFORE trigger, stored generated columns are not
834 : : * computed yet, so don't make them accessible in NEW row.
835 : : */
836 : :
837 [ + + ]: 44 : if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
838 : : {
1545 andres@anarazel.de 839 : 21 : pltevent = PLyUnicode_FromString("INSERT");
840 : :
5277 peter_e@gmx.net 841 : 21 : PyDict_SetItemString(pltdata, "old", Py_None);
3117 tgl@sss.pgh.pa.us 842 : 42 : pytnew = PLy_input_from_tuple(&proc->result_in,
843 : : tdata->tg_trigtuple,
844 : : rel_descr,
2618 peter@eisentraut.org 845 : 21 : !TRIGGER_FIRED_BEFORE(tdata->tg_event));
5277 peter_e@gmx.net 846 : 21 : PyDict_SetItemString(pltdata, "new", pytnew);
847 : : Py_DECREF(pytnew);
848 : 21 : *rv = tdata->tg_trigtuple;
849 : : }
850 [ + + ]: 23 : else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
851 : : {
1545 andres@anarazel.de 852 : 6 : pltevent = PLyUnicode_FromString("DELETE");
853 : :
5277 peter_e@gmx.net 854 : 6 : PyDict_SetItemString(pltdata, "new", Py_None);
3117 tgl@sss.pgh.pa.us 855 : 6 : pytold = PLy_input_from_tuple(&proc->result_in,
856 : : tdata->tg_trigtuple,
857 : : rel_descr,
858 : : true);
5277 peter_e@gmx.net 859 : 6 : PyDict_SetItemString(pltdata, "old", pytold);
860 : : Py_DECREF(pytold);
861 : 6 : *rv = tdata->tg_trigtuple;
862 : : }
863 [ + - ]: 17 : else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
864 : : {
1545 andres@anarazel.de 865 : 17 : pltevent = PLyUnicode_FromString("UPDATE");
866 : :
3117 tgl@sss.pgh.pa.us 867 : 34 : pytnew = PLy_input_from_tuple(&proc->result_in,
868 : : tdata->tg_newtuple,
869 : : rel_descr,
2618 peter@eisentraut.org 870 : 17 : !TRIGGER_FIRED_BEFORE(tdata->tg_event));
5277 peter_e@gmx.net 871 : 17 : PyDict_SetItemString(pltdata, "new", pytnew);
872 : : Py_DECREF(pytnew);
3117 tgl@sss.pgh.pa.us 873 : 17 : pytold = PLy_input_from_tuple(&proc->result_in,
874 : : tdata->tg_trigtuple,
875 : : rel_descr,
876 : : true);
5277 peter_e@gmx.net 877 : 17 : PyDict_SetItemString(pltdata, "old", pytold);
878 : : Py_DECREF(pytold);
879 : 17 : *rv = tdata->tg_newtuple;
880 : : }
881 : : else
882 : : {
5277 peter_e@gmx.net 883 [ # # ]:UBC 0 : elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
884 : : pltevent = NULL; /* keep compiler quiet */
885 : : }
886 : :
5277 peter_e@gmx.net 887 :CBC 44 : PyDict_SetItemString(pltdata, "event", pltevent);
888 : : Py_DECREF(pltevent);
889 : : }
890 [ + - ]: 5 : else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
891 : : {
1545 andres@anarazel.de 892 : 5 : pltlevel = PLyUnicode_FromString("STATEMENT");
5277 peter_e@gmx.net 893 : 5 : PyDict_SetItemString(pltdata, "level", pltlevel);
894 : : Py_DECREF(pltlevel);
895 : :
896 : 5 : PyDict_SetItemString(pltdata, "old", Py_None);
897 : 5 : PyDict_SetItemString(pltdata, "new", Py_None);
898 : 5 : *rv = NULL;
899 : :
900 [ + + ]: 5 : if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
1545 andres@anarazel.de 901 : 1 : pltevent = PLyUnicode_FromString("INSERT");
5277 peter_e@gmx.net 902 [ + + ]: 4 : else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
1545 andres@anarazel.de 903 : 1 : pltevent = PLyUnicode_FromString("DELETE");
5277 peter_e@gmx.net 904 [ + + ]: 3 : else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
1545 andres@anarazel.de 905 : 2 : pltevent = PLyUnicode_FromString("UPDATE");
5277 peter_e@gmx.net 906 [ + - ]: 1 : else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
1545 andres@anarazel.de 907 : 1 : pltevent = PLyUnicode_FromString("TRUNCATE");
908 : : else
909 : : {
5277 peter_e@gmx.net 910 [ # # ]:UBC 0 : elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
911 : : pltevent = NULL; /* keep compiler quiet */
912 : : }
913 : :
5277 peter_e@gmx.net 914 :CBC 5 : PyDict_SetItemString(pltdata, "event", pltevent);
915 : : Py_DECREF(pltevent);
916 : : }
917 : : else
5277 peter_e@gmx.net 918 [ # # ]:UBC 0 : elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
919 : :
5277 peter_e@gmx.net 920 [ + + ]:CBC 49 : if (tdata->tg_trigger->tgnargs)
921 : : {
922 : : /*
923 : : * all strings...
924 : : */
925 : : int i;
926 : : PyObject *pltarg;
927 : :
928 : : /* pltargs should have been allocated before the PG_TRY block. */
789 tgl@sss.pgh.pa.us 929 [ + - - + ]: 16 : Assert(pltargs && pltargs != Py_None);
930 : :
5277 peter_e@gmx.net 931 [ + + ]: 45 : for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
932 : : {
1545 andres@anarazel.de 933 : 29 : pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
934 : :
935 : : /*
936 : : * stolen, don't Py_DECREF
937 : : */
5277 peter_e@gmx.net 938 : 29 : PyList_SetItem(pltargs, i, pltarg);
939 : : }
940 : : }
941 : : else
942 : : {
789 tgl@sss.pgh.pa.us 943 [ - + ]: 33 : Assert(pltargs == Py_None);
944 : : }
5277 peter_e@gmx.net 945 : 49 : PyDict_SetItemString(pltdata, "args", pltargs);
946 : : Py_DECREF(pltargs);
947 : : }
5277 peter_e@gmx.net 948 :UBC 0 : PG_CATCH();
949 : : {
1123 nathan@postgresql.or 950 : 0 : Py_XDECREF(pltargs);
5277 peter_e@gmx.net 951 : 0 : Py_XDECREF(pltdata);
952 : 0 : PG_RE_THROW();
953 : : }
5277 peter_e@gmx.net 954 [ - + ]:CBC 49 : PG_END_TRY();
955 : :
956 : 49 : return pltdata;
957 : : }
958 : :
959 : : /*
960 : : * Apply changes requested by a MODIFY return from a trigger function.
961 : : */
962 : : static HeapTuple
963 : 20 : PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
964 : : HeapTuple otup)
965 : : {
966 : : HeapTuple rtup;
967 : : PyObject *volatile plntup;
968 : : PyObject *volatile plkeys;
969 : : PyObject *volatile plval;
970 : : Datum *volatile modvalues;
971 : : bool *volatile modnulls;
972 : : bool *volatile modrepls;
973 : : ErrorContextCallback plerrcontext;
974 : :
975 : 20 : plerrcontext.callback = plpython_trigger_error_callback;
976 : 20 : plerrcontext.previous = error_context_stack;
977 : 20 : error_context_stack = &plerrcontext;
978 : :
4448 tgl@sss.pgh.pa.us 979 : 20 : plntup = plkeys = plval = NULL;
5277 peter_e@gmx.net 980 : 20 : modvalues = NULL;
981 : 20 : modnulls = NULL;
3490 tgl@sss.pgh.pa.us 982 : 20 : modrepls = NULL;
983 : :
5277 peter_e@gmx.net 984 [ + + ]: 20 : PG_TRY();
985 : : {
986 : : TupleDesc tupdesc;
987 : : int nkeys,
988 : : i;
989 : :
990 [ + + ]: 20 : if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
991 [ + - ]: 1 : ereport(ERROR,
992 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
993 : : errmsg("TD[\"new\"] deleted, cannot modify row")));
4448 tgl@sss.pgh.pa.us 994 [ - + ]: 19 : Py_INCREF(plntup);
5277 peter_e@gmx.net 995 [ + + ]: 19 : if (!PyDict_Check(plntup))
996 [ + - ]: 1 : ereport(ERROR,
997 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
998 : : errmsg("TD[\"new\"] is not a dictionary")));
999 : :
1000 : 18 : plkeys = PyDict_Keys(plntup);
3490 tgl@sss.pgh.pa.us 1001 : 18 : nkeys = PyList_Size(plkeys);
1002 : :
3117 1003 : 18 : tupdesc = RelationGetDescr(tdata->tg_relation);
1004 : :
3490 1005 : 18 : modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
1006 : 18 : modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
1007 : 18 : modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
1008 : :
1009 [ + + ]: 45 : for (i = 0; i < nkeys; i++)
1010 : : {
1011 : : PyObject *platt;
1012 : : char *plattstr;
1013 : : int attn;
1014 : : PLyObToDatum *att;
1015 : :
5277 peter_e@gmx.net 1016 : 31 : platt = PyList_GetItem(plkeys, i);
1545 andres@anarazel.de 1017 [ + + ]: 31 : if (PyUnicode_Check(platt))
5277 peter_e@gmx.net 1018 : 30 : plattstr = PLyUnicode_AsString(platt);
1019 : : else
1020 : : {
1021 [ + - ]: 1 : ereport(ERROR,
1022 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
1023 : : errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i)));
1024 : : plattstr = NULL; /* keep compiler quiet */
1025 : : }
1026 : 30 : attn = SPI_fnumber(tupdesc, plattstr);
1027 [ + + ]: 30 : if (attn == SPI_ERROR_NOATTRIBUTE)
1028 [ + - ]: 2 : ereport(ERROR,
1029 : : (errcode(ERRCODE_UNDEFINED_COLUMN),
1030 : : errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
1031 : : plattstr)));
3490 tgl@sss.pgh.pa.us 1032 [ - + ]: 28 : if (attn <= 0)
3490 tgl@sss.pgh.pa.us 1033 [ # # ]:UBC 0 : ereport(ERROR,
1034 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1035 : : errmsg("cannot set system attribute \"%s\"",
1036 : : plattstr)));
2618 peter@eisentraut.org 1037 [ + + ]:CBC 28 : if (TupleDescAttr(tupdesc, attn - 1)->attgenerated)
1038 [ + - ]: 1 : ereport(ERROR,
1039 : : (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1040 : : errmsg("cannot set generated column \"%s\"",
1041 : : plattstr)));
1042 : :
5277 peter_e@gmx.net 1043 : 27 : plval = PyDict_GetItem(plntup, platt);
1044 [ - + ]: 27 : if (plval == NULL)
5277 peter_e@gmx.net 1045 [ # # ]:UBC 0 : elog(FATAL, "Python interpreter is probably corrupted");
1046 : :
5277 peter_e@gmx.net 1047 [ + + ]:CBC 27 : Py_INCREF(plval);
1048 : :
1049 : : /* We assume proc->result is set up to convert tuples properly */
242 peter@eisentraut.org 1050 :GNC 27 : att = &proc->result.tuple.atts[attn - 1];
1051 : :
3117 tgl@sss.pgh.pa.us 1052 :CBC 54 : modvalues[attn - 1] = PLy_output_convert(att,
1053 : : plval,
1054 : 27 : &modnulls[attn - 1]);
3490 1055 : 27 : modrepls[attn - 1] = true;
1056 : :
5277 peter_e@gmx.net 1057 : 27 : Py_DECREF(plval);
1058 : 27 : plval = NULL;
1059 : : }
1060 : :
3490 tgl@sss.pgh.pa.us 1061 : 14 : rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
1062 : : }
5277 peter_e@gmx.net 1063 : 6 : PG_CATCH();
1064 : : {
1065 : 6 : Py_XDECREF(plntup);
1066 : 6 : Py_XDECREF(plkeys);
1067 : 6 : Py_XDECREF(plval);
1068 : :
1069 [ + + ]: 6 : if (modvalues)
1070 : 4 : pfree(modvalues);
3490 tgl@sss.pgh.pa.us 1071 [ + + ]: 6 : if (modnulls)
1072 : 4 : pfree(modnulls);
1073 [ + + ]: 6 : if (modrepls)
1074 : 4 : pfree(modrepls);
1075 : :
5277 peter_e@gmx.net 1076 : 6 : PG_RE_THROW();
1077 : : }
1078 [ - + ]: 14 : PG_END_TRY();
1079 : :
1080 : 14 : Py_DECREF(plntup);
1081 : 14 : Py_DECREF(plkeys);
1082 : :
1083 : 14 : pfree(modvalues);
1084 : 14 : pfree(modnulls);
3490 tgl@sss.pgh.pa.us 1085 : 14 : pfree(modrepls);
1086 : :
5277 peter_e@gmx.net 1087 : 14 : error_context_stack = plerrcontext.previous;
1088 : :
1089 : 14 : return rtup;
1090 : : }
1091 : :
1092 : : static void
1093 : 6 : plpython_trigger_error_callback(void *arg)
1094 : : {
5191 tgl@sss.pgh.pa.us 1095 : 6 : PLyExecutionContext *exec_ctx = PLy_current_execution_context();
1096 : :
1097 [ + - ]: 6 : if (exec_ctx->curr_proc)
5277 peter_e@gmx.net 1098 : 6 : errcontext("while modifying trigger row");
1099 : 6 : }
1100 : :
1101 : : /* execute Python code, propagate Python errors to the backend */
1102 : : static PyObject *
3707 tgl@sss.pgh.pa.us 1103 : 572 : PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs)
1104 : : {
2399 peter@eisentraut.org 1105 : 572 : PyObject *rv = NULL;
5277 peter_e@gmx.net 1106 : 572 : int volatile save_subxact_level = list_length(explicit_subtransactions);
1107 : :
1108 : 572 : PyDict_SetItemString(proc->globals, kargs, vargs);
1109 : :
1110 [ + - ]: 572 : PG_TRY();
1111 : : {
459 peter@eisentraut.org 1112 : 572 : rv = PyEval_EvalCode(proc->code, proc->globals, proc->globals);
1113 : :
1114 : : /*
1115 : : * Since plpy will only let you close subtransactions that you
1116 : : * started, you cannot *unnest* subtransactions, only *nest* them
1117 : : * without closing.
1118 : : */
5277 peter_e@gmx.net 1119 [ - + ]: 572 : Assert(list_length(explicit_subtransactions) >= save_subxact_level);
1120 : : }
2402 peter@eisentraut.org 1121 :UBC 0 : PG_FINALLY();
1122 : : {
5277 peter_e@gmx.net 1123 :CBC 572 : PLy_abort_open_subtransactions(save_subxact_level);
1124 : : }
1125 [ - + ]: 572 : PG_END_TRY();
1126 : :
1127 : : /* If the Python code returned an error, propagate it */
1128 [ + + ]: 572 : if (rv == NULL)
1129 : 54 : PLy_elog(ERROR, NULL);
1130 : :
1131 : 518 : return rv;
1132 : : }
1133 : :
1134 : : /*
1135 : : * Abort lingering subtransactions that have been explicitly started
1136 : : * by plpy.subtransaction().start() and not properly closed.
1137 : : */
1138 : : static void
1139 : 572 : PLy_abort_open_subtransactions(int save_subxact_level)
1140 : : {
1141 [ - + ]: 572 : Assert(save_subxact_level >= 0);
1142 : :
1143 [ + + ]: 578 : while (list_length(explicit_subtransactions) > save_subxact_level)
1144 : : {
1145 : : PLySubtransactionData *subtransactiondata;
1146 : :
1147 [ - + ]: 6 : Assert(explicit_subtransactions != NIL);
1148 : :
1149 [ + - ]: 6 : ereport(WARNING,
1150 : : (errmsg("forcibly aborting a subtransaction that has not been exited")));
1151 : :
1152 : 6 : RollbackAndReleaseCurrentSubTransaction();
1153 : :
1154 : 6 : subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions);
1155 : 6 : explicit_subtransactions = list_delete_first(explicit_subtransactions);
1156 : :
1157 : 6 : MemoryContextSwitchTo(subtransactiondata->oldcontext);
1158 : 6 : CurrentResourceOwner = subtransactiondata->oldowner;
3859 tgl@sss.pgh.pa.us 1159 : 6 : pfree(subtransactiondata);
1160 : : }
5277 peter_e@gmx.net 1161 : 572 : }
|