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 "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_planobject.h"
#include "plpy_plpymodule.h"
#include "plpy_procedure.h"
#include "plpy_resultobject.h"
#include "plpy_spi.h"
#include "plpython.h"
#include "utils/memutils.h"
#include "utils/syscache.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 537 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().

538 {
539  PyObject *args = NULL;
540  PyObject *spierror = NULL;
541  PyObject *spidata = NULL;
542 
543  args = Py_BuildValue("(s)", edata->message);
544  if (!args)
545  goto failure;
546 
547  /* create a new SPI exception with the error message as the parameter */
548  spierror = PyObject_CallObject(excclass, args);
549  if (!spierror)
550  goto failure;
551 
552  spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
553  edata->internalquery, edata->internalpos,
554  edata->schema_name, edata->table_name, edata->column_name,
555  edata->datatype_name, edata->constraint_name);
556  if (!spidata)
557  goto failure;
558 
559  if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
560  goto failure;
561 
562  PyErr_SetObject(excclass, spierror);
563 
564  Py_DECREF(args);
565  Py_DECREF(spierror);
566  Py_DECREF(spidata);
567  return;
568 
569 failure:
570  Py_XDECREF(args);
571  Py_XDECREF(spierror);
572  Py_XDECREF(spidata);
573  elog(ERROR, "could not convert SPI error to Python exception");
574 }
char * schema_name
Definition: elog.h:399
int sqlerrcode
Definition: elog.h:391
char * internalquery
Definition: elog.h:406
#define ERROR
Definition: elog.h:43
char * table_name
Definition: elog.h:400
int internalpos
Definition: elog.h:405
char * datatype_name
Definition: elog.h:402
char * detail
Definition: elog.h:393
char * column_name
Definition: elog.h:401
char * hint
Definition: elog.h:395
#define elog(elevel,...)
Definition: elog.h:228
char * constraint_name
Definition: elog.h:403
char * message
Definition: elog.h:392

◆ PLy_spi_execute()

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

Definition at line 156 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().

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

◆ PLy_spi_execute_fetch_result()

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

Definition at line 350 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, 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().

351 {
352  PLyResultObject *result;
354  volatile MemoryContext oldcontext;
355 
356  result = (PLyResultObject *) PLy_result_new();
357  if (!result)
358  {
359  SPI_freetuptable(tuptable);
360  return NULL;
361  }
362  Py_DECREF(result->status);
363  result->status = PyInt_FromLong(status);
364 
365  if (status > 0 && tuptable == NULL)
366  {
367  Py_DECREF(result->nrows);
368  result->nrows = PyLong_FromUnsignedLongLong(rows);
369  }
370  else if (status > 0 && tuptable != NULL)
371  {
372  PLyDatumToOb ininfo;
373  MemoryContext cxt;
374 
375  Py_DECREF(result->nrows);
376  result->nrows = PyLong_FromUnsignedLongLong(rows);
377 
379  "PL/Python temp context",
381 
382  /* Initialize for converting result tuples to Python */
383  PLy_input_setup_func(&ininfo, cxt, RECORDOID, -1,
384  exec_ctx->curr_proc);
385 
386  oldcontext = CurrentMemoryContext;
387  PG_TRY();
388  {
389  MemoryContext oldcontext2;
390 
391  if (rows)
392  {
393  uint64 i;
394 
395  /*
396  * PyList_New() and PyList_SetItem() use Py_ssize_t for list
397  * size and list indices; so we cannot support a result larger
398  * than PY_SSIZE_T_MAX.
399  */
400  if (rows > (uint64) PY_SSIZE_T_MAX)
401  ereport(ERROR,
402  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
403  errmsg("query result has too many rows to fit in a Python list")));
404 
405  Py_DECREF(result->rows);
406  result->rows = PyList_New(rows);
407  if (result->rows)
408  {
409  PLy_input_setup_tuple(&ininfo, tuptable->tupdesc,
410  exec_ctx->curr_proc);
411 
412  for (i = 0; i < rows; i++)
413  {
414  PyObject *row = PLy_input_from_tuple(&ininfo,
415  tuptable->vals[i],
416  tuptable->tupdesc,
417  true);
418 
419  PyList_SetItem(result->rows, i, row);
420  }
421  }
422  }
423 
424  /*
425  * Save tuple descriptor for later use by result set metadata
426  * functions. Save it in TopMemoryContext so that it survives
427  * outside of an SPI context. We trust that PLy_result_dealloc()
428  * will clean it up when the time is right. (Do this as late as
429  * possible, to minimize the number of ways the tupdesc could get
430  * leaked due to errors.)
431  */
433  result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
434  MemoryContextSwitchTo(oldcontext2);
435  }
436  PG_CATCH();
437  {
438  MemoryContextSwitchTo(oldcontext);
439  MemoryContextDelete(cxt);
440  Py_DECREF(result);
441  PG_RE_THROW();
442  }
443  PG_END_TRY();
444 
445  MemoryContextDelete(cxt);
446  SPI_freetuptable(tuptable);
447 
448  /* in case PyList_New() failed above */
449  if (!result->rows)
450  {
451  Py_DECREF(result);
452  result = NULL;
453  }
454  }
455 
456  return (PyObject *) result;
457 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:608
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
HeapTuple * vals
Definition: spi.h:26
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:164
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:417
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
MemoryContext TopMemoryContext
Definition: mcxt.c:44
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
TupleDesc tupdesc
Definition: spi.h:25
#define PG_CATCH()
Definition: elog.h:332
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:133
#define PG_RE_THROW()
Definition: elog.h:363
#define PY_SSIZE_T_MAX
Definition: plpython.h:68
PyObject * PLy_result_new(void)
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
PyObject_HEAD PyObject * nrows
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347

◆ PLy_spi_execute_plan()

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

Definition at line 177 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_FINALLY, 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().

178 {
179  volatile int nargs;
180  int i,
181  rv;
182  PLyPlanObject *plan;
183  volatile MemoryContext oldcontext;
184  volatile ResourceOwner oldowner;
185  PyObject *ret;
186 
187  if (list != NULL)
188  {
189  if (!PySequence_Check(list) || PyString_Check(list) || PyUnicode_Check(list))
190  {
191  PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
192  return NULL;
193  }
194  nargs = PySequence_Length(list);
195  }
196  else
197  nargs = 0;
198 
199  plan = (PLyPlanObject *) ob;
200 
201  if (nargs != plan->nargs)
202  {
203  char *sv;
204  PyObject *so = PyObject_Str(list);
205 
206  if (!so)
207  PLy_elog(ERROR, "could not execute plan");
208  sv = PyString_AsString(so);
209  PLy_exception_set_plural(PyExc_TypeError,
210  "Expected sequence of %d argument, got %d: %s",
211  "Expected sequence of %d arguments, got %d: %s",
212  plan->nargs,
213  plan->nargs, nargs, sv);
214  Py_DECREF(so);
215 
216  return NULL;
217  }
218 
219  oldcontext = CurrentMemoryContext;
220  oldowner = CurrentResourceOwner;
221 
222  PLy_spi_subtransaction_begin(oldcontext, oldowner);
223 
224  PG_TRY();
225  {
227  char *volatile nulls;
228  volatile int j;
229 
230  if (nargs > 0)
231  nulls = palloc(nargs * sizeof(char));
232  else
233  nulls = NULL;
234 
235  for (j = 0; j < nargs; j++)
236  {
237  PLyObToDatum *arg = &plan->args[j];
238  PyObject *elem;
239 
240  elem = PySequence_GetItem(list, j);
241  PG_TRY();
242  {
243  bool isnull;
244 
245  plan->values[j] = PLy_output_convert(arg, elem, &isnull);
246  nulls[j] = isnull ? 'n' : ' ';
247  }
248  PG_FINALLY();
249  {
250  Py_DECREF(elem);
251  }
252  PG_END_TRY();
253  }
254 
255  rv = SPI_execute_plan(plan->plan, plan->values, nulls,
256  exec_ctx->curr_proc->fn_readonly, limit);
258 
259  if (nargs > 0)
260  pfree(nulls);
261 
262  PLy_spi_subtransaction_commit(oldcontext, oldowner);
263  }
264  PG_CATCH();
265  {
266  int k;
267 
268  /*
269  * cleanup plan->values array
270  */
271  for (k = 0; k < nargs; k++)
272  {
273  if (!plan->args[k].typbyval &&
274  (plan->values[k] != PointerGetDatum(NULL)))
275  {
276  pfree(DatumGetPointer(plan->values[k]));
277  plan->values[k] = PointerGetDatum(NULL);
278  }
279  }
280 
281  PLy_spi_subtransaction_abort(oldcontext, oldowner);
282  return NULL;
283  }
284  PG_END_TRY();
285 
286  for (i = 0; i < nargs; i++)
287  {
288  if (!plan->args[i].typbyval &&
289  (plan->values[i] != PointerGetDatum(NULL)))
290  {
291  pfree(DatumGetPointer(plan->values[i]));
292  plan->values[i] = PointerGetDatum(NULL);
293  }
294  }
295 
296  if (rv < 0)
297  {
299  "SPI_execute_plan failed: %s",
301  return NULL;
302  }
303 
304  return ret;
305 }
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:501
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:119
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
#define PointerGetDatum(X)
Definition: postgres.h:556
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
SPITupleTable * SPI_tuptable
Definition: spi.c:46
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
uint64 SPI_processed
Definition: spi.c:45
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
#define PLy_elog
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:531
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
PLyObToDatum * args
PyObject_HEAD SPIPlanPtr plan
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
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:350
#define PG_FINALLY()
Definition: elog.h:339
#define PG_CATCH()
Definition: elog.h:332
#define DatumGetPointer(X)
Definition: postgres.h:549
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
void * palloc(Size size)
Definition: mcxt.c:949
int i
void * arg
#define PG_TRY()
Definition: elog.h:322
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17
#define PG_END_TRY()
Definition: elog.h:347

◆ PLy_spi_execute_query()

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

Definition at line 308 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().

309 {
310  int rv;
311  volatile MemoryContext oldcontext;
312  volatile ResourceOwner oldowner;
313  PyObject *ret = NULL;
314 
315  oldcontext = CurrentMemoryContext;
316  oldowner = CurrentResourceOwner;
317 
318  PLy_spi_subtransaction_begin(oldcontext, oldowner);
319 
320  PG_TRY();
321  {
323 
324  pg_verifymbstr(query, strlen(query), false);
325  rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
327 
328  PLy_spi_subtransaction_commit(oldcontext, oldowner);
329  }
330  PG_CATCH();
331  {
332  PLy_spi_subtransaction_abort(oldcontext, oldowner);
333  return NULL;
334  }
335  PG_END_TRY();
336 
337  if (rv < 0)
338  {
339  Py_XDECREF(ret);
341  "SPI_execute failed: %s",
343  return NULL;
344  }
345 
346  return ret;
347 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
SPITupleTable * SPI_tuptable
Definition: spi.c:46
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
uint64 SPI_processed
Definition: spi.c:45
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
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:350
#define PG_CATCH()
Definition: elog.h:332
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1914
#define PG_TRY()
Definition: elog.h:322
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17
#define PG_END_TRY()
Definition: elog.h:347
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:496

◆ PLy_spi_prepare()

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

Definition at line 39 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.

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

◆ PLy_spi_subtransaction_abort()

void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 502 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().

503 {
504  ErrorData *edata;
505  PLyExceptionEntry *entry;
506  PyObject *exc;
507 
508  /* Save error info */
509  MemoryContextSwitchTo(oldcontext);
510  edata = CopyErrorData();
511  FlushErrorState();
512 
513  /* Abort the inner transaction */
515  MemoryContextSwitchTo(oldcontext);
516  CurrentResourceOwner = oldowner;
517 
518  /* Look up the correct exception */
519  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
520  HASH_FIND, NULL);
521 
522  /*
523  * This could be a custom error code, if that's the case fallback to
524  * SPIError
525  */
526  exc = entry ? entry->exc : PLy_exc_spi_error;
527  /* Make Python raise the exception */
528  PLy_spi_exception_set(exc, edata);
529  FreeErrorData(edata);
530 }
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:537
int sqlerrcode
Definition: elog.h:391
ErrorData * CopyErrorData(void)
Definition: elog.c:1584
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
void FlushErrorState(void)
Definition: elog.c:1678
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1640
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4464
HTAB * PLy_spi_exceptions
PyObject * exc
Definition: plpy_spi.h:18
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17

◆ PLy_spi_subtransaction_begin()

void PLy_spi_subtransaction_begin ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 485 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().

486 {
488  /* Want to run inside function's memory context */
489  MemoryContextSwitchTo(oldcontext);
490 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4359

◆ PLy_spi_subtransaction_commit()

void PLy_spi_subtransaction_commit ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 493 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().

494 {
495  /* Commit the inner transaction, return to outer xact context */
497  MemoryContextSwitchTo(oldcontext);
498  CurrentResourceOwner = oldowner;
499 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4430
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109