PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 "plpython.h"
#include "utils/memutils.h"
Include dependency graph for plpy_spi.c:

Go to the source code of this file.

Functions

static PyObject * PLy_spi_execute_query (char *query, long limit)
 
static PyObject * PLy_spi_execute_fetch_result (SPITupleTable *tuptable, uint64 rows, int status)
 
static void PLy_spi_exception_set (PyObject *excclass, ErrorData *edata)
 
PyObject * PLy_spi_prepare (PyObject *self, PyObject *args)
 
PyObject * PLy_spi_execute (PyObject *self, PyObject *args)
 
PyObject * PLy_spi_execute_plan (PyObject *ob, PyObject *list, long limit)
 
PyObject * PLy_commit (PyObject *self, PyObject *args)
 
PyObject * PLy_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 446 of file plpy_spi.c.

447{
450
451 PG_TRY();
452 {
453 SPI_commit();
454
455 /* was cleared at transaction end, reset pointer */
456 exec_ctx->scratch_ctx = NULL;
457 }
458 PG_CATCH();
459 {
460 ErrorData *edata;
461 PLyExceptionEntry *entry;
462 PyObject *exc;
463
464 /* Save error info */
465 MemoryContextSwitchTo(oldcontext);
466 edata = CopyErrorData();
468
469 /* was cleared at transaction end, reset pointer */
470 exec_ctx->scratch_ctx = NULL;
471
472 /* Look up the correct exception */
473 entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
474 HASH_FIND, NULL);
475
476 /*
477 * This could be a custom error code, if that's the case fallback to
478 * SPIError
479 */
480 exc = entry ? entry->exc : PLy_exc_spi_error;
481 /* Make Python raise the exception */
482 PLy_spi_exception_set(exc, edata);
483 FreeErrorData(edata);
484
485 return NULL;
486 }
487 PG_END_TRY();
488
489 Py_RETURN_NONE;
490}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1818
ErrorData * CopyErrorData(void)
Definition: elog.c:1746
void FlushErrorState(void)
Definition: elog.c:1867
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
@ HASH_FIND
Definition: hsearch.h:113
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:365
HTAB * PLy_spi_exceptions
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:617
void SPI_commit(void)
Definition: spi.c:320
int sqlerrcode
Definition: elog.h:439
PyObject * exc
Definition: plpy_spi.h:21
MemoryContext scratch_ctx
Definition: plpy_main.h:21

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, 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, PLyExecutionContext::scratch_ctx, SPI_commit(), and ErrorData::sqlerrcode.

◆ PLy_rollback()

PyObject * PLy_rollback ( PyObject *  self,
PyObject *  args 
)

Definition at line 493 of file plpy_spi.c.

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

References CopyErrorData(), CurrentMemoryContext, PLyExceptionEntry::exc, 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, PLyExecutionContext::scratch_ctx, SPI_rollback(), and ErrorData::sqlerrcode.

◆ PLy_spi_exception_set()

static void PLy_spi_exception_set ( PyObject *  excclass,
ErrorData edata 
)
static

Definition at line 617 of file plpy_spi.c.

618{
619 PyObject *args = NULL;
620 PyObject *spierror = NULL;
621 PyObject *spidata = NULL;
622
623 args = Py_BuildValue("(s)", edata->message);
624 if (!args)
625 goto failure;
626
627 /* create a new SPI exception with the error message as the parameter */
628 spierror = PyObject_CallObject(excclass, args);
629 if (!spierror)
630 goto failure;
631
632 spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
633 edata->internalquery, edata->internalpos,
634 edata->schema_name, edata->table_name, edata->column_name,
635 edata->datatype_name, edata->constraint_name);
636 if (!spidata)
637 goto failure;
638
639 if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
640 goto failure;
641
642 PyErr_SetObject(excclass, spierror);
643
644 Py_DECREF(args);
645 Py_DECREF(spierror);
646 Py_DECREF(spidata);
647 return;
648
649failure:
650 Py_XDECREF(args);
651 Py_XDECREF(spierror);
652 Py_XDECREF(spidata);
653 elog(ERROR, "could not convert SPI error to Python exception");
654}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
int internalpos
Definition: elog.h:453
char * schema_name
Definition: elog.h:447
char * internalquery
Definition: elog.h:454
char * datatype_name
Definition: elog.h:450
char * detail
Definition: elog.h:441
char * table_name
Definition: elog.h:448
char * message
Definition: elog.h:440
char * hint
Definition: elog.h:443
char * constraint_name
Definition: elog.h:451
char * column_name
Definition: elog.h:449

References generate_unaccent_rules::args, ErrorData::column_name, ErrorData::constraint_name, ErrorData::datatype_name, ErrorData::detail, elog, ERROR, ErrorData::hint, ErrorData::internalpos, ErrorData::internalquery, ErrorData::message, ErrorData::schema_name, ErrorData::sqlerrcode, and ErrorData::table_name.

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 150 of file plpy_spi.c.

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

References generate_unaccent_rules::args, is_PLyPlanObject(), sort-test::list, 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 336 of file plpy_spi.c.

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

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CreateTupleDescCopy(), PLyExecutionContext::curr_proc, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, i, MemoryContextDelete(), MemoryContextSwitchTo(), PLyResultObject::nrows, 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(), PLyResultObject::rows, SPI_freetuptable(), PLyResultObject::status, TopMemoryContext, SPITupleTable::tupdesc, PLyResultObject::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 171 of file plpy_spi.c.

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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, arg, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, CurTransactionContext, ERROR, PLyProcedure::fn_readonly, j, sort-test::list, 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 294 of file plpy_spi.c.

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

References PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, PLyProcedure::fn_readonly, 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 36 of file plpy_spi.c.

37{
39 PyObject *list = NULL;
40 PyObject *volatile optr = NULL;
41 char *query;
43 volatile MemoryContext oldcontext;
44 volatile ResourceOwner oldowner;
45 volatile int nargs;
46
47 if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
48 return NULL;
49
50 if (list && (!PySequence_Check(list)))
51 {
52 PLy_exception_set(PyExc_TypeError,
53 "second argument of plpy.prepare must be a sequence");
54 return NULL;
55 }
56
57 if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
58 return NULL;
59
61 "PL/Python plan context",
63 oldcontext = MemoryContextSwitchTo(plan->mcxt);
64
65 nargs = list ? PySequence_Length(list) : 0;
66
67 plan->nargs = nargs;
68 plan->types = nargs ? palloc0(sizeof(Oid) * nargs) : NULL;
69 plan->args = nargs ? palloc0(sizeof(PLyObToDatum) * nargs) : NULL;
70
71 MemoryContextSwitchTo(oldcontext);
72
73 oldcontext = CurrentMemoryContext;
74 oldowner = CurrentResourceOwner;
75
76 PLy_spi_subtransaction_begin(oldcontext, oldowner);
77
78 PG_TRY();
79 {
80 int i;
81
82 for (i = 0; i < nargs; i++)
83 {
84 char *sptr;
85 Oid typeId;
86 int32 typmod;
87
88 optr = PySequence_GetItem(list, i);
89 if (PyUnicode_Check(optr))
90 sptr = PLyUnicode_AsString(optr);
91 else
92 {
94 (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
95 sptr = NULL; /* keep compiler quiet */
96 }
97
98 /********************************************************
99 * Resolve argument type names and then look them up by
100 * oid in the system cache, and remember the required
101 *information for input conversion.
102 ********************************************************/
103
104 (void) parseTypeString(sptr, &typeId, &typmod, NULL);
105
106 Py_DECREF(optr);
107
108 /*
109 * set optr to NULL, so we won't try to unref it again in case of
110 * an error
111 */
112 optr = NULL;
113
114 plan->types[i] = typeId;
115 PLy_output_setup_func(&plan->args[i], plan->mcxt,
116 typeId, typmod,
117 exec_ctx->curr_proc);
118 }
119
120 pg_verifymbstr(query, strlen(query), false);
121 plan->plan = SPI_prepare(query, plan->nargs, plan->types);
122 if (plan->plan == NULL)
123 elog(ERROR, "SPI_prepare failed: %s",
125
126 /* transfer plan from procCxt to topCxt */
127 if (SPI_keepplan(plan->plan))
128 elog(ERROR, "SPI_keepplan failed");
129
130 PLy_spi_subtransaction_commit(oldcontext, oldowner);
131 }
132 PG_CATCH();
133 {
134 Py_DECREF(plan);
135 Py_XDECREF(optr);
136
137 PLy_spi_subtransaction_abort(oldcontext, oldowner);
138 return NULL;
139 }
140 PG_END_TRY();
141
142 Assert(plan->plan != NULL);
143 return (PyObject *) plan;
144}
#define Assert(condition)
Definition: c.h:815
int32_t int32
Definition: c.h:484
void * palloc0(Size size)
Definition: mcxt.c:1347
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)
Definition: plpy_typeio.c:296
unsigned int Oid
Definition: postgres_ext.h:32
int SPI_result
Definition: spi.c:46
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:860
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:976

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, generate_unaccent_rules::args, Assert, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errmsg(), ERROR, i, sort-test::list, MemoryContextSwitchTo(), palloc0(), 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 582 of file plpy_spi.c.

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

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

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 565 of file plpy_spi.c.

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

References BeginInternalSubTransaction(), 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 573 of file plpy_spi.c.

574{
575 /* Commit the inner transaction, return to outer xact context */
577 MemoryContextSwitchTo(oldcontext);
578 CurrentResourceOwner = oldowner;
579}
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4760

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().