PostgreSQL Source Code git master
Loading...
Searching...
No Matches
plpy_spi.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "mb/pg_wchar.h"
#include "parser/parse_type.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_planobject.h"
#include "plpy_plpymodule.h"
#include "plpy_resultobject.h"
#include "plpy_spi.h"
#include "plpy_util.h"
#include "utils/memutils.h"
Include dependency graph for plpy_spi.c:

Go to the source code of this file.

Functions

static PyObjectPLy_spi_execute_query (char *query, long limit)
 
static PyObjectPLy_spi_execute_fetch_result (SPITupleTable *tuptable, uint64 rows, int status)
 
static void PLy_spi_exception_set (PyObject *excclass, ErrorData *edata)
 
PyObjectPLy_spi_prepare (PyObject *self, PyObject *args)
 
PyObjectPLy_spi_execute (PyObject *self, PyObject *args)
 
PyObjectPLy_spi_execute_plan (PyObject *ob, PyObject *list, long limit)
 
PyObjectPLy_commit (PyObject *self, PyObject *args)
 
PyObjectPLy_rollback (PyObject *self, PyObject *args)
 
void PLy_spi_subtransaction_begin (MemoryContext oldcontext, ResourceOwner oldowner)
 
void PLy_spi_subtransaction_commit (MemoryContext oldcontext, ResourceOwner oldowner)
 
void PLy_spi_subtransaction_abort (MemoryContext oldcontext, ResourceOwner oldowner)
 

Function Documentation

◆ PLy_commit()

PyObject * PLy_commit ( PyObject self,
PyObject args 
)

Definition at line 448 of file plpy_spi.c.

449{
452
453 PG_TRY();
454 {
455 SPI_commit();
456
457 /* was cleared at transaction end, reset pointer */
458 exec_ctx->scratch_ctx = NULL;
459 }
460 PG_CATCH();
461 {
463 PLyExceptionEntry *entry;
464 PyObject *exc;
465
466 /* Save error info */
467 MemoryContextSwitchTo(oldcontext);
470
471 /* was cleared at transaction end, reset pointer */
472 exec_ctx->scratch_ctx = NULL;
473
474 /* Look up the correct exception */
475 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
476 HASH_FIND, NULL);
477
478 /*
479 * This could be a custom error code, if that's the case fallback to
480 * SPIError
481 */
482 exc = entry ? entry->exc : PLy_exc_spi_error;
483 /* Make Python raise the exception */
486
487 return NULL;
488 }
489 PG_END_TRY();
490
492}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
void FreeErrorData(ErrorData *edata)
Definition elog.c:2014
ErrorData * CopyErrorData(void)
Definition elog.c:1942
void FlushErrorState(void)
Definition elog.c:2063
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define PG_CATCH(...)
Definition elog.h:384
@ HASH_FIND
Definition hsearch.h:108
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
PyObject * PLy_exc_spi_error
Definition plpy_elog.c:17
PLyExecutionContext * PLy_current_execution_context(void)
Definition plpy_main.c:336
HTAB * PLy_spi_exceptions
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition plpy_spi.c:619
static int fb(int x)
void SPI_commit(void)
Definition spi.c:321
PyObject * exc
Definition plpy_spi.h:21

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, fb(), FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, and SPI_commit().

◆ PLy_rollback()

PyObject * PLy_rollback ( PyObject self,
PyObject args 
)

Definition at line 495 of file plpy_spi.c.

496{
499
500 PG_TRY();
501 {
502 SPI_rollback();
503
504 /* was cleared at transaction end, reset pointer */
505 exec_ctx->scratch_ctx = NULL;
506 }
507 PG_CATCH();
508 {
510 PLyExceptionEntry *entry;
511 PyObject *exc;
512
513 /* Save error info */
514 MemoryContextSwitchTo(oldcontext);
517
518 /* was cleared at transaction end, reset pointer */
519 exec_ctx->scratch_ctx = NULL;
520
521 /* Look up the correct exception */
522 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
523 HASH_FIND, NULL);
524
525 /*
526 * This could be a custom error code, if that's the case fallback to
527 * SPIError
528 */
529 exc = entry ? entry->exc : PLy_exc_spi_error;
530 /* Make Python raise the exception */
533
534 return NULL;
535 }
536 PG_END_TRY();
537
539}
void SPI_rollback(void)
Definition spi.c:414

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, fb(), FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, and SPI_rollback().

◆ PLy_spi_exception_set()

static void PLy_spi_exception_set ( PyObject excclass,
ErrorData edata 
)
static

Definition at line 619 of file plpy_spi.c.

620{
621 PyObject *args = NULL;
624
625 args = Py_BuildValue("(s)", edata->message);
626 if (!args)
627 goto failure;
628
629 /* create a new SPI exception with the error message as the parameter */
631 if (!spierror)
632 goto failure;
633
634 spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
635 edata->internalquery, edata->internalpos,
636 edata->schema_name, edata->table_name, edata->column_name,
637 edata->datatype_name, edata->constraint_name);
638 if (!spidata)
639 goto failure;
640
641 if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
642 goto failure;
643
645
646 Py_DECREF(args);
649 return;
650
651failure:
652 Py_XDECREF(args);
655 elog(ERROR, "could not convert SPI error to Python exception");
656}
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228

References elog, ERROR, and fb().

Referenced by PLy_commit(), PLy_rollback(), and PLy_spi_subtransaction_abort().

◆ PLy_spi_execute()

PyObject * PLy_spi_execute ( PyObject self,
PyObject args 
)

Definition at line 152 of file plpy_spi.c.

153{
154 char *query;
155 PyObject *plan;
156 PyObject *list = NULL;
157 long limit = 0;
158
159 if (PyArg_ParseTuple(args, "s|l", &query, &limit))
160 return PLy_spi_execute_query(query, limit);
161
162 PyErr_Clear();
163
164 if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) &&
166 return PLy_spi_execute_plan(plan, list, limit);
167
168 PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
169 return NULL;
170}
#define plan(x)
Definition pg_regress.c:164
PyObject * PLy_exc_error
Definition plpy_elog.c:15
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition plpy_elog.c:490
bool is_PLyPlanObject(PyObject *ob)
PyObject * PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
Definition plpy_spi.c:173
static PyObject * PLy_spi_execute_query(char *query, long limit)
Definition plpy_spi.c:296

References fb(), is_PLyPlanObject(), plan, PLy_exc_error, PLy_exception_set(), PLy_spi_execute_plan(), and PLy_spi_execute_query().

◆ PLy_spi_execute_fetch_result()

static PyObject * PLy_spi_execute_fetch_result ( SPITupleTable tuptable,
uint64  rows,
int  status 
)
static

Definition at line 338 of file plpy_spi.c.

339{
342 volatile MemoryContext oldcontext;
343
345 if (!result)
346 {
347 SPI_freetuptable(tuptable);
348 return NULL;
349 }
350 Py_DECREF(result->status);
351 result->status = PyLong_FromLong(status);
352
353 if (status > 0 && tuptable == NULL)
354 {
355 Py_DECREF(result->nrows);
356 result->nrows = PyLong_FromUnsignedLongLong(rows);
357 }
358 else if (status > 0 && tuptable != NULL)
359 {
361 MemoryContext cxt;
362
363 Py_DECREF(result->nrows);
364 result->nrows = PyLong_FromUnsignedLongLong(rows);
365
367 "PL/Python temp context",
369
370 /* Initialize for converting result tuples to Python */
372 exec_ctx->curr_proc);
373
374 oldcontext = CurrentMemoryContext;
375 PG_TRY();
376 {
378
379 if (rows)
380 {
381 uint64 i;
382
383 /*
384 * PyList_New() and PyList_SetItem() use Py_ssize_t for list
385 * size and list indices; so we cannot support a result larger
386 * than PY_SSIZE_T_MAX.
387 */
388 if (rows > (uint64) PY_SSIZE_T_MAX)
391 errmsg("query result has too many rows to fit in a Python list")));
392
393 Py_DECREF(result->rows);
394 result->rows = PyList_New(rows);
395 if (result->rows)
396 {
398 exec_ctx->curr_proc);
399
400 for (i = 0; i < rows; i++)
401 {
403 tuptable->vals[i],
404 tuptable->tupdesc,
405 true);
406
407 PyList_SetItem(result->rows, i, row);
408 }
409 }
410 }
411
412 /*
413 * Save tuple descriptor for later use by result set metadata
414 * functions. Save it in TopMemoryContext so that it survives
415 * outside of an SPI context. We trust that PLy_result_dealloc()
416 * will clean it up when the time is right. (Do this as late as
417 * possible, to minimize the number of ways the tupdesc could get
418 * leaked due to errors.)
419 */
421 result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
423 }
424 PG_CATCH();
425 {
426 MemoryContextSwitchTo(oldcontext);
429 PG_RE_THROW();
430 }
431 PG_END_TRY();
432
434 SPI_freetuptable(tuptable);
435
436 /* in case PyList_New() failed above */
437 if (!result->rows)
438 {
440 result = NULL;
441 }
442 }
443
444 return (PyObject *) result;
445}
uint64_t uint64
Definition c.h:625
uint32 result
int errcode(int sqlerrcode)
Definition elog.c:875
#define PG_RE_THROW()
Definition elog.h:407
#define ereport(elevel,...)
Definition elog.h:152
int i
Definition isn.c:77
MemoryContext TopMemoryContext
Definition mcxt.c:167
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static char * errmsg
PyObject * PLy_result_new(void)
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
void SPI_freetuptable(SPITupleTable *tuptable)
Definition spi.c:1387
TupleDesc tupdesc
Definition spi.h:25
HeapTuple * vals
Definition spi.h:26
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:242

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CreateTupleDescCopy(), CurrentMemoryContext, ereport, errcode(), errmsg, ERROR, fb(), i, MemoryContextDelete(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_current_execution_context(), PLy_input_from_tuple(), PLy_input_setup_func(), PLy_input_setup_tuple(), PLy_result_new(), result, SPI_freetuptable(), TopMemoryContext, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by PLy_spi_execute_plan(), and PLy_spi_execute_query().

◆ PLy_spi_execute_plan()

PyObject * PLy_spi_execute_plan ( PyObject ob,
PyObject list,
long  limit 
)

Definition at line 173 of file plpy_spi.c.

174{
175 volatile int nargs;
176 int rv;
178 volatile MemoryContext oldcontext;
179 volatile ResourceOwner oldowner;
180 PyObject *ret;
181
182 if (list != NULL)
183 {
184 if (!PySequence_Check(list) || PyUnicode_Check(list))
185 {
186 PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
187 return NULL;
188 }
189 nargs = PySequence_Length(list);
190 }
191 else
192 nargs = 0;
193
194 plan = (PLyPlanObject *) ob;
195
196 if (nargs != plan->nargs)
197 {
198 char *sv;
199 PyObject *so = PyObject_Str(list);
200
201 if (!so)
202 PLy_elog(ERROR, "could not execute plan");
205 "Expected sequence of %d argument, got %d: %s",
206 "Expected sequence of %d arguments, got %d: %s",
207 plan->nargs,
208 plan->nargs, nargs, sv);
209 Py_DECREF(so);
210
211 return NULL;
212 }
213
214 oldcontext = CurrentMemoryContext;
215 oldowner = CurrentResourceOwner;
216
217 PLy_spi_subtransaction_begin(oldcontext, oldowner);
218
219 PG_TRY();
220 {
222 MemoryContext tmpcontext;
223 Datum *volatile values;
224 char *volatile nulls;
225 volatile int j;
226
227 /*
228 * Converted arguments and associated cruft will be in this context,
229 * which is local to our subtransaction.
230 */
232 "PL/Python temporary context",
234 MemoryContextSwitchTo(tmpcontext);
235
236 if (nargs > 0)
237 {
238 values = (Datum *) palloc(nargs * sizeof(Datum));
239 nulls = (char *) palloc(nargs * sizeof(char));
240 }
241 else
242 {
243 values = NULL;
244 nulls = NULL;
245 }
246
247 for (j = 0; j < nargs; j++)
248 {
249 PLyObToDatum *arg = &plan->args[j];
250 PyObject *elem;
251
252 elem = PySequence_GetItem(list, j);
253 PG_TRY(2);
254 {
255 bool isnull;
256
257 values[j] = PLy_output_convert(arg, elem, &isnull);
258 nulls[j] = isnull ? 'n' : ' ';
259 }
260 PG_FINALLY(2);
261 {
262 Py_DECREF(elem);
263 }
264 PG_END_TRY(2);
265 }
266
267 MemoryContextSwitchTo(oldcontext);
268
269 rv = SPI_execute_plan(plan->plan, values, nulls,
270 exec_ctx->curr_proc->fn_readonly, limit);
272
273 MemoryContextDelete(tmpcontext);
274 PLy_spi_subtransaction_commit(oldcontext, oldowner);
275 }
276 PG_CATCH();
277 {
278 /* Subtransaction abort will remove the tmpcontext */
279 PLy_spi_subtransaction_abort(oldcontext, oldowner);
280 return NULL;
281 }
282 PG_END_TRY();
283
284 if (rv < 0)
285 {
287 "SPI_execute_plan failed: %s",
289 return NULL;
290 }
291
292 return ret;
293}
static Datum values[MAXATTR]
Definition bootstrap.c:190
Datum arg
Definition elog.c:1323
#define PG_FINALLY(...)
Definition elog.h:391
int j
Definition isn.c:78
#define PLy_elog
void * palloc(Size size)
Definition mcxt.c:1390
MemoryContext CurTransactionContext
Definition mcxt.c:173
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition plpy_elog.c:504
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition plpy_spi.c:575
static PyObject * PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
Definition plpy_spi.c:338
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition plpy_spi.c:584
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition plpy_spi.c:567
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
char * PLyUnicode_AsString(PyObject *unicode)
Definition plpy_util.c:81
uint64_t Datum
Definition postgres.h:70
ResourceOwner CurrentResourceOwner
Definition resowner.c:173
uint64 SPI_processed
Definition spi.c:45
const char * SPI_result_code_string(int code)
Definition spi.c:1973
SPITupleTable * SPI_tuptable
Definition spi.c:46
int SPI_execute_plan(SPIPlanPtr plan, const Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition spi.c:673

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, arg, CurrentMemoryContext, CurrentResourceOwner, CurTransactionContext, ERROR, fb(), j, MemoryContextDelete(), MemoryContextSwitchTo(), palloc(), PG_CATCH, PG_END_TRY, PG_FINALLY, PG_TRY, plan, PLy_current_execution_context(), PLy_elog, PLy_exc_spi_error, PLy_exception_set(), PLy_exception_set_plural(), PLy_output_convert(), PLy_spi_execute_fetch_result(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyUnicode_AsString(), SPI_execute_plan(), SPI_processed, SPI_result_code_string(), SPI_tuptable, and values.

Referenced by PLy_plan_execute(), and PLy_spi_execute().

◆ PLy_spi_execute_query()

static PyObject * PLy_spi_execute_query ( char query,
long  limit 
)
static

Definition at line 296 of file plpy_spi.c.

297{
298 int rv;
299 volatile MemoryContext oldcontext;
300 volatile ResourceOwner oldowner;
301 PyObject *ret = NULL;
302
303 oldcontext = CurrentMemoryContext;
304 oldowner = CurrentResourceOwner;
305
306 PLy_spi_subtransaction_begin(oldcontext, oldowner);
307
308 PG_TRY();
309 {
311
312 pg_verifymbstr(query, strlen(query), false);
313 rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
315
316 PLy_spi_subtransaction_commit(oldcontext, oldowner);
317 }
318 PG_CATCH();
319 {
320 PLy_spi_subtransaction_abort(oldcontext, oldowner);
321 return NULL;
322 }
323 PG_END_TRY();
324
325 if (rv < 0)
326 {
327 Py_XDECREF(ret);
329 "SPI_execute failed: %s",
331 return NULL;
332 }
333
334 return ret;
335}
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition mbutils.c:1683
int SPI_execute(const char *src, bool read_only, long tcount)
Definition spi.c:597

References CurrentMemoryContext, CurrentResourceOwner, fb(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLy_current_execution_context(), PLy_exc_spi_error, PLy_exception_set(), PLy_spi_execute_fetch_result(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), SPI_execute(), SPI_processed, SPI_result_code_string(), and SPI_tuptable.

Referenced by PLy_spi_execute().

◆ PLy_spi_prepare()

PyObject * PLy_spi_prepare ( PyObject self,
PyObject args 
)

Definition at line 37 of file plpy_spi.c.

38{
41 PyObject *volatile optr = NULL;
42 char *query;
44 volatile MemoryContext oldcontext;
45 volatile ResourceOwner oldowner;
46 volatile int nargs;
47
48 if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
49 return NULL;
50
51 if (list && (!PySequence_Check(list)))
52 {
54 "second argument of plpy.prepare must be a sequence");
55 return NULL;
56 }
57
58 if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
59 return NULL;
60
62 "PL/Python plan context",
64 oldcontext = MemoryContextSwitchTo(plan->mcxt);
65
66 nargs = list ? PySequence_Length(list) : 0;
67
68 plan->nargs = nargs;
69 plan->types = nargs ? palloc0_array(Oid, nargs) : NULL;
70 plan->args = nargs ? palloc0_array(PLyObToDatum, nargs) : NULL;
71
72 MemoryContextSwitchTo(oldcontext);
73
74 oldcontext = CurrentMemoryContext;
75 oldowner = CurrentResourceOwner;
76
77 PLy_spi_subtransaction_begin(oldcontext, oldowner);
78
79 PG_TRY();
80 {
81 int i;
82
83 for (i = 0; i < nargs; i++)
84 {
85 char *sptr;
86 Oid typeId;
87 int32 typmod;
88
89 optr = PySequence_GetItem(list, i);
92 else
93 {
95 (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
96 sptr = NULL; /* keep compiler quiet */
97 }
98
99 /********************************************************
100 * Resolve argument type names and then look them up by
101 * oid in the system cache, and remember the required
102 *information for input conversion.
103 ********************************************************/
104
105 (void) parseTypeString(sptr, &typeId, &typmod, NULL);
106
108
109 /*
110 * set optr to NULL, so we won't try to unref it again in case of
111 * an error
112 */
113 optr = NULL;
114
115 plan->types[i] = typeId;
116 PLy_output_setup_func(&plan->args[i], plan->mcxt,
117 typeId, typmod,
118 exec_ctx->curr_proc);
119 }
120
121 pg_verifymbstr(query, strlen(query), false);
122 plan->plan = SPI_prepare(query, plan->nargs, plan->types);
123 if (plan->plan == NULL)
124 elog(ERROR, "SPI_prepare failed: %s",
126
127 /* transfer plan from procCxt to topCxt */
128 if (SPI_keepplan(plan->plan))
129 elog(ERROR, "SPI_keepplan failed");
130
131 PLy_spi_subtransaction_commit(oldcontext, oldowner);
132 }
133 PG_CATCH();
134 {
137
138 PLy_spi_subtransaction_abort(oldcontext, oldowner);
139 return NULL;
140 }
141 PG_END_TRY();
142
143 Assert(plan->plan != NULL);
144 return (PyObject *) plan;
145}
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
#define palloc0_array(type, count)
Definition fe_memutils.h:92
bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, Node *escontext)
Definition parse_type.c:785
PyObject * PLy_plan_new(void)
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
unsigned int Oid
int SPI_result
Definition spi.c:47
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition spi.c:861
int SPI_keepplan(SPIPlanPtr plan)
Definition spi.c:977

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errmsg, ERROR, fb(), i, MemoryContextSwitchTo(), palloc0_array, parseTypeString(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plan, PLy_current_execution_context(), PLy_exception_set(), PLy_output_setup_func(), PLy_plan_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyUnicode_AsString(), SPI_keepplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), and TopMemoryContext.

◆ PLy_spi_subtransaction_abort()

void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 584 of file plpy_spi.c.

585{
587 PLyExceptionEntry *entry;
588 PyObject *exc;
589
590 /* Save error info */
591 MemoryContextSwitchTo(oldcontext);
594
595 /* Abort the inner transaction */
597 MemoryContextSwitchTo(oldcontext);
598 CurrentResourceOwner = oldowner;
599
600 /* Look up the correct exception */
601 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
602 HASH_FIND, NULL);
603
604 /*
605 * This could be a custom error code, if that's the case fallback to
606 * SPIError
607 */
608 exc = entry ? entry->exc : PLy_exc_spi_error;
609 /* Make Python raise the exception */
612}
void RollbackAndReleaseCurrentSubTransaction(void)
Definition xact.c:4847

References CopyErrorData(), CurrentResourceOwner, PLyExceptionEntry::exc, fb(), FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), PLy_exc_spi_error, PLy_spi_exception_set(), PLy_spi_exceptions, and RollbackAndReleaseCurrentSubTransaction().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().

◆ PLy_spi_subtransaction_begin()

void PLy_spi_subtransaction_begin ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 567 of file plpy_spi.c.

568{
570 /* Want to run inside function's memory context */
571 MemoryContextSwitchTo(oldcontext);
572}
void BeginInternalSubTransaction(const char *name)
Definition xact.c:4745

References BeginInternalSubTransaction(), fb(), and MemoryContextSwitchTo().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().

◆ PLy_spi_subtransaction_commit()

void PLy_spi_subtransaction_commit ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 575 of file plpy_spi.c.

576{
577 /* Commit the inner transaction, return to outer xact context */
579 MemoryContextSwitchTo(oldcontext);
580 CurrentResourceOwner = oldowner;
581}
void ReleaseCurrentSubTransaction(void)
Definition xact.c:4819

References CurrentResourceOwner, MemoryContextSwitchTo(), and ReleaseCurrentSubTransaction().

Referenced by PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), and PLy_spi_prepare().