PostgreSQL Source Code  git master
plpy_spi.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.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 "utils/memutils.h"
#include "utils/syscache.h"
#include "plpython.h"
#include "plpy_spi.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_planobject.h"
#include "plpy_plpymodule.h"
#include "plpy_procedure.h"
#include "plpy_resultobject.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)
 
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_spi_exception_set()

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

Definition at line 546 of file plpy_spi.c.

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

547 {
548  PyObject *args = NULL;
549  PyObject *spierror = NULL;
550  PyObject *spidata = NULL;
551 
552  args = Py_BuildValue("(s)", edata->message);
553  if (!args)
554  goto failure;
555 
556  /* create a new SPI exception with the error message as the parameter */
557  spierror = PyObject_CallObject(excclass, args);
558  if (!spierror)
559  goto failure;
560 
561  spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
562  edata->internalquery, edata->internalpos,
563  edata->schema_name, edata->table_name, edata->column_name,
564  edata->datatype_name, edata->constraint_name);
565  if (!spidata)
566  goto failure;
567 
568  if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
569  goto failure;
570 
571  PyErr_SetObject(excclass, spierror);
572 
573  Py_DECREF(args);
574  Py_DECREF(spierror);
575  Py_DECREF(spidata);
576  return;
577 
578 failure:
579  Py_XDECREF(args);
580  Py_XDECREF(spierror);
581  Py_XDECREF(spidata);
582  elog(ERROR, "could not convert SPI error to Python exception");
583 }
char * schema_name
Definition: elog.h:349
int sqlerrcode
Definition: elog.h:342
char * internalquery
Definition: elog.h:356
#define ERROR
Definition: elog.h:43
char * table_name
Definition: elog.h:350
int internalpos
Definition: elog.h:355
char * datatype_name
Definition: elog.h:352
char * detail
Definition: elog.h:344
char * column_name
Definition: elog.h:351
char * hint
Definition: elog.h:346
#define elog
Definition: elog.h:219
char * constraint_name
Definition: elog.h:353
char * message
Definition: elog.h:343

◆ PLy_spi_execute()

PyObject* PLy_spi_execute ( PyObject *  self,
PyObject *  args 
)

Definition at line 160 of file plpy_spi.c.

References is_PLyPlanObject(), sort-test::list, PLy_exc_error, PLy_exception_set(), PLy_spi_execute_plan(), and PLy_spi_execute_query().

161 {
162  char *query;
163  PyObject *plan;
164  PyObject *list = NULL;
165  long limit = 0;
166 
167  if (PyArg_ParseTuple(args, "s|l", &query, &limit))
168  return PLy_spi_execute_query(query, limit);
169 
170  PyErr_Clear();
171 
172  if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) &&
173  is_PLyPlanObject(plan))
174  return PLy_spi_execute_plan(plan, list, limit);
175 
176  PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
177  return NULL;
178 }
PyObject * PLy_exc_error
Definition: plpy_elog.c:19
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
bool is_PLyPlanObject(PyObject *ob)
PyObject * PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
Definition: plpy_spi.c:181
static PyObject * PLy_spi_execute_query(char *query, long limit)
Definition: plpy_spi.c:314

◆ PLy_spi_execute_fetch_result()

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

Definition at line 356 of file plpy_spi.c.

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(), PY_SSIZE_T_MAX, RECORDOID, PLyResultObject::rows, SPI_freetuptable(), PLyResultObject::status, TopMemoryContext, PLyResultObject::tupdesc, SPITupleTable::tupdesc, and SPITupleTable::vals.

Referenced by PLy_spi_execute_plan(), and PLy_spi_execute_query().

357 {
358  PLyResultObject *result;
360  volatile MemoryContext oldcontext;
361 
362  result = (PLyResultObject *) PLy_result_new();
363  if (!result)
364  {
365  SPI_freetuptable(tuptable);
366  return NULL;
367  }
368  Py_DECREF(result->status);
369  result->status = PyInt_FromLong(status);
370 
371  if (status > 0 && tuptable == NULL)
372  {
373  Py_DECREF(result->nrows);
374  result->nrows = (rows > (uint64) LONG_MAX) ?
375  PyFloat_FromDouble((double) rows) :
376  PyInt_FromLong((long) rows);
377  }
378  else if (status > 0 && tuptable != NULL)
379  {
380  PLyDatumToOb ininfo;
381  MemoryContext cxt;
382 
383  Py_DECREF(result->nrows);
384  result->nrows = (rows > (uint64) LONG_MAX) ?
385  PyFloat_FromDouble((double) rows) :
386  PyInt_FromLong((long) rows);
387 
389  "PL/Python temp context",
391 
392  /* Initialize for converting result tuples to Python */
393  PLy_input_setup_func(&ininfo, cxt, RECORDOID, -1,
394  exec_ctx->curr_proc);
395 
396  oldcontext = CurrentMemoryContext;
397  PG_TRY();
398  {
399  MemoryContext oldcontext2;
400 
401  if (rows)
402  {
403  uint64 i;
404 
405  /*
406  * PyList_New() and PyList_SetItem() use Py_ssize_t for list
407  * size and list indices; so we cannot support a result larger
408  * than PY_SSIZE_T_MAX.
409  */
410  if (rows > (uint64) PY_SSIZE_T_MAX)
411  ereport(ERROR,
412  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
413  errmsg("query result has too many rows to fit in a Python list")));
414 
415  Py_DECREF(result->rows);
416  result->rows = PyList_New(rows);
417  if (result->rows)
418  {
419  PLy_input_setup_tuple(&ininfo, tuptable->tupdesc,
420  exec_ctx->curr_proc);
421 
422  for (i = 0; i < rows; i++)
423  {
424  PyObject *row = PLy_input_from_tuple(&ininfo,
425  tuptable->vals[i],
426  tuptable->tupdesc);
427 
428  PyList_SetItem(result->rows, i, row);
429  }
430  }
431  }
432 
433  /*
434  * Save tuple descriptor for later use by result set metadata
435  * functions. Save it in TopMemoryContext so that it survives
436  * outside of an SPI context. We trust that PLy_result_dealloc()
437  * will clean it up when the time is right. (Do this as late as
438  * possible, to minimize the number of ways the tupdesc could get
439  * leaked due to errors.)
440  */
442  result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
443  MemoryContextSwitchTo(oldcontext2);
444  }
445  PG_CATCH();
446  {
447  MemoryContextSwitchTo(oldcontext);
448  MemoryContextDelete(cxt);
449  Py_DECREF(result);
450  PG_RE_THROW();
451  }
452  PG_END_TRY();
453 
454  MemoryContextDelete(cxt);
455  SPI_freetuptable(tuptable);
456 
457  /* in case PyList_New() failed above */
458  if (!result->rows)
459  {
460  Py_DECREF(result);
461  result = NULL;
462  }
463  }
464 
465  return (PyObject *) result;
466 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:102
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:137
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
HeapTuple * vals
Definition: spi.h:28
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:168
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
#define RECORDOID
Definition: pg_type.h:680
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:165
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:978
TupleDesc tupdesc
Definition: spi.h:27
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define PY_SSIZE_T_MAX
Definition: plpython.h:66
PyObject * PLy_result_new(void)
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
PyObject_HEAD PyObject * nrows
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_spi_execute_plan()

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

Definition at line 181 of file plpy_spi.c.

References arg, PLyPlanObject::args, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, DatumGetPointer, ERROR, PLyProcedure::fn_readonly, i, PLyPlanObject::nargs, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyPlanObject::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(), PointerGetDatum, SPI_execute_plan(), SPI_processed, SPI_result_code_string(), SPI_tuptable, PLyObToDatum::typbyval, and PLyPlanObject::values.

Referenced by PLy_plan_execute(), and PLy_spi_execute().

182 {
183  volatile int nargs;
184  int i,
185  rv;
186  PLyPlanObject *plan;
187  volatile MemoryContext oldcontext;
188  volatile ResourceOwner oldowner;
189  PyObject *ret;
190 
191  if (list != NULL)
192  {
193  if (!PySequence_Check(list) || PyString_Check(list) || PyUnicode_Check(list))
194  {
195  PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
196  return NULL;
197  }
198  nargs = PySequence_Length(list);
199  }
200  else
201  nargs = 0;
202 
203  plan = (PLyPlanObject *) ob;
204 
205  if (nargs != plan->nargs)
206  {
207  char *sv;
208  PyObject *so = PyObject_Str(list);
209 
210  if (!so)
211  PLy_elog(ERROR, "could not execute plan");
212  sv = PyString_AsString(so);
213  PLy_exception_set_plural(PyExc_TypeError,
214  "Expected sequence of %d argument, got %d: %s",
215  "Expected sequence of %d arguments, got %d: %s",
216  plan->nargs,
217  plan->nargs, nargs, sv);
218  Py_DECREF(so);
219 
220  return NULL;
221  }
222 
223  oldcontext = CurrentMemoryContext;
224  oldowner = CurrentResourceOwner;
225 
226  PLy_spi_subtransaction_begin(oldcontext, oldowner);
227 
228  PG_TRY();
229  {
231  char *volatile nulls;
232  volatile int j;
233 
234  if (nargs > 0)
235  nulls = palloc(nargs * sizeof(char));
236  else
237  nulls = NULL;
238 
239  for (j = 0; j < nargs; j++)
240  {
241  PLyObToDatum *arg = &plan->args[j];
242  PyObject *elem;
243 
244  elem = PySequence_GetItem(list, j);
245  PG_TRY();
246  {
247  bool isnull;
248 
249  plan->values[j] = PLy_output_convert(arg, elem, &isnull);
250  nulls[j] = isnull ? 'n' : ' ';
251  }
252  PG_CATCH();
253  {
254  Py_DECREF(elem);
255  PG_RE_THROW();
256  }
257  PG_END_TRY();
258  Py_DECREF(elem);
259  }
260 
261  rv = SPI_execute_plan(plan->plan, plan->values, nulls,
262  exec_ctx->curr_proc->fn_readonly, limit);
264 
265  if (nargs > 0)
266  pfree(nulls);
267 
268  PLy_spi_subtransaction_commit(oldcontext, oldowner);
269  }
270  PG_CATCH();
271  {
272  int k;
273 
274  /*
275  * cleanup plan->values array
276  */
277  for (k = 0; k < nargs; k++)
278  {
279  if (!plan->args[k].typbyval &&
280  (plan->values[k] != PointerGetDatum(NULL)))
281  {
282  pfree(DatumGetPointer(plan->values[k]));
283  plan->values[k] = PointerGetDatum(NULL);
284  }
285  }
286 
287  PLy_spi_subtransaction_abort(oldcontext, oldowner);
288  return NULL;
289  }
290  PG_END_TRY();
291 
292  for (i = 0; i < nargs; i++)
293  {
294  if (!plan->args[i].typbyval &&
295  (plan->values[i] != PointerGetDatum(NULL)))
296  {
297  pfree(DatumGetPointer(plan->values[i]));
298  plan->values[i] = PointerGetDatum(NULL);
299  }
300  }
301 
302  if (rv < 0)
303  {
305  "SPI_execute_plan failed: %s",
307  return NULL;
308  }
309 
310  return ret;
311 }
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:514
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:123
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
#define PointerGetDatum(X)
Definition: postgres.h:562
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPITupleTable * SPI_tuptable
Definition: spi.c:41
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
uint64 SPI_processed
Definition: spi.c:39
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:345
const char * SPI_result_code_string(int code)
Definition: spi.c:1521
PLyObToDatum * args
PyObject_HEAD SPIPlanPtr plan
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define PLy_elog
Definition: plpy_elog.h:36
static PyObject * PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
Definition: plpy_spi.c:356
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define DatumGetPointer(X)
Definition: postgres.h:555
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
void * palloc(Size size)
Definition: mcxt.c:835
int i
void * arg
#define PG_TRY()
Definition: elog.h:284
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:21
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_spi_execute_query()

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

Definition at line 314 of file plpy_spi.c.

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

315 {
316  int rv;
317  volatile MemoryContext oldcontext;
318  volatile ResourceOwner oldowner;
319  PyObject *ret = NULL;
320 
321  oldcontext = CurrentMemoryContext;
322  oldowner = CurrentResourceOwner;
323 
324  PLy_spi_subtransaction_begin(oldcontext, oldowner);
325 
326  PG_TRY();
327  {
329 
330  pg_verifymbstr(query, strlen(query), false);
331  rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
333 
334  PLy_spi_subtransaction_commit(oldcontext, oldowner);
335  }
336  PG_CATCH();
337  {
338  PLy_spi_subtransaction_abort(oldcontext, oldowner);
339  return NULL;
340  }
341  PG_END_TRY();
342 
343  if (rv < 0)
344  {
345  Py_XDECREF(ret);
347  "SPI_execute failed: %s",
349  return NULL;
350  }
351 
352  return ret;
353 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPITupleTable * SPI_tuptable
Definition: spi.c:41
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
uint64 SPI_processed
Definition: spi.c:39
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
const char * SPI_result_code_string(int code)
Definition: spi.c:1521
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
PLyProcedure * curr_proc
Definition: plpy_main.h:20
static PyObject * PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
Definition: plpy_spi.c:356
#define PG_CATCH()
Definition: elog.h:293
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1866
#define PG_TRY()
Definition: elog.h:284
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:21
#define PG_END_TRY()
Definition: elog.h:300
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:310

◆ PLy_spi_prepare()

PyObject* PLy_spi_prepare ( PyObject *  self,
PyObject *  args 
)

Definition at line 43 of file plpy_spi.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, PLyPlanObject::args, Assert, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ereport, errmsg(), ERROR, i, sort-test::list, PLyPlanObject::mcxt, MemoryContextSwitchTo(), PLyPlanObject::nargs, palloc0(), parseTypeString(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLyPlanObject::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(), TopMemoryContext, PLyPlanObject::types, and PLyPlanObject::values.

44 {
45  PLyPlanObject *plan;
46  PyObject *list = NULL;
47  PyObject *volatile optr = NULL;
48  char *query;
50  volatile MemoryContext oldcontext;
51  volatile ResourceOwner oldowner;
52  volatile int nargs;
53 
54  if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
55  return NULL;
56 
57  if (list && (!PySequence_Check(list)))
58  {
59  PLy_exception_set(PyExc_TypeError,
60  "second argument of plpy.prepare must be a sequence");
61  return NULL;
62  }
63 
64  if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
65  return NULL;
66 
68  "PL/Python plan context",
70  oldcontext = MemoryContextSwitchTo(plan->mcxt);
71 
72  nargs = list ? PySequence_Length(list) : 0;
73 
74  plan->nargs = nargs;
75  plan->types = nargs ? palloc0(sizeof(Oid) * nargs) : NULL;
76  plan->values = nargs ? palloc0(sizeof(Datum) * nargs) : NULL;
77  plan->args = nargs ? palloc0(sizeof(PLyObToDatum) * nargs) : NULL;
78 
79  MemoryContextSwitchTo(oldcontext);
80 
81  oldcontext = CurrentMemoryContext;
82  oldowner = CurrentResourceOwner;
83 
84  PLy_spi_subtransaction_begin(oldcontext, oldowner);
85 
86  PG_TRY();
87  {
88  int i;
89 
90  for (i = 0; i < nargs; i++)
91  {
92  char *sptr;
93  Oid typeId;
94  int32 typmod;
95 
96  optr = PySequence_GetItem(list, i);
97  if (PyString_Check(optr))
98  sptr = PyString_AsString(optr);
99  else if (PyUnicode_Check(optr))
100  sptr = PLyUnicode_AsString(optr);
101  else
102  {
103  ereport(ERROR,
104  (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
105  sptr = NULL; /* keep compiler quiet */
106  }
107 
108  /********************************************************
109  * Resolve argument type names and then look them up by
110  * oid in the system cache, and remember the required
111  *information for input conversion.
112  ********************************************************/
113 
114  parseTypeString(sptr, &typeId, &typmod, false);
115 
116  Py_DECREF(optr);
117 
118  /*
119  * set optr to NULL, so we won't try to unref it again in case of
120  * an error
121  */
122  optr = NULL;
123 
124  plan->types[i] = typeId;
125  PLy_output_setup_func(&plan->args[i], plan->mcxt,
126  typeId, typmod,
127  exec_ctx->curr_proc);
128  }
129 
130  pg_verifymbstr(query, strlen(query), false);
131  plan->plan = SPI_prepare(query, plan->nargs, plan->types);
132  if (plan->plan == NULL)
133  elog(ERROR, "SPI_prepare failed: %s",
135 
136  /* transfer plan from procCxt to topCxt */
137  if (SPI_keepplan(plan->plan))
138  elog(ERROR, "SPI_keepplan failed");
139 
140  PLy_spi_subtransaction_commit(oldcontext, oldowner);
141  }
142  PG_CATCH();
143  {
144  Py_DECREF(plan);
145  Py_XDECREF(optr);
146 
147  PLy_spi_subtransaction_abort(oldcontext, oldowner);
148  return NULL;
149  }
150  PG_END_TRY();
151 
152  Assert(plan->plan != NULL);
153  return (PyObject *) plan;
154 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:488
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
signed int int32
Definition: c.h:294
char * PLyUnicode_AsString(PyObject *unicode)
Definition: plpy_util.c:94
int SPI_result
Definition: spi.c:42
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
#define ERROR
Definition: elog.h:43
const char * SPI_result_code_string(int code)
Definition: spi.c:1521
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:566
PLyObToDatum * args
PyObject_HEAD SPIPlanPtr plan
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:165
MemoryContext mcxt
void * palloc0(Size size)
Definition: mcxt.c:864
PyObject * PLy_plan_new(void)
uintptr_t Datum
Definition: postgres.h:372
void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:815
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:680
void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:299
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1866
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_spi_subtransaction_abort()

void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 511 of file plpy_spi.c.

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

512 {
513  ErrorData *edata;
514  PLyExceptionEntry *entry;
515  PyObject *exc;
516 
517  /* Save error info */
518  MemoryContextSwitchTo(oldcontext);
519  edata = CopyErrorData();
520  FlushErrorState();
521 
522  /* Abort the inner transaction */
524  MemoryContextSwitchTo(oldcontext);
525  CurrentResourceOwner = oldowner;
526 
527  /* Look up the correct exception */
528  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
529  HASH_FIND, NULL);
530 
531  /*
532  * This could be a custom error code, if that's the case fallback to
533  * SPIError
534  */
535  exc = entry ? entry->exc : PLy_exc_spi_error;
536  /* Make Python raise the exception */
537  PLy_spi_exception_set(exc, edata);
538  FreeErrorData(edata);
539 }
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:546
int sqlerrcode
Definition: elog.h:342
ErrorData * CopyErrorData(void)
Definition: elog.c:1497
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:904
void FlushErrorState(void)
Definition: elog.c:1587
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1551
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4277
HTAB * PLy_spi_exceptions
PyObject * exc
Definition: plpy_spi.h:18
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:21

◆ PLy_spi_subtransaction_begin()

void PLy_spi_subtransaction_begin ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 494 of file plpy_spi.c.

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

495 {
497  /* Want to run inside function's memory context */
498  MemoryContextSwitchTo(oldcontext);
499 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4172

◆ PLy_spi_subtransaction_commit()

void PLy_spi_subtransaction_commit ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 502 of file plpy_spi.c.

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

503 {
504  /* Commit the inner transaction, return to outer xact context */
506  MemoryContextSwitchTo(oldcontext);
507  CurrentResourceOwner = oldowner;
508 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4243
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109