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