PostgreSQL Source Code  git master
plpy_cursorobject.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "utils/memutils.h"
#include "plpython.h"
#include "plpy_cursorobject.h"
#include "plpy_elog.h"
#include "plpy_main.h"
#include "plpy_planobject.h"
#include "plpy_procedure.h"
#include "plpy_resultobject.h"
#include "plpy_spi.h"
Include dependency graph for plpy_cursorobject.c:

Go to the source code of this file.

Functions

static PyObject * PLy_cursor_query (const char *query)
 
static void PLy_cursor_dealloc (PyObject *arg)
 
static PyObject * PLy_cursor_iternext (PyObject *self)
 
static PyObject * PLy_cursor_fetch (PyObject *self, PyObject *args)
 
static PyObject * PLy_cursor_close (PyObject *self, PyObject *unused)
 
void PLy_cursor_init_type (void)
 
PyObject * PLy_cursor (PyObject *self, PyObject *args)
 
PyObject * PLy_cursor_plan (PyObject *ob, PyObject *args)
 

Variables

static char PLy_cursor_doc []
 
static PyMethodDef PLy_cursor_methods []
 
static PyTypeObject PLy_CursorType
 

Function Documentation

◆ PLy_cursor()

PyObject* PLy_cursor ( PyObject *  self,
PyObject *  args 
)

Definition at line 87 of file plpy_cursorobject.c.

References PLy_cursor_plan(), PLy_cursor_query(), PLy_exc_error, and PLy_exception_set().

88 {
89  char *query;
90  PyObject *plan;
91  PyObject *planargs = NULL;
92 
93  if (PyArg_ParseTuple(args, "s", &query))
94  return PLy_cursor_query(query);
95 
96  PyErr_Clear();
97 
98  if (PyArg_ParseTuple(args, "O|O", &plan, &planargs))
99  return PLy_cursor_plan(plan, planargs);
100 
101  PLy_exception_set(PLy_exc_error, "plpy.cursor expected a query or a plan");
102  return NULL;
103 }
PyObject * PLy_exc_error
Definition: plpy_elog.c:19
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
static PyObject * PLy_cursor_query(const char *query)
PyObject * PLy_cursor_plan(PyObject *ob, PyObject *args)

◆ PLy_cursor_close()

static PyObject * PLy_cursor_close ( PyObject *  self,
PyObject *  unused 
)
static

Definition at line 503 of file plpy_cursorobject.c.

References PLyCursorObject::closed, GetPortalByName(), PLy_exception_set(), PortalIsValid, PLyCursorObject::portalname, SPI_cursor_close(), and UnpinPortal().

504 {
506 
507  if (!cursor->closed)
508  {
509  Portal portal = GetPortalByName(cursor->portalname);
510 
511  if (!PortalIsValid(portal))
512  {
513  PLy_exception_set(PyExc_ValueError,
514  "closing a cursor in an aborted subtransaction");
515  return NULL;
516  }
517 
518  UnpinPortal(portal);
519  SPI_cursor_close(portal);
520  cursor->closed = true;
521  }
522 
523  Py_RETURN_NONE;
524 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:373
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
Definition: type.h:124
#define PortalIsValid(p)
Definition: portal.h:199
void SPI_cursor_close(Portal portal)
Definition: spi.c:1411

◆ PLy_cursor_dealloc()

static void PLy_cursor_dealloc ( PyObject *  arg)
static

Definition at line 312 of file plpy_cursorobject.c.

References PLyCursorObject::closed, GetPortalByName(), PLyCursorObject::mcxt, MemoryContextDelete(), PortalIsValid, PLyCursorObject::portalname, SPI_cursor_close(), and UnpinPortal().

313 {
315  Portal portal;
316 
317  cursor = (PLyCursorObject *) arg;
318 
319  if (!cursor->closed)
320  {
321  portal = GetPortalByName(cursor->portalname);
322 
323  if (PortalIsValid(portal))
324  {
325  UnpinPortal(portal);
326  SPI_cursor_close(portal);
327  }
328  cursor->closed = true;
329  }
330  if (cursor->mcxt)
331  {
332  MemoryContextDelete(cursor->mcxt);
333  cursor->mcxt = NULL;
334  }
335  arg->ob_type->tp_free(arg);
336 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:373
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
MemoryContext mcxt
Definition: type.h:124
#define PortalIsValid(p)
Definition: portal.h:199
void SPI_cursor_close(Portal portal)
Definition: spi.c:1411
void * arg

◆ PLy_cursor_fetch()

static PyObject * PLy_cursor_fetch ( PyObject *  self,
PyObject *  args 
)
static

Definition at line 401 of file plpy_cursorobject.c.

References PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, ereport, errcode(), errmsg(), ERROR, GetPortalByName(), i, PLyResultObject::nrows, PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exception_set(), PLy_input_from_tuple(), PLy_input_setup_tuple(), PLy_result_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PortalIsValid, PLyCursorObject::portalname, PY_SSIZE_T_MAX, PLyCursorObject::result, PLyResultObject::rows, SPI_cursor_fetch(), SPI_freetuptable(), SPI_OK_FETCH, SPI_processed, SPI_tuptable, PLyResultObject::status, SPITupleTable::tupdesc, and SPITupleTable::vals.

402 {
404  int count;
405  PLyResultObject *ret;
407  volatile MemoryContext oldcontext;
408  volatile ResourceOwner oldowner;
409  Portal portal;
410 
411  if (!PyArg_ParseTuple(args, "i:fetch", &count))
412  return NULL;
413 
414  cursor = (PLyCursorObject *) self;
415 
416  if (cursor->closed)
417  {
418  PLy_exception_set(PyExc_ValueError, "fetch from a closed cursor");
419  return NULL;
420  }
421 
422  portal = GetPortalByName(cursor->portalname);
423  if (!PortalIsValid(portal))
424  {
425  PLy_exception_set(PyExc_ValueError,
426  "iterating a cursor in an aborted subtransaction");
427  return NULL;
428  }
429 
430  ret = (PLyResultObject *) PLy_result_new();
431  if (ret == NULL)
432  return NULL;
433 
434  oldcontext = CurrentMemoryContext;
435  oldowner = CurrentResourceOwner;
436 
437  PLy_spi_subtransaction_begin(oldcontext, oldowner);
438 
439  PG_TRY();
440  {
441  SPI_cursor_fetch(portal, true, count);
442 
443  Py_DECREF(ret->status);
444  ret->status = PyInt_FromLong(SPI_OK_FETCH);
445 
446  Py_DECREF(ret->nrows);
447  ret->nrows = (SPI_processed > (uint64) LONG_MAX) ?
448  PyFloat_FromDouble((double) SPI_processed) :
449  PyInt_FromLong((long) SPI_processed);
450 
451  if (SPI_processed != 0)
452  {
453  uint64 i;
454 
455  /*
456  * PyList_New() and PyList_SetItem() use Py_ssize_t for list size
457  * and list indices; so we cannot support a result larger than
458  * PY_SSIZE_T_MAX.
459  */
460  if (SPI_processed > (uint64) PY_SSIZE_T_MAX)
461  ereport(ERROR,
462  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
463  errmsg("query result has too many rows to fit in a Python list")));
464 
465  Py_DECREF(ret->rows);
466  ret->rows = PyList_New(SPI_processed);
467  if (!ret->rows)
468  {
469  Py_DECREF(ret);
470  ret = NULL;
471  }
472  else
473  {
475  exec_ctx->curr_proc);
476 
477  for (i = 0; i < SPI_processed; i++)
478  {
479  PyObject *row = PLy_input_from_tuple(&cursor->result,
480  SPI_tuptable->vals[i],
482 
483  PyList_SetItem(ret->rows, i, row);
484  }
485  }
486  }
487 
489 
490  PLy_spi_subtransaction_commit(oldcontext, oldowner);
491  }
492  PG_CATCH();
493  {
494  PLy_spi_subtransaction_abort(oldcontext, oldowner);
495  return NULL;
496  }
497  PG_END_TRY();
498 
499  return (PyObject *) ret;
500 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
PyObject_HEAD char * portalname
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:137
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPITupleTable * SPI_tuptable
Definition: spi.c:41
int errcode(int sqlerrcode)
Definition: elog.c:575
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
HeapTuple * vals
Definition: spi.h:28
PLyDatumToOb result
uint64 SPI_processed
Definition: spi.c:39
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
#define ERROR
Definition: elog.h:43
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:168
Definition: type.h:124
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define ereport(elevel, rest)
Definition: elog.h:122
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:978
#define PortalIsValid(p)
Definition: portal.h:199
#define SPI_OK_FETCH
Definition: spi.h:52
TupleDesc tupdesc
Definition: spi.h:27
#define PG_CATCH()
Definition: elog.h:293
#define PY_SSIZE_T_MAX
Definition: plpython.h:66
PyObject * PLy_result_new(void)
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1355
PyObject_HEAD PyObject * nrows
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_cursor_init_type()

void PLy_cursor_init_type ( void  )

Definition at line 80 of file plpy_cursorobject.c.

References elog, ERROR, and PLy_CursorType.

Referenced by PLy_init_plpy().

81 {
82  if (PyType_Ready(&PLy_CursorType) < 0)
83  elog(ERROR, "could not initialize PLy_CursorType");
84 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219
static PyTypeObject PLy_CursorType

◆ PLy_cursor_iternext()

static PyObject * PLy_cursor_iternext ( PyObject *  self)
static

Definition at line 339 of file plpy_cursorobject.c.

References PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, GetPortalByName(), PG_CATCH, PG_END_TRY, PG_TRY, PLy_current_execution_context(), PLy_exception_set(), PLy_input_from_tuple(), PLy_input_setup_tuple(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.

340 {
342  PyObject *ret;
344  volatile MemoryContext oldcontext;
345  volatile ResourceOwner oldowner;
346  Portal portal;
347 
348  cursor = (PLyCursorObject *) self;
349 
350  if (cursor->closed)
351  {
352  PLy_exception_set(PyExc_ValueError, "iterating a closed cursor");
353  return NULL;
354  }
355 
356  portal = GetPortalByName(cursor->portalname);
357  if (!PortalIsValid(portal))
358  {
359  PLy_exception_set(PyExc_ValueError,
360  "iterating a cursor in an aborted subtransaction");
361  return NULL;
362  }
363 
364  oldcontext = CurrentMemoryContext;
365  oldowner = CurrentResourceOwner;
366 
367  PLy_spi_subtransaction_begin(oldcontext, oldowner);
368 
369  PG_TRY();
370  {
371  SPI_cursor_fetch(portal, true, 1);
372  if (SPI_processed == 0)
373  {
374  PyErr_SetNone(PyExc_StopIteration);
375  ret = NULL;
376  }
377  else
378  {
380  exec_ctx->curr_proc);
381 
382  ret = PLy_input_from_tuple(&cursor->result, SPI_tuptable->vals[0],
384  }
385 
387 
388  PLy_spi_subtransaction_commit(oldcontext, oldowner);
389  }
390  PG_CATCH();
391  {
392  PLy_spi_subtransaction_abort(oldcontext, oldowner);
393  return NULL;
394  }
395  PG_END_TRY();
396 
397  return ret;
398 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
PyObject_HEAD char * portalname
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc)
Definition: plpy_typeio.c:137
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPITupleTable * SPI_tuptable
Definition: spi.c:41
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
HeapTuple * vals
Definition: spi.h:28
PLyDatumToOb result
uint64 SPI_processed
Definition: spi.c:39
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:168
Definition: type.h:124
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:978
#define PortalIsValid(p)
Definition: portal.h:199
TupleDesc tupdesc
Definition: spi.h:27
#define PG_CATCH()
Definition: elog.h:293
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1355
#define PG_TRY()
Definition: elog.h:284
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_cursor_plan()

PyObject* PLy_cursor_plan ( PyObject *  ob,
PyObject *  args 
)

Definition at line 170 of file plpy_cursorobject.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, arg, PLyPlanObject::args, Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, DatumGetPointer, elog, ERROR, PLyProcedure::fn_readonly, i, PLyCursorObject::mcxt, MemoryContextStrdup(), PortalData::name, PLyPlanObject::nargs, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PinPortal(), PLyPlanObject::plan, PLy_current_execution_context(), PLy_CursorType, PLy_elog, PLy_exception_set(), PLy_exception_set_plural(), PLy_input_setup_func(), PLy_output_convert(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PointerGetDatum, PLyCursorObject::portalname, RECORDOID, PLyCursorObject::result, SPI_cursor_open(), SPI_result, SPI_result_code_string(), TopMemoryContext, PLyObToDatum::typbyval, and PLyPlanObject::values.

Referenced by PLy_cursor(), and PLy_plan_cursor().

171 {
173  volatile int nargs;
174  int i;
175  PLyPlanObject *plan;
177  volatile MemoryContext oldcontext;
178  volatile ResourceOwner oldowner;
179 
180  if (args)
181  {
182  if (!PySequence_Check(args) || PyString_Check(args) || PyUnicode_Check(args))
183  {
184  PLy_exception_set(PyExc_TypeError, "plpy.cursor takes a sequence as its second argument");
185  return NULL;
186  }
187  nargs = PySequence_Length(args);
188  }
189  else
190  nargs = 0;
191 
192  plan = (PLyPlanObject *) ob;
193 
194  if (nargs != plan->nargs)
195  {
196  char *sv;
197  PyObject *so = PyObject_Str(args);
198 
199  if (!so)
200  PLy_elog(ERROR, "could not execute plan");
201  sv = PyString_AsString(so);
202  PLy_exception_set_plural(PyExc_TypeError,
203  "Expected sequence of %d argument, got %d: %s",
204  "Expected sequence of %d arguments, got %d: %s",
205  plan->nargs,
206  plan->nargs, nargs, sv);
207  Py_DECREF(so);
208 
209  return NULL;
210  }
211 
212  if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
213  return NULL;
214  cursor->portalname = NULL;
215  cursor->closed = false;
217  "PL/Python cursor context",
219 
220  /* Initialize for converting result tuples to Python */
221  PLy_input_setup_func(&cursor->result, cursor->mcxt,
222  RECORDOID, -1,
223  exec_ctx->curr_proc);
224 
225  oldcontext = CurrentMemoryContext;
226  oldowner = CurrentResourceOwner;
227 
228  PLy_spi_subtransaction_begin(oldcontext, oldowner);
229 
230  PG_TRY();
231  {
232  Portal portal;
233  char *volatile nulls;
234  volatile int j;
235 
236  if (nargs > 0)
237  nulls = palloc(nargs * sizeof(char));
238  else
239  nulls = NULL;
240 
241  for (j = 0; j < nargs; j++)
242  {
243  PLyObToDatum *arg = &plan->args[j];
244  PyObject *elem;
245 
246  elem = PySequence_GetItem(args, j);
247  PG_TRY();
248  {
249  bool isnull;
250 
251  plan->values[j] = PLy_output_convert(arg, elem, &isnull);
252  nulls[j] = isnull ? 'n' : ' ';
253  }
254  PG_CATCH();
255  {
256  Py_DECREF(elem);
257  PG_RE_THROW();
258  }
259  PG_END_TRY();
260  Py_DECREF(elem);
261  }
262 
263  portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls,
264  exec_ctx->curr_proc->fn_readonly);
265  if (portal == NULL)
266  elog(ERROR, "SPI_cursor_open() failed: %s",
268 
269  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);
270 
271  PinPortal(portal);
272 
273  PLy_spi_subtransaction_commit(oldcontext, oldowner);
274  }
275  PG_CATCH();
276  {
277  int k;
278 
279  /* cleanup plan->values array */
280  for (k = 0; k < nargs; k++)
281  {
282  if (!plan->args[k].typbyval &&
283  (plan->values[k] != PointerGetDatum(NULL)))
284  {
285  pfree(DatumGetPointer(plan->values[k]));
286  plan->values[k] = PointerGetDatum(NULL);
287  }
288  }
289 
290  Py_DECREF(cursor);
291 
292  PLy_spi_subtransaction_abort(oldcontext, oldowner);
293  return NULL;
294  }
295  PG_END_TRY();
296 
297  for (i = 0; i < nargs; i++)
298  {
299  if (!plan->args[i].typbyval &&
300  (plan->values[i] != PointerGetDatum(NULL)))
301  {
302  pfree(DatumGetPointer(plan->values[i]));
303  plan->values[i] = PointerGetDatum(NULL);
304  }
305  }
306 
307  Assert(cursor->portalname != NULL);
308  return (PyObject *) cursor;
309 }
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:514
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:123
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
PyObject_HEAD char * portalname
#define PointerGetDatum(X)
Definition: postgres.h:562
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1037
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:500
PLyDatumToOb result
int SPI_result
Definition: spi.c:42
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
void pfree(void *pointer)
Definition: mcxt.c:936
const char * name
Definition: portal.h:117
#define ERROR
Definition: elog.h:43
MemoryContext mcxt
const char * SPI_result_code_string(int code)
Definition: spi.c:1521
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
void PinPortal(Portal portal)
Definition: portalmem.c:364
PLyObToDatum * args
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
Definition: type.h:124
PyObject_HEAD SPIPlanPtr plan
#define RECORDOID
Definition: pg_type.h:680
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext TopMemoryContext
Definition: mcxt.c:43
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:165
#define PLy_elog
Definition: plpy_elog.h:36
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:680
#define PG_RE_THROW()
Definition: elog.h:314
#define DatumGetPointer(X)
Definition: postgres.h:555
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
void * palloc(Size size)
Definition: mcxt.c:835
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1050
int i
void * arg
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
static PyTypeObject PLy_CursorType
#define PG_END_TRY()
Definition: elog.h:300

◆ PLy_cursor_query()

static PyObject * PLy_cursor_query ( const char *  query)
static

Definition at line 107 of file plpy_cursorobject.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, PLyProcedure::fn_readonly, PLyCursorObject::mcxt, MemoryContextStrdup(), PortalData::name, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PinPortal(), PLy_current_execution_context(), PLy_CursorType, PLy_input_setup_func(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyCursorObject::portalname, RECORDOID, PLyCursorObject::result, SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), and TopMemoryContext.

Referenced by PLy_cursor().

108 {
111  volatile MemoryContext oldcontext;
112  volatile ResourceOwner oldowner;
113 
114  if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
115  return NULL;
116  cursor->portalname = NULL;
117  cursor->closed = false;
119  "PL/Python cursor context",
121 
122  /* Initialize for converting result tuples to Python */
123  PLy_input_setup_func(&cursor->result, cursor->mcxt,
124  RECORDOID, -1,
125  exec_ctx->curr_proc);
126 
127  oldcontext = CurrentMemoryContext;
128  oldowner = CurrentResourceOwner;
129 
130  PLy_spi_subtransaction_begin(oldcontext, oldowner);
131 
132  PG_TRY();
133  {
134  SPIPlanPtr plan;
135  Portal portal;
136 
137  pg_verifymbstr(query, strlen(query), false);
138 
139  plan = SPI_prepare(query, 0, NULL);
140  if (plan == NULL)
141  elog(ERROR, "SPI_prepare failed: %s",
143 
144  portal = SPI_cursor_open(NULL, plan, NULL, NULL,
145  exec_ctx->curr_proc->fn_readonly);
146  SPI_freeplan(plan);
147 
148  if (portal == NULL)
149  elog(ERROR, "SPI_cursor_open() failed: %s",
151 
152  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);
153 
154  PinPortal(portal);
155 
156  PLy_spi_subtransaction_commit(oldcontext, oldowner);
157  }
158  PG_CATCH();
159  {
160  PLy_spi_subtransaction_abort(oldcontext, oldowner);
161  return NULL;
162  }
163  PG_END_TRY();
164 
165  Assert(cursor->portalname != NULL);
166  return (PyObject *) cursor;
167 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:511
PyObject_HEAD char * portalname
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:488
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1037
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:409
PLyDatumToOb result
int SPI_result
Definition: spi.c:42
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:494
const char * name
Definition: portal.h:117
#define ERROR
Definition: elog.h:43
MemoryContext mcxt
const char * SPI_result_code_string(int code)
Definition: spi.c:1521
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
void PinPortal(Portal portal)
Definition: portalmem.c:364
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:421
Definition: type.h:124
#define RECORDOID
Definition: pg_type.h:680
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext TopMemoryContext
Definition: mcxt.c:43
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:165
#define PG_CATCH()
Definition: elog.h:293
#define Assert(condition)
Definition: c.h:680
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:615
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1050
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
static PyTypeObject PLy_CursorType
#define PG_END_TRY()
Definition: elog.h:300

Variable Documentation

◆ PLy_cursor_doc

char PLy_cursor_doc[]
static
Initial value:
= {
"Wrapper around a PostgreSQL cursor"
}

Definition at line 34 of file plpy_cursorobject.c.

◆ PLy_cursor_methods

PyMethodDef PLy_cursor_methods[]
static
Initial value:
= {
{"fetch", PLy_cursor_fetch, METH_VARARGS, NULL},
{"close", PLy_cursor_close, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
}
static PyObject * PLy_cursor_close(PyObject *self, PyObject *unused)
static PyObject * PLy_cursor_fetch(PyObject *self, PyObject *args)

Definition at line 38 of file plpy_cursorobject.c.

◆ PLy_CursorType

PyTypeObject PLy_CursorType
static

Definition at line 44 of file plpy_cursorobject.c.

Referenced by PLy_cursor_init_type(), PLy_cursor_plan(), and PLy_cursor_query().