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

459 {
460  MemoryContext oldcontext = CurrentMemoryContext;
462 
463  PG_TRY();
464  {
465  SPI_commit();
466 
467  /* was cleared at transaction end, reset pointer */
468  exec_ctx->scratch_ctx = NULL;
469  }
470  PG_CATCH();
471  {
472  ErrorData *edata;
473  PLyExceptionEntry *entry;
474  PyObject *exc;
475 
476  /* Save error info */
477  MemoryContextSwitchTo(oldcontext);
478  edata = CopyErrorData();
479  FlushErrorState();
480 
481  /* was cleared at transaction end, reset pointer */
482  exec_ctx->scratch_ctx = NULL;
483 
484  /* Look up the correct exception */
485  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
486  HASH_FIND, NULL);
487 
488  /*
489  * This could be a custom error code, if that's the case fallback to
490  * SPIError
491  */
492  exc = entry ? entry->exc : PLy_exc_spi_error;
493  /* Make Python raise the exception */
494  PLy_spi_exception_set(exc, edata);
495  FreeErrorData(edata);
496 
497  return NULL;
498  }
499  PG_END_TRY();
500 
501  Py_RETURN_NONE;
502 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
void FreeErrorData(ErrorData *edata)
Definition: elog.c:1613
void FlushErrorState(void)
Definition: elog.c:1651
ErrorData * CopyErrorData(void)
Definition: elog.c:1557
#define PG_TRY(...)
Definition: elog.h:309
#define PG_END_TRY(...)
Definition: elog.h:334
#define PG_CATCH(...)
Definition: elog.h:319
@ HASH_FIND
Definition: hsearch.h:113
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
PyObject * PLy_exc_spi_error
Definition: plpy_elog.c:17
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:367
HTAB * PLy_spi_exceptions
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
Definition: plpy_spi.c:629
void SPI_commit(void)
Definition: spi.c:321
int sqlerrcode
Definition: elog.h:377
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 505 of file plpy_spi.c.

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

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

630 {
631  PyObject *args = NULL;
632  PyObject *spierror = NULL;
633  PyObject *spidata = NULL;
634 
635  args = Py_BuildValue("(s)", edata->message);
636  if (!args)
637  goto failure;
638 
639  /* create a new SPI exception with the error message as the parameter */
640  spierror = PyObject_CallObject(excclass, args);
641  if (!spierror)
642  goto failure;
643 
644  spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
645  edata->internalquery, edata->internalpos,
646  edata->schema_name, edata->table_name, edata->column_name,
647  edata->datatype_name, edata->constraint_name);
648  if (!spidata)
649  goto failure;
650 
651  if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1)
652  goto failure;
653 
654  PyErr_SetObject(excclass, spierror);
655 
656  Py_DECREF(args);
657  Py_DECREF(spierror);
658  Py_DECREF(spidata);
659  return;
660 
661 failure:
662  Py_XDECREF(args);
663  Py_XDECREF(spierror);
664  Py_XDECREF(spidata);
665  elog(ERROR, "could not convert SPI error to Python exception");
666 }
#define ERROR
Definition: elog.h:35
int internalpos
Definition: elog.h:391
char * schema_name
Definition: elog.h:385
char * internalquery
Definition: elog.h:392
char * datatype_name
Definition: elog.h:388
char * detail
Definition: elog.h:379
char * table_name
Definition: elog.h:386
char * message
Definition: elog.h:378
char * hint
Definition: elog.h:381
char * constraint_name
Definition: elog.h:389
char * column_name
Definition: elog.h:387

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

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

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

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

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

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

References arg, PLyPlanObject::args, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, DatumGetPointer(), ERROR, PLyProcedure::fn_readonly, i, j, sort-test::list, 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(), PLyUnicode_AsString(), 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().

◆ PLy_spi_execute_query()

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

Definition at line 306 of file plpy_spi.c.

307 {
308  int rv;
309  volatile MemoryContext oldcontext;
310  volatile ResourceOwner oldowner;
311  PyObject *ret = NULL;
312 
313  oldcontext = CurrentMemoryContext;
314  oldowner = CurrentResourceOwner;
315 
316  PLy_spi_subtransaction_begin(oldcontext, oldowner);
317 
318  PG_TRY();
319  {
321 
322  pg_verifymbstr(query, strlen(query), false);
323  rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit);
325 
326  PLy_spi_subtransaction_commit(oldcontext, oldowner);
327  }
328  PG_CATCH();
329  {
330  PLy_spi_subtransaction_abort(oldcontext, oldowner);
331  return NULL;
332  }
333  PG_END_TRY();
334 
335  if (rv < 0)
336  {
337  Py_XDECREF(ret);
339  "SPI_execute failed: %s",
341  return NULL;
342  }
343 
344  return ret;
345 }
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: mbutils.c:1505
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:594

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

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 (PyUnicode_Check(optr))
94  sptr = PLyUnicode_AsString(optr);
95  else
96  {
97  ereport(ERROR,
98  (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)));
99  sptr = NULL; /* keep compiler quiet */
100  }
101 
102  /********************************************************
103  * Resolve argument type names and then look them up by
104  * oid in the system cache, and remember the required
105  *information for input conversion.
106  ********************************************************/
107 
108  parseTypeString(sptr, &typeId, &typmod, false);
109 
110  Py_DECREF(optr);
111 
112  /*
113  * set optr to NULL, so we won't try to unref it again in case of
114  * an error
115  */
116  optr = NULL;
117 
118  plan->types[i] = typeId;
119  PLy_output_setup_func(&plan->args[i], plan->mcxt,
120  typeId, typmod,
121  exec_ctx->curr_proc);
122  }
123 
124  pg_verifymbstr(query, strlen(query), false);
125  plan->plan = SPI_prepare(query, plan->nargs, plan->types);
126  if (plan->plan == NULL)
127  elog(ERROR, "SPI_prepare failed: %s",
129 
130  /* transfer plan from procCxt to topCxt */
131  if (SPI_keepplan(plan->plan))
132  elog(ERROR, "SPI_keepplan failed");
133 
134  PLy_spi_subtransaction_commit(oldcontext, oldowner);
135  }
136  PG_CATCH();
137  {
138  Py_DECREF(plan);
139  Py_XDECREF(optr);
140 
141  PLy_spi_subtransaction_abort(oldcontext, oldowner);
142  return NULL;
143  }
144  PG_END_TRY();
145 
146  Assert(plan->plan != NULL);
147  return (PyObject *) plan;
148 }
signed int int32
Definition: c.h:430
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc0(Size size)
Definition: mcxt.c:1230
void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:780
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:295
uintptr_t Datum
Definition: postgres.h:412
unsigned int Oid
Definition: postgres_ext.h:31
int SPI_result
Definition: spi.c:47
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:858
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:974
MemoryContext mcxt

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, generate_unaccent_rules::args, 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.

◆ PLy_spi_subtransaction_abort()

void PLy_spi_subtransaction_abort ( MemoryContext  oldcontext,
ResourceOwner  oldowner 
)

Definition at line 594 of file plpy_spi.c.

595 {
596  ErrorData *edata;
597  PLyExceptionEntry *entry;
598  PyObject *exc;
599 
600  /* Save error info */
601  MemoryContextSwitchTo(oldcontext);
602  edata = CopyErrorData();
603  FlushErrorState();
604 
605  /* Abort the inner transaction */
607  MemoryContextSwitchTo(oldcontext);
608  CurrentResourceOwner = oldowner;
609 
610  /* Look up the correct exception */
611  entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
612  HASH_FIND, NULL);
613 
614  /*
615  * This could be a custom error code, if that's the case fallback to
616  * SPIError
617  */
618  exc = entry ? entry->exc : PLy_exc_spi_error;
619  /* Make Python raise the exception */
620  PLy_spi_exception_set(exc, edata);
621  FreeErrorData(edata);
622 }
void RollbackAndReleaseCurrentSubTransaction(void)
Definition: xact.c:4625

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

578 {
580  /* Want to run inside function's memory context */
581  MemoryContextSwitchTo(oldcontext);
582 }
void BeginInternalSubTransaction(const char *name)
Definition: xact.c:4520

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

586 {
587  /* Commit the inner transaction, return to outer xact context */
589  MemoryContextSwitchTo(oldcontext);
590  CurrentResourceOwner = oldowner;
591 }
void ReleaseCurrentSubTransaction(void)
Definition: xact.c:4591

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