PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

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

Definition at line 556 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, NULL, ErrorData::schema_name, ErrorData::sqlerrcode, and ErrorData::table_name.

Referenced by PLy_spi_subtransaction_abort().

557 {
558  PyObject *args = NULL;
559  PyObject *spierror = NULL;
560  PyObject *spidata = NULL;
561 
562  args = Py_BuildValue("(s)", edata->message);
563  if (!args)
564  goto failure;
565 
566  /* create a new SPI exception with the error message as the parameter */
567  spierror = PyObject_CallObject(excclass, args);
568  if (!spierror)
569  goto failure;
570 
571  spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
572  edata->internalquery, edata->internalpos,
573  edata->schema_name, edata->table_name, edata->column_name,
574  edata->datatype_name, edata->constraint_name);
575  if (!spidata)
576  goto failure;
577 
578  if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
579  goto failure;
580 
581  PyErr_SetObject(excclass, spierror);
582 
583  Py_DECREF(args);
584  Py_DECREF(spierror);
585  Py_DECREF(spidata);
586  return;
587 
588 failure:
589  Py_XDECREF(args);
590  Py_XDECREF(spierror);
591  Py_XDECREF(spidata);
592  elog(ERROR, "could not convert SPI error to Python exception");
593 }
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
#define NULL
Definition: c.h:229
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
PyObject* PLy_spi_execute ( PyObject *  self,
PyObject *  args 
)

Definition at line 175 of file plpy_spi.c.

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

176 {
177  char *query;
178  PyObject *plan;
179  PyObject *list = NULL;
180  long limit = 0;
181 
182  if (PyArg_ParseTuple(args, "s|l", &query, &limit))
183  return PLy_spi_execute_query(query, limit);
184 
185  PyErr_Clear();
186 
187  if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) &&
188  is_PLyPlanObject(plan))
189  return PLy_spi_execute_plan(plan, list, limit);
190 
191  PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
192  return NULL;
193 }
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:196
#define NULL
Definition: c.h:229
static PyObject * PLy_spi_execute_query(char *query, long limit)
Definition: plpy_spi.c:344
tuple list
Definition: sort-test.py:11
static PyObject * PLy_spi_execute_fetch_result ( SPITupleTable tuptable,
uint64  rows,
int  status 
)
static

Definition at line 386 of file plpy_spi.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), generate_unaccent_rules::args, CreateTupleDescCopy(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, i, MemoryContextDelete(), MemoryContextSwitchTo(), PLyResultObject::nrows, NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLy_input_tuple_funcs(), PLy_result_new(), PLy_typeinfo_init(), PLyDict_FromTuple(), PY_SSIZE_T_MAX, result, 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().

387 {
389  volatile MemoryContext oldcontext;
390 
391  result = (PLyResultObject *) PLy_result_new();
392  Py_DECREF(result->status);
393  result->status = PyInt_FromLong(status);
394 
395  if (status > 0 && tuptable == NULL)
396  {
397  Py_DECREF(result->nrows);
398  result->nrows = (rows > (uint64) LONG_MAX) ?
399  PyFloat_FromDouble((double) rows) :
400  PyInt_FromLong((long) rows);
401  }
402  else if (status > 0 && tuptable != NULL)
403  {
405  MemoryContext cxt;
406 
407  Py_DECREF(result->nrows);
408  result->nrows = (rows > (uint64) LONG_MAX) ?
409  PyFloat_FromDouble((double) rows) :
410  PyInt_FromLong((long) rows);
411 
413  "PL/Python temp context",
415  PLy_typeinfo_init(&args, cxt);
416 
417  oldcontext = CurrentMemoryContext;
418  PG_TRY();
419  {
420  MemoryContext oldcontext2;
421 
422  if (rows)
423  {
424  uint64 i;
425 
426  /*
427  * PyList_New() and PyList_SetItem() use Py_ssize_t for list
428  * size and list indices; so we cannot support a result larger
429  * than PY_SSIZE_T_MAX.
430  */
431  if (rows > (uint64) PY_SSIZE_T_MAX)
432  ereport(ERROR,
433  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
434  errmsg("query result has too many rows to fit in a Python list")));
435 
436  Py_DECREF(result->rows);
437  result->rows = PyList_New(rows);
438 
439  PLy_input_tuple_funcs(&args, tuptable->tupdesc);
440  for (i = 0; i < rows; i++)
441  {
442  PyObject *row = PLyDict_FromTuple(&args,
443  tuptable->vals[i],
444  tuptable->tupdesc);
445 
446  PyList_SetItem(result->rows, i, row);
447  }
448  }
449 
450  /*
451  * Save tuple descriptor for later use by result set metadata
452  * functions. Save it in TopMemoryContext so that it survives
453  * outside of an SPI context. We trust that PLy_result_dealloc()
454  * will clean it up when the time is right. (Do this as late as
455  * possible, to minimize the number of ways the tupdesc could get
456  * leaked due to errors.)
457  */
459  result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
460  MemoryContextSwitchTo(oldcontext2);
461  }
462  PG_CATCH();
463  {
464  MemoryContextSwitchTo(oldcontext);
465  MemoryContextDelete(cxt);
466  Py_DECREF(result);
467  PG_RE_THROW();
468  }
469  PG_END_TRY();
470 
471  MemoryContextDelete(cxt);
472  SPI_freetuptable(tuptable);
473  }
474 
475  return (PyObject *) result;
476 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:141
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
Definition: plpy_typeio.c:70
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
void PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
Definition: plpy_typeio.c:105
return result
Definition: formatting.c:1633
HeapTuple * vals
Definition: spi.h:28
#define ERROR
Definition: elog.h:43
PyObject * PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:280
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:970
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
TupleDesc tupdesc
Definition: spi.h:27
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#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:224
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300
PyObject* PLy_spi_execute_plan ( PyObject *  ob,
PyObject *  list,
long  limit 
)

Definition at line 196 of file plpy_spi.c.

References PLyPlanObject::args, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, PLyTypeOutput::d, DatumGetPointer, ERROR, PLyProcedure::fn_readonly, PLyObToDatum::func, i, InputFunctionCall(), PLyPlanObject::nargs, NULL, PLyTypeInfo::out, 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_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, PLyObToDatum::typfunc, PLyObToDatum::typioparam, and PLyPlanObject::values.

Referenced by PLy_plan_execute(), and PLy_spi_execute().

197 {
198  volatile int nargs;
199  int i,
200  rv;
201  PLyPlanObject *plan;
202  volatile MemoryContext oldcontext;
203  volatile ResourceOwner oldowner;
204  PyObject *ret;
205 
206  if (list != NULL)
207  {
208  if (!PySequence_Check(list) || PyString_Check(list) || PyUnicode_Check(list))
209  {
210  PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
211  return NULL;
212  }
213  nargs = PySequence_Length(list);
214  }
215  else
216  nargs = 0;
217 
218  plan = (PLyPlanObject *) ob;
219 
220  if (nargs != plan->nargs)
221  {
222  char *sv;
223  PyObject *so = PyObject_Str(list);
224 
225  if (!so)
226  PLy_elog(ERROR, "could not execute plan");
227  sv = PyString_AsString(so);
228  PLy_exception_set_plural(PyExc_TypeError,
229  "Expected sequence of %d argument, got %d: %s",
230  "Expected sequence of %d arguments, got %d: %s",
231  plan->nargs,
232  plan->nargs, nargs, sv);
233  Py_DECREF(so);
234 
235  return NULL;
236  }
237 
238  oldcontext = CurrentMemoryContext;
239  oldowner = CurrentResourceOwner;
240 
241  PLy_spi_subtransaction_begin(oldcontext, oldowner);
242 
243  PG_TRY();
244  {
246  char *volatile nulls;
247  volatile int j;
248 
249  if (nargs > 0)
250  nulls = palloc(nargs * sizeof(char));
251  else
252  nulls = NULL;
253 
254  for (j = 0; j < nargs; j++)
255  {
256  PyObject *elem;
257 
258  elem = PySequence_GetItem(list, j);
259  if (elem != Py_None)
260  {
261  PG_TRY();
262  {
263  plan->values[j] =
264  plan->args[j].out.d.func(&(plan->args[j].out.d),
265  -1,
266  elem,
267  false);
268  }
269  PG_CATCH();
270  {
271  Py_DECREF(elem);
272  PG_RE_THROW();
273  }
274  PG_END_TRY();
275 
276  Py_DECREF(elem);
277  nulls[j] = ' ';
278  }
279  else
280  {
281  Py_DECREF(elem);
282  plan->values[j] =
283  InputFunctionCall(&(plan->args[j].out.d.typfunc),
284  NULL,
285  plan->args[j].out.d.typioparam,
286  -1);
287  nulls[j] = 'n';
288  }
289  }
290 
291  rv = SPI_execute_plan(plan->plan, plan->values, nulls,
292  exec_ctx->curr_proc->fn_readonly, limit);
294 
295  if (nargs > 0)
296  pfree(nulls);
297 
298  PLy_spi_subtransaction_commit(oldcontext, oldowner);
299  }
300  PG_CATCH();
301  {
302  int k;
303 
304  /*
305  * cleanup plan->values array
306  */
307  for (k = 0; k < nargs; k++)
308  {
309  if (!plan->args[k].out.d.typbyval &&
310  (plan->values[k] != PointerGetDatum(NULL)))
311  {
312  pfree(DatumGetPointer(plan->values[k]));
313  plan->values[k] = PointerGetDatum(NULL);
314  }
315  }
316 
317  PLy_spi_subtransaction_abort(oldcontext, oldowner);
318  return NULL;
319  }
320  PG_END_TRY();
321 
322  for (i = 0; i < nargs; i++)
323  {
324  if (!plan->args[i].out.d.typbyval &&
325  (plan->values[i] != PointerGetDatum(NULL)))
326  {
327  pfree(DatumGetPointer(plan->values[i]));
328  plan->values[i] = PointerGetDatum(NULL);
329  }
330  }
331 
332  if (rv < 0)
333  {
335  "SPI_execute_plan failed: %s",
337  return NULL;
338  }
339 
340  return ret;
341 }
FmgrInfo typfunc
Definition: plpy_typeio.h:58
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:514
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:521
#define PointerGetDatum(X)
Definition: postgres.h:562
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
void PLy_elog(int elevel, const char *fmt,...)
Definition: plpy_elog.c:47
SPITupleTable * SPI_tuptable
Definition: spi.c:41
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
PLyObToDatumFunc func
Definition: plpy_typeio.h:57
uint64 SPI_processed
Definition: spi.c:39
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:504
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
PLyObToDatum d
Definition: plpy_typeio.h:77
PLyTypeInfo * args
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:339
const char * SPI_result_code_string(int code)
Definition: spi.c:1513
PLyTypeOutput out
Definition: plpy_typeio.h:87
PyObject_HEAD SPIPlanPtr plan
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:386
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1623
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
#define PG_RE_THROW()
Definition: elog.h:314
#define DatumGetPointer(X)
Definition: postgres.h:555
tuple list
Definition: sort-test.py:11
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:512
void * palloc(Size size)
Definition: mcxt.c:849
int i
#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
static PyObject * PLy_spi_execute_query ( char *  query,
long  limit 
)
static

Definition at line 344 of file plpy_spi.c.

References PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, PLyProcedure::fn_readonly, NULL, 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().

345 {
346  int rv;
347  volatile MemoryContext oldcontext;
348  volatile ResourceOwner oldowner;
349  PyObject *ret = NULL;
350 
351  oldcontext = CurrentMemoryContext;
352  oldowner = CurrentResourceOwner;
353 
354  PLy_spi_subtransaction_begin(oldcontext, oldowner);
355 
356  PG_TRY();
357  {
359 
360  pg_verifymbstr(query, strlen(query), false);
361  rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
363 
364  PLy_spi_subtransaction_commit(oldcontext, oldowner);
365  }
366  PG_CATCH();
367  {
368  PLy_spi_subtransaction_abort(oldcontext, oldowner);
369  return NULL;
370  }
371  PG_END_TRY();
372 
373  if (rv < 0)
374  {
375  Py_XDECREF(ret);
377  "SPI_execute failed: %s",
379  return NULL;
380  }
381 
382  return ret;
383 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:521
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPITupleTable * SPI_tuptable
Definition: spi.c:41
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:398
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:504
const char * SPI_result_code_string(int code)
Definition: spi.c:1513
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:386
#define PG_CATCH()
Definition: elog.h:293
#define NULL
Definition: c.h:229
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:512
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:304
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, HeapTupleIsValid, i, PLyProcedure::langid, sort-test::list, PLyPlanObject::mcxt, MemoryContextSwitchTo(), PLyPlanObject::nargs, NULL, ObjectIdGetDatum, palloc(), parseTypeString(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLyPlanObject::plan, PLy_current_execution_context(), PLy_exception_set(), PLy_output_datum_func(), PLy_plan_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_typeinfo_init(), PLyUnicode_AsString(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1, SPI_keepplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), TopMemoryContext, PLyProcedure::trftypes, TYPEOID, PLyPlanObject::types, and PLyPlanObject::values.

44 {
45  PLyPlanObject *plan;
46  PyObject *list = NULL;
47  PyObject *volatile optr = NULL;
48  char *query;
49  volatile MemoryContext oldcontext;
50  volatile ResourceOwner oldowner;
51  volatile int nargs;
52 
53  if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list))
54  return NULL;
55 
56  if (list && (!PySequence_Check(list)))
57  {
58  PLy_exception_set(PyExc_TypeError,
59  "second argument of plpy.prepare must be a sequence");
60  return NULL;
61  }
62 
63  if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL)
64  return NULL;
65 
67  "PL/Python plan context",
69  oldcontext = MemoryContextSwitchTo(plan->mcxt);
70 
71  nargs = list ? PySequence_Length(list) : 0;
72 
73  plan->nargs = nargs;
74  plan->types = nargs ? palloc(sizeof(Oid) * nargs) : NULL;
75  plan->values = nargs ? palloc(sizeof(Datum) * nargs) : NULL;
76  plan->args = nargs ? palloc(sizeof(PLyTypeInfo) * nargs) : NULL;
77 
78  MemoryContextSwitchTo(oldcontext);
79 
80  oldcontext = CurrentMemoryContext;
81  oldowner = CurrentResourceOwner;
82 
83  PLy_spi_subtransaction_begin(oldcontext, oldowner);
84 
85  PG_TRY();
86  {
87  int i;
89 
90  /*
91  * the other loop might throw an exception, if PLyTypeInfo member
92  * isn't properly initialized the Py_DECREF(plan) will go boom
93  */
94  for (i = 0; i < nargs; i++)
95  {
96  PLy_typeinfo_init(&plan->args[i], plan->mcxt);
97  plan->values[i] = PointerGetDatum(NULL);
98  }
99 
100  for (i = 0; i < nargs; i++)
101  {
102  char *sptr;
103  HeapTuple typeTup;
104  Oid typeId;
105  int32 typmod;
106 
107  optr = PySequence_GetItem(list, i);
108  if (PyString_Check(optr))
109  sptr = PyString_AsString(optr);
110  else if (PyUnicode_Check(optr))
111  sptr = PLyUnicode_AsString(optr);
112  else
113  {
114  ereport(ERROR,
115  (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
116  sptr = NULL; /* keep compiler quiet */
117  }
118 
119  /********************************************************
120  * Resolve argument type names and then look them up by
121  * oid in the system cache, and remember the required
122  *information for input conversion.
123  ********************************************************/
124 
125  parseTypeString(sptr, &typeId, &typmod, false);
126 
127  typeTup = SearchSysCache1(TYPEOID,
128  ObjectIdGetDatum(typeId));
129  if (!HeapTupleIsValid(typeTup))
130  elog(ERROR, "cache lookup failed for type %u", typeId);
131 
132  Py_DECREF(optr);
133 
134  /*
135  * set optr to NULL, so we won't try to unref it again in case of
136  * an error
137  */
138  optr = NULL;
139 
140  plan->types[i] = typeId;
141  PLy_output_datum_func(&plan->args[i], typeTup, exec_ctx->curr_proc->langid, exec_ctx->curr_proc->trftypes);
142  ReleaseSysCache(typeTup);
143  }
144 
145  pg_verifymbstr(query, strlen(query), false);
146  plan->plan = SPI_prepare(query, plan->nargs, plan->types);
147  if (plan->plan == NULL)
148  elog(ERROR, "SPI_prepare failed: %s",
150 
151  /* transfer plan from procCxt to topCxt */
152  if (SPI_keepplan(plan->plan))
153  elog(ERROR, "SPI_keepplan failed");
154 
155  PLy_spi_subtransaction_commit(oldcontext, oldowner);
156  }
157  PG_CATCH();
158  {
159  Py_DECREF(plan);
160  Py_XDECREF(optr);
161 
162  PLy_spi_subtransaction_abort(oldcontext, oldowner);
163  return NULL;
164  }
165  PG_END_TRY();
166 
167  Assert(plan->plan != NULL);
168  return (PyObject *) plan;
169 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:521
void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
Definition: plpy_typeio.c:70
void PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trftypes)
Definition: plpy_typeio.c:96
#define PointerGetDatum(X)
Definition: postgres.h:562
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:482
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:398
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
signed int int32
Definition: c.h:256
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:504
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
PLyTypeInfo * args
const char * SPI_result_code_string(int code)
Definition: spi.c:1513
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:560
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
MemoryContext mcxt
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
PyObject * PLy_plan_new(void)
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:781
#define PG_CATCH()
Definition: elog.h:293
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
tuple list
Definition: sort-test.py:11
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:512
void * palloc(Size size)
Definition: mcxt.c:849
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
void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 521 of file plpy_spi.c.

References CopyErrorData(), CurrentResourceOwner, PLyExceptionEntry::exc, FlushErrorState(), FreeErrorData(), HASH_FIND, hash_search(), MemoryContextSwitchTo(), NULL, 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().

522 {
523  ErrorData *edata;
524  PLyExceptionEntry *entry;
525  PyObject *exc;
526 
527  /* Save error info */
528  MemoryContextSwitchTo(oldcontext);
529  edata = CopyErrorData();
530  FlushErrorState();
531 
532  /* Abort the inner transaction */
534  MemoryContextSwitchTo(oldcontext);
535  CurrentResourceOwner = oldowner;
536 
537  /* Look up the correct exception */
538  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
539  HASH_FIND, NULL);
540 
541  /*
542  * This could be a custom error code, if that's the case fallback to
543  * SPIError
544  */
545  exc = entry ? entry->exc : PLy_exc_spi_error;
546  /* Make Python raise the exception */
547  PLy_spi_exception_set(exc, edata);
548  FreeErrorData(edata);
549 }
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:556
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:885
void FlushErrorState(void)
Definition: elog.c:1587
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1551
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4158
#define NULL
Definition: c.h:229
HTAB * PLy_spi_exceptions
PyObject * exc
Definition: plpy_spi.h:18
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:21
void PLy_spi_subtransaction_begin ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 504 of file plpy_spi.c.

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

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

505 {
507  /* Want to run inside function's memory context */
508  MemoryContextSwitchTo(oldcontext);
509 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define NULL
Definition: c.h:229
void BeginInternalSubTransaction(char *name)
Definition: xact.c:4054
void PLy_spi_subtransaction_commit ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

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

513 {
514  /* Commit the inner transaction, return to outer xact context */
516  MemoryContextSwitchTo(oldcontext);
517  CurrentResourceOwner = oldowner;
518 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4124
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109