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

456 {
457  MemoryContext oldcontext = CurrentMemoryContext;
459 
460  PG_TRY();
461  {
462  SPI_commit();
463 
464  /* was cleared at transaction end, reset pointer */
465  exec_ctx->scratch_ctx = NULL;
466  }
467  PG_CATCH();
468  {
469  ErrorData *edata;
470  PLyExceptionEntry *entry;
471  PyObject *exc;
472 
473  /* Save error info */
474  MemoryContextSwitchTo(oldcontext);
475  edata = CopyErrorData();
476  FlushErrorState();
477 
478  /* was cleared at transaction end, reset pointer */
479  exec_ctx->scratch_ctx = NULL;
480 
481  /* Look up the correct exception */
482  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
483  HASH_FIND, NULL);
484 
485  /*
486  * This could be a custom error code, if that's the case fallback to
487  * SPIError
488  */
489  exc = entry ? entry->exc : PLy_exc_spi_error;
490  /* Make Python raise the exception */
491  PLy_spi_exception_set(exc, edata);
492  FreeErrorData(edata);
493 
494  return NULL;
495  }
496  PG_END_TRY();
497 
498  Py_RETURN_NONE;
499 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1818
void FlushErrorState(void)
Definition: elog.c:1867
ErrorData * CopyErrorData(void)
Definition: elog.c:1746
#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
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:626
MemoryContextSwitchTo(old_ctx)
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 502 of file plpy_spi.c.

503 {
504  MemoryContext oldcontext = CurrentMemoryContext;
506 
507  PG_TRY();
508  {
509  SPI_rollback();
510 
511  /* was cleared at transaction end, reset pointer */
512  exec_ctx->scratch_ctx = NULL;
513  }
514  PG_CATCH();
515  {
516  ErrorData *edata;
517  PLyExceptionEntry *entry;
518  PyObject *exc;
519 
520  /* Save error info */
521  MemoryContextSwitchTo(oldcontext);
522  edata = CopyErrorData();
523  FlushErrorState();
524 
525  /* was cleared at transaction end, reset pointer */
526  exec_ctx->scratch_ctx = NULL;
527 
528  /* Look up the correct exception */
529  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
530  HASH_FIND, NULL);
531 
532  /*
533  * This could be a custom error code, if that's the case fallback to
534  * SPIError
535  */
536  exc = entry ? entry->exc : PLy_exc_spi_error;
537  /* Make Python raise the exception */
538  PLy_spi_exception_set(exc, edata);
539  FreeErrorData(edata);
540 
541  return NULL;
542  }
543  PG_END_TRY();
544 
545  Py_RETURN_NONE;
546 }
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 626 of file plpy_spi.c.

627 {
628  PyObject *args = NULL;
629  PyObject *spierror = NULL;
630  PyObject *spidata = NULL;
631 
632  args = Py_BuildValue("(s)", edata->message);
633  if (!args)
634  goto failure;
635 
636  /* create a new SPI exception with the error message as the parameter */
637  spierror = PyObject_CallObject(excclass, args);
638  if (!spierror)
639  goto failure;
640 
641  spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
642  edata->internalquery, edata->internalpos,
643  edata->schema_name, edata->table_name, edata->column_name,
644  edata->datatype_name, edata->constraint_name);
645  if (!spidata)
646  goto failure;
647 
648  if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
649  goto failure;
650 
651  PyErr_SetObject(excclass, spierror);
652 
653  Py_DECREF(args);
654  Py_DECREF(spierror);
655  Py_DECREF(spidata);
656  return;
657 
658 failure:
659  Py_XDECREF(args);
660  Py_XDECREF(spierror);
661  Py_XDECREF(spidata);
662  elog(ERROR, "could not convert SPI error to Python exception");
663 }
#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 151 of file plpy_spi.c.

152 {
153  char *query;
154  PyObject *plan;
155  PyObject *list = NULL;
156  long limit = 0;
157 
158  if (PyArg_ParseTuple(args, "s|l", &query, &limit))
159  return PLy_spi_execute_query(query, limit);
160 
161  PyErr_Clear();
162 
163  if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) &&
165  return PLy_spi_execute_plan(plan, list, limit);
166 
167  PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan");
168  return NULL;
169 }
#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:172
static PyObject * PLy_spi_execute_query(char *query, long limit)
Definition: plpy_spi.c:303

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

346 {
347  PLyResultObject *result;
349  volatile MemoryContext oldcontext;
350 
351  result = (PLyResultObject *) PLy_result_new();
352  if (!result)
353  {
354  SPI_freetuptable(tuptable);
355  return NULL;
356  }
357  Py_DECREF(result->status);
358  result->status = PyLong_FromLong(status);
359 
360  if (status > 0 && tuptable == NULL)
361  {
362  Py_DECREF(result->nrows);
363  result->nrows = PyLong_FromUnsignedLongLong(rows);
364  }
365  else if (status > 0 && tuptable != NULL)
366  {
367  PLyDatumToOb ininfo;
368  MemoryContext cxt;
369 
370  Py_DECREF(result->nrows);
371  result->nrows = PyLong_FromUnsignedLongLong(rows);
372 
374  "PL/Python temp context",
376 
377  /* Initialize for converting result tuples to Python */
378  PLy_input_setup_func(&ininfo, cxt, RECORDOID, -1,
379  exec_ctx->curr_proc);
380 
381  oldcontext = CurrentMemoryContext;
382  PG_TRY();
383  {
384  MemoryContext oldcontext2;
385 
386  if (rows)
387  {
388  uint64 i;
389 
390  /*
391  * PyList_New() and PyList_SetItem() use Py_ssize_t for list
392  * size and list indices; so we cannot support a result larger
393  * than PY_SSIZE_T_MAX.
394  */
395  if (rows > (uint64) PY_SSIZE_T_MAX)
396  ereport(ERROR,
397  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
398  errmsg("query result has too many rows to fit in a Python list")));
399 
400  Py_DECREF(result->rows);
401  result->rows = PyList_New(rows);
402  if (result->rows)
403  {
404  PLy_input_setup_tuple(&ininfo, tuptable->tupdesc,
405  exec_ctx->curr_proc);
406 
407  for (i = 0; i < rows; i++)
408  {
409  PyObject *row = PLy_input_from_tuple(&ininfo,
410  tuptable->vals[i],
411  tuptable->tupdesc,
412  true);
413 
414  PyList_SetItem(result->rows, i, row);
415  }
416  }
417  }
418 
419  /*
420  * Save tuple descriptor for later use by result set metadata
421  * functions. Save it in TopMemoryContext so that it survives
422  * outside of an SPI context. We trust that PLy_result_dealloc()
423  * will clean it up when the time is right. (Do this as late as
424  * possible, to minimize the number of ways the tupdesc could get
425  * leaked due to errors.)
426  */
428  result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc);
429  MemoryContextSwitchTo(oldcontext2);
430  }
431  PG_CATCH();
432  {
433  MemoryContextSwitchTo(oldcontext);
434  MemoryContextDelete(cxt);
435  Py_DECREF(result);
436  PG_RE_THROW();
437  }
438  PG_END_TRY();
439 
440  MemoryContextDelete(cxt);
441  SPI_freetuptable(tuptable);
442 
443  /* in case PyList_New() failed above */
444  if (!result->rows)
445  {
446  Py_DECREF(result);
447  result = NULL;
448  }
449  }
450 
451  return (PyObject *) result;
452 }
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)
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:134
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:418
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:133

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

173 {
174  volatile int nargs;
175  int i,
176  rv;
178  volatile MemoryContext oldcontext;
179  volatile ResourceOwner oldowner;
180  PyObject *ret;
181 
182  if (list != NULL)
183  {
184  if (!PySequence_Check(list) || PyUnicode_Check(list))
185  {
186  PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument");
187  return NULL;
188  }
189  nargs = PySequence_Length(list);
190  }
191  else
192  nargs = 0;
193 
194  plan = (PLyPlanObject *) ob;
195 
196  if (nargs != plan->nargs)
197  {
198  char *sv;
199  PyObject *so = PyObject_Str(list);
200 
201  if (!so)
202  PLy_elog(ERROR, "could not execute plan");
203  sv = PLyUnicode_AsString(so);
204  PLy_exception_set_plural(PyExc_TypeError,
205  "Expected sequence of %d argument, got %d: %s",
206  "Expected sequence of %d arguments, got %d: %s",
207  plan->nargs,
208  plan->nargs, nargs, sv);
209  Py_DECREF(so);
210 
211  return NULL;
212  }
213 
214  oldcontext = CurrentMemoryContext;
215  oldowner = CurrentResourceOwner;
216 
217  PLy_spi_subtransaction_begin(oldcontext, oldowner);
218 
219  PG_TRY();
220  {
222  char *volatile nulls;
223  volatile int j;
224 
225  if (nargs > 0)
226  nulls = palloc(nargs * sizeof(char));
227  else
228  nulls = NULL;
229 
230  for (j = 0; j < nargs; j++)
231  {
232  PLyObToDatum *arg = &plan->args[j];
233  PyObject *elem;
234 
235  elem = PySequence_GetItem(list, j);
236  PG_TRY(2);
237  {
238  bool isnull;
239 
240  plan->values[j] = PLy_output_convert(arg, elem, &isnull);
241  nulls[j] = isnull ? 'n' : ' ';
242  }
243  PG_FINALLY(2);
244  {
245  Py_DECREF(elem);
246  }
247  PG_END_TRY(2);
248  }
249 
250  rv = SPI_execute_plan(plan->plan, plan->values, nulls,
251  exec_ctx->curr_proc->fn_readonly, limit);
253 
254  if (nargs > 0)
255  pfree(nulls);
256 
257  PLy_spi_subtransaction_commit(oldcontext, oldowner);
258  }
259  PG_CATCH();
260  {
261  int k;
262 
263  /*
264  * cleanup plan->values array
265  */
266  for (k = 0; k < nargs; k++)
267  {
268  if (!plan->args[k].typbyval &&
269  (plan->values[k] != PointerGetDatum(NULL)))
270  {
271  pfree(DatumGetPointer(plan->values[k]));
272  plan->values[k] = PointerGetDatum(NULL);
273  }
274  }
275 
276  PLy_spi_subtransaction_abort(oldcontext, oldowner);
277  return NULL;
278  }
279  PG_END_TRY();
280 
281  for (i = 0; i < nargs; i++)
282  {
283  if (!plan->args[i].typbyval &&
284  (plan->values[i] != PointerGetDatum(NULL)))
285  {
286  pfree(DatumGetPointer(plan->values[i]));
287  plan->values[i] = PointerGetDatum(NULL);
288  }
289  }
290 
291  if (rv < 0)
292  {
294  "SPI_execute_plan failed: %s",
296  return NULL;
297  }
298 
299  return ret;
300 }
#define PG_FINALLY(...)
Definition: elog.h:388
int j
Definition: isn.c:73
#define PLy_elog
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
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:582
static PyObject * PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
Definition: plpy_spi.c:345
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:591
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:574
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
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
const char * SPI_result_code_string(int code)
Definition: spi.c:1972
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:672

References arg, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, DatumGetPointer(), ERROR, PLyProcedure::fn_readonly, i, j, sort-test::list, palloc(), pfree(), 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(), PointerGetDatum(), SPI_execute_plan(), SPI_processed, SPI_result_code_string(), and SPI_tuptable.

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

304 {
305  int rv;
306  volatile MemoryContext oldcontext;
307  volatile ResourceOwner oldowner;
308  PyObject *ret = NULL;
309 
310  oldcontext = CurrentMemoryContext;
311  oldowner = CurrentResourceOwner;
312 
313  PLy_spi_subtransaction_begin(oldcontext, oldowner);
314 
315  PG_TRY();
316  {
318 
319  pg_verifymbstr(query, strlen(query), false);
320  rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
322 
323  PLy_spi_subtransaction_commit(oldcontext, oldowner);
324  }
325  PG_CATCH();
326  {
327  PLy_spi_subtransaction_abort(oldcontext, oldowner);
328  return NULL;
329  }
330  PG_END_TRY();
331 
332  if (rv < 0)
333  {
334  Py_XDECREF(ret);
336  "SPI_execute failed: %s",
338  return NULL;
339  }
340 
341  return ret;
342 }
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->values = nargs ? palloc0(sizeof(Datum) * nargs) : NULL;
70  plan->args = nargs ? palloc0(sizeof(PLyObToDatum) * nargs) : NULL;
71 
72  MemoryContextSwitchTo(oldcontext);
73 
74  oldcontext = CurrentMemoryContext;
75  oldowner = CurrentResourceOwner;
76 
77  PLy_spi_subtransaction_begin(oldcontext, oldowner);
78 
79  PG_TRY();
80  {
81  int i;
82 
83  for (i = 0; i < nargs; i++)
84  {
85  char *sptr;
86  Oid typeId;
87  int32 typmod;
88 
89  optr = PySequence_GetItem(list, i);
90  if (PyUnicode_Check(optr))
91  sptr = PLyUnicode_AsString(optr);
92  else
93  {
94  ereport(ERROR,
95  (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
96  sptr = NULL; /* keep compiler quiet */
97  }
98 
99  /********************************************************
100  * Resolve argument type names and then look them up by
101  * oid in the system cache, and remember the required
102  *information for input conversion.
103  ********************************************************/
104 
105  (void) parseTypeString(sptr, &typeId, &typmod, NULL);
106 
107  Py_DECREF(optr);
108 
109  /*
110  * set optr to NULL, so we won't try to unref it again in case of
111  * an error
112  */
113  optr = NULL;
114 
115  plan->types[i] = typeId;
116  PLy_output_setup_func(&plan->args[i], plan->mcxt,
117  typeId, typmod,
118  exec_ctx->curr_proc);
119  }
120 
121  pg_verifymbstr(query, strlen(query), false);
122  plan->plan = SPI_prepare(query, plan->nargs, plan->types);
123  if (plan->plan == NULL)
124  elog(ERROR, "SPI_prepare failed: %s",
126 
127  /* transfer plan from procCxt to topCxt */
128  if (SPI_keepplan(plan->plan))
129  elog(ERROR, "SPI_keepplan failed");
130 
131  PLy_spi_subtransaction_commit(oldcontext, oldowner);
132  }
133  PG_CATCH();
134  {
135  Py_DECREF(plan);
136  Py_XDECREF(optr);
137 
138  PLy_spi_subtransaction_abort(oldcontext, oldowner);
139  return NULL;
140  }
141  PG_END_TRY();
142 
143  Assert(plan->plan != NULL);
144  return (PyObject *) plan;
145 }
signed int int32
Definition: c.h:482
#define Assert(condition)
Definition: c.h:837
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
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
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 591 of file plpy_spi.c.

592 {
593  ErrorData *edata;
594  PLyExceptionEntry *entry;
595  PyObject *exc;
596 
597  /* Save error info */
598  MemoryContextSwitchTo(oldcontext);
599  edata = CopyErrorData();
600  FlushErrorState();
601 
602  /* Abort the inner transaction */
604  MemoryContextSwitchTo(oldcontext);
605  CurrentResourceOwner = oldowner;
606 
607  /* Look up the correct exception */
608  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
609  HASH_FIND, NULL);
610 
611  /*
612  * This could be a custom error code, if that's the case fallback to
613  * SPIError
614  */
615  exc = entry ? entry->exc : PLy_exc_spi_error;
616  /* Make Python raise the exception */
617  PLy_spi_exception_set(exc, edata);
618  FreeErrorData(edata);
619 }
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 574 of file plpy_spi.c.

575 {
577  /* Want to run inside function's memory context */
578  MemoryContextSwitchTo(oldcontext);
579 }
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 582 of file plpy_spi.c.

583 {
584  /* Commit the inner transaction, return to outer xact context */
586  MemoryContextSwitchTo(oldcontext);
587  CurrentResourceOwner = oldowner;
588 }
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().