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 "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 "plpython.h"
#include "utils/memutils.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 60 of file plpy_cursorobject.c.

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

61 {
62  char *query;
63  PyObject *plan;
64  PyObject *planargs = NULL;
65 
66  if (PyArg_ParseTuple(args, "s", &query))
67  return PLy_cursor_query(query);
68 
69  PyErr_Clear();
70 
71  if (PyArg_ParseTuple(args, "O|O", &plan, &planargs))
72  return PLy_cursor_plan(plan, planargs);
73 
74  PLy_exception_set(PLy_exc_error, "plpy.cursor expected a query or a plan");
75  return NULL;
76 }
PyObject * PLy_exc_error
Definition: plpy_elog.c:15
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
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 473 of file plpy_cursorobject.c.

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

474 {
476 
477  if (!cursor->closed)
478  {
479  Portal portal = GetPortalByName(cursor->portalname);
480 
481  if (!PortalIsValid(portal))
482  {
483  PLy_exception_set(PyExc_ValueError,
484  "closing a cursor in an aborted subtransaction");
485  return NULL;
486  }
487 
488  UnpinPortal(portal);
489  SPI_cursor_close(portal);
490  cursor->closed = true;
491  }
492 
493  Py_RETURN_NONE;
494 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:377
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
Definition: type.h:130
#define PortalIsValid(p)
Definition: portal.h:201
void SPI_cursor_close(Portal portal)
Definition: spi.c:1595

◆ PLy_cursor_dealloc()

static void PLy_cursor_dealloc ( PyObject *  arg)
static

Definition at line 283 of file plpy_cursorobject.c.

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

284 {
286  Portal portal;
287 
288  cursor = (PLyCursorObject *) arg;
289 
290  if (!cursor->closed)
291  {
292  portal = GetPortalByName(cursor->portalname);
293 
294  if (PortalIsValid(portal))
295  {
296  UnpinPortal(portal);
297  SPI_cursor_close(portal);
298  }
299  cursor->closed = true;
300  }
301  if (cursor->mcxt)
302  {
303  MemoryContextDelete(cursor->mcxt);
304  cursor->mcxt = NULL;
305  }
306  arg->ob_type->tp_free(arg);
307 }
void UnpinPortal(Portal portal)
Definition: portalmem.c:377
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
MemoryContext mcxt
Definition: type.h:130
#define PortalIsValid(p)
Definition: portal.h:201
void SPI_cursor_close(Portal portal)
Definition: spi.c:1595
void * arg

◆ PLy_cursor_fetch()

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

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

373 {
375  int count;
376  PLyResultObject *ret;
378  volatile MemoryContext oldcontext;
379  volatile ResourceOwner oldowner;
380  Portal portal;
381 
382  if (!PyArg_ParseTuple(args, "i:fetch", &count))
383  return NULL;
384 
385  cursor = (PLyCursorObject *) self;
386 
387  if (cursor->closed)
388  {
389  PLy_exception_set(PyExc_ValueError, "fetch from a closed cursor");
390  return NULL;
391  }
392 
393  portal = GetPortalByName(cursor->portalname);
394  if (!PortalIsValid(portal))
395  {
396  PLy_exception_set(PyExc_ValueError,
397  "iterating a cursor in an aborted subtransaction");
398  return NULL;
399  }
400 
401  ret = (PLyResultObject *) PLy_result_new();
402  if (ret == NULL)
403  return NULL;
404 
405  oldcontext = CurrentMemoryContext;
406  oldowner = CurrentResourceOwner;
407 
408  PLy_spi_subtransaction_begin(oldcontext, oldowner);
409 
410  PG_TRY();
411  {
412  SPI_cursor_fetch(portal, true, count);
413 
414  Py_DECREF(ret->status);
415  ret->status = PyInt_FromLong(SPI_OK_FETCH);
416 
417  Py_DECREF(ret->nrows);
418  ret->nrows = PyLong_FromUnsignedLongLong(SPI_processed);
419 
420  if (SPI_processed != 0)
421  {
422  uint64 i;
423 
424  /*
425  * PyList_New() and PyList_SetItem() use Py_ssize_t for list size
426  * and list indices; so we cannot support a result larger than
427  * PY_SSIZE_T_MAX.
428  */
429  if (SPI_processed > (uint64) PY_SSIZE_T_MAX)
430  ereport(ERROR,
431  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
432  errmsg("query result has too many rows to fit in a Python list")));
433 
434  Py_DECREF(ret->rows);
435  ret->rows = PyList_New(SPI_processed);
436  if (!ret->rows)
437  {
438  Py_DECREF(ret);
439  ret = NULL;
440  }
441  else
442  {
444  exec_ctx->curr_proc);
445 
446  for (i = 0; i < SPI_processed; i++)
447  {
448  PyObject *row = PLy_input_from_tuple(&cursor->result,
449  SPI_tuptable->vals[i],
451  true);
452 
453  PyList_SetItem(ret->rows, i, row);
454  }
455  }
456  }
457 
459 
460  PLy_spi_subtransaction_commit(oldcontext, oldowner);
461  }
462  PG_CATCH();
463  {
464  PLy_spi_subtransaction_abort(oldcontext, oldowner);
465  return NULL;
466  }
467  PG_END_TRY();
468 
469  return (PyObject *) ret;
470 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:608
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
HeapTuple * vals
Definition: spi.h:26
PLyDatumToOb result
uint64 SPI_processed
Definition: spi.c:45
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
#define ERROR
Definition: elog.h:43
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:164
Definition: type.h:130
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
#define PortalIsValid(p)
Definition: portal.h:201
#define SPI_OK_FETCH
Definition: spi.h:55
TupleDesc tupdesc
Definition: spi.h:25
#define PG_CATCH()
Definition: elog.h:332
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:133
#define PY_SSIZE_T_MAX
Definition: plpython.h:68
PyObject * PLy_result_new(void)
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1539
PyObject_HEAD PyObject * nrows
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347

◆ PLy_cursor_init_type()

void PLy_cursor_init_type ( void  )

Definition at line 53 of file plpy_cursorobject.c.

References elog, ERROR, and PLy_CursorType.

Referenced by PLy_init_plpy().

54 {
55  if (PyType_Ready(&PLy_CursorType) < 0)
56  elog(ERROR, "could not initialize PLy_CursorType");
57 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:228
static PyTypeObject PLy_CursorType

◆ PLy_cursor_iternext()

static PyObject * PLy_cursor_iternext ( PyObject *  self)
static

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

311 {
313  PyObject *ret;
315  volatile MemoryContext oldcontext;
316  volatile ResourceOwner oldowner;
317  Portal portal;
318 
319  cursor = (PLyCursorObject *) self;
320 
321  if (cursor->closed)
322  {
323  PLy_exception_set(PyExc_ValueError, "iterating a closed cursor");
324  return NULL;
325  }
326 
327  portal = GetPortalByName(cursor->portalname);
328  if (!PortalIsValid(portal))
329  {
330  PLy_exception_set(PyExc_ValueError,
331  "iterating a cursor in an aborted subtransaction");
332  return NULL;
333  }
334 
335  oldcontext = CurrentMemoryContext;
336  oldowner = CurrentResourceOwner;
337 
338  PLy_spi_subtransaction_begin(oldcontext, oldowner);
339 
340  PG_TRY();
341  {
342  SPI_cursor_fetch(portal, true, 1);
343  if (SPI_processed == 0)
344  {
345  PyErr_SetNone(PyExc_StopIteration);
346  ret = NULL;
347  }
348  else
349  {
351  exec_ctx->curr_proc);
352 
353  ret = PLy_input_from_tuple(&cursor->result, SPI_tuptable->vals[0],
354  SPI_tuptable->tupdesc, true);
355  }
356 
358 
359  PLy_spi_subtransaction_commit(oldcontext, oldowner);
360  }
361  PG_CATCH();
362  {
363  PLy_spi_subtransaction_abort(oldcontext, oldowner);
364  return NULL;
365  }
366  PG_END_TRY();
367 
368  return ret;
369 }
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
PyObject_HEAD char * portalname
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
SPITupleTable * SPI_tuptable
Definition: spi.c:46
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
HeapTuple * vals
Definition: spi.h:26
PLyDatumToOb result
uint64 SPI_processed
Definition: spi.c:45
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc, PLyProcedure *proc)
Definition: plpy_typeio.c:164
Definition: type.h:130
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
PLyProcedure * curr_proc
Definition: plpy_main.h:20
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
#define PortalIsValid(p)
Definition: portal.h:201
TupleDesc tupdesc
Definition: spi.h:25
#define PG_CATCH()
Definition: elog.h:332
PyObject * PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc, bool include_generated)
Definition: plpy_typeio.c:133
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1539
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347

◆ PLy_cursor_plan()

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

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

144 {
146  volatile int nargs;
147  int i;
148  PLyPlanObject *plan;
150  volatile MemoryContext oldcontext;
151  volatile ResourceOwner oldowner;
152 
153  if (args)
154  {
155  if (!PySequence_Check(args) || PyString_Check(args) || PyUnicode_Check(args))
156  {
157  PLy_exception_set(PyExc_TypeError, "plpy.cursor takes a sequence as its second argument");
158  return NULL;
159  }
160  nargs = PySequence_Length(args);
161  }
162  else
163  nargs = 0;
164 
165  plan = (PLyPlanObject *) ob;
166 
167  if (nargs != plan->nargs)
168  {
169  char *sv;
170  PyObject *so = PyObject_Str(args);
171 
172  if (!so)
173  PLy_elog(ERROR, "could not execute plan");
174  sv = PyString_AsString(so);
175  PLy_exception_set_plural(PyExc_TypeError,
176  "Expected sequence of %d argument, got %d: %s",
177  "Expected sequence of %d arguments, got %d: %s",
178  plan->nargs,
179  plan->nargs, nargs, sv);
180  Py_DECREF(so);
181 
182  return NULL;
183  }
184 
185  if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
186  return NULL;
187  cursor->portalname = NULL;
188  cursor->closed = false;
190  "PL/Python cursor context",
192 
193  /* Initialize for converting result tuples to Python */
194  PLy_input_setup_func(&cursor->result, cursor->mcxt,
195  RECORDOID, -1,
196  exec_ctx->curr_proc);
197 
198  oldcontext = CurrentMemoryContext;
199  oldowner = CurrentResourceOwner;
200 
201  PLy_spi_subtransaction_begin(oldcontext, oldowner);
202 
203  PG_TRY();
204  {
205  Portal portal;
206  char *volatile nulls;
207  volatile int j;
208 
209  if (nargs > 0)
210  nulls = palloc(nargs * sizeof(char));
211  else
212  nulls = NULL;
213 
214  for (j = 0; j < nargs; j++)
215  {
216  PLyObToDatum *arg = &plan->args[j];
217  PyObject *elem;
218 
219  elem = PySequence_GetItem(args, j);
220  PG_TRY();
221  {
222  bool isnull;
223 
224  plan->values[j] = PLy_output_convert(arg, elem, &isnull);
225  nulls[j] = isnull ? 'n' : ' ';
226  }
227  PG_FINALLY();
228  {
229  Py_DECREF(elem);
230  }
231  PG_END_TRY();
232  }
233 
234  portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls,
235  exec_ctx->curr_proc->fn_readonly);
236  if (portal == NULL)
237  elog(ERROR, "SPI_cursor_open() failed: %s",
239 
240  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);
241 
242  PinPortal(portal);
243 
244  PLy_spi_subtransaction_commit(oldcontext, oldowner);
245  }
246  PG_CATCH();
247  {
248  int k;
249 
250  /* cleanup plan->values array */
251  for (k = 0; k < nargs; k++)
252  {
253  if (!plan->args[k].typbyval &&
254  (plan->values[k] != PointerGetDatum(NULL)))
255  {
256  pfree(DatumGetPointer(plan->values[k]));
257  plan->values[k] = PointerGetDatum(NULL);
258  }
259  }
260 
261  Py_DECREF(cursor);
262 
263  PLy_spi_subtransaction_abort(oldcontext, oldowner);
264  return NULL;
265  }
266  PG_END_TRY();
267 
268  for (i = 0; i < nargs; i++)
269  {
270  if (!plan->args[i].typbyval &&
271  (plan->values[i] != PointerGetDatum(NULL)))
272  {
273  pfree(DatumGetPointer(plan->values[i]));
274  plan->values[i] = PointerGetDatum(NULL);
275  }
276  }
277 
278  Assert(cursor->portalname != NULL);
279  return (PyObject *) cursor;
280 }
void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: plpy_elog.c:501
#define AllocSetContextCreate
Definition: memutils.h:170
Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val, bool *isnull)
Definition: plpy_typeio.c:119
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
PyObject_HEAD char * portalname
#define PointerGetDatum(X)
Definition: postgres.h:556
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1221
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
void PLy_exception_set(PyObject *exc, const char *fmt,...)
Definition: plpy_elog.c:487
PLyDatumToOb result
int SPI_result
Definition: spi.c:47
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
void pfree(void *pointer)
Definition: mcxt.c:1056
const char * name
Definition: portal.h:117
#define ERROR
Definition: elog.h:43
MemoryContext mcxt
#define PLy_elog
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void PinPortal(Portal portal)
Definition: portalmem.c:368
PLyObToDatum * args
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:417
Definition: type.h:130
PyObject_HEAD SPIPlanPtr plan
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext TopMemoryContext
Definition: mcxt.c:44
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define PG_FINALLY()
Definition: elog.h:339
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
#define DatumGetPointer(X)
Definition: postgres.h:549
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
void * palloc(Size size)
Definition: mcxt.c:949
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
int i
void * arg
#define PG_TRY()
Definition: elog.h:322
static PyTypeObject PLy_CursorType
#define PG_END_TRY()
Definition: elog.h:347

◆ PLy_cursor_query()

static PyObject * PLy_cursor_query ( const char *  query)
static

Definition at line 80 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, PLyCursorObject::result, SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_result, SPI_result_code_string(), and TopMemoryContext.

Referenced by PLy_cursor().

81 {
84  volatile MemoryContext oldcontext;
85  volatile ResourceOwner oldowner;
86 
87  if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
88  return NULL;
89  cursor->portalname = NULL;
90  cursor->closed = false;
92  "PL/Python cursor context",
94 
95  /* Initialize for converting result tuples to Python */
96  PLy_input_setup_func(&cursor->result, cursor->mcxt,
97  RECORDOID, -1,
98  exec_ctx->curr_proc);
99 
100  oldcontext = CurrentMemoryContext;
101  oldowner = CurrentResourceOwner;
102 
103  PLy_spi_subtransaction_begin(oldcontext, oldowner);
104 
105  PG_TRY();
106  {
107  SPIPlanPtr plan;
108  Portal portal;
109 
110  pg_verifymbstr(query, strlen(query), false);
111 
112  plan = SPI_prepare(query, 0, NULL);
113  if (plan == NULL)
114  elog(ERROR, "SPI_prepare failed: %s",
116 
117  portal = SPI_cursor_open(NULL, plan, NULL, NULL,
118  exec_ctx->curr_proc->fn_readonly);
119  SPI_freeplan(plan);
120 
121  if (portal == NULL)
122  elog(ERROR, "SPI_cursor_open() failed: %s",
124 
125  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);
126 
127  PinPortal(portal);
128 
129  PLy_spi_subtransaction_commit(oldcontext, oldowner);
130  }
131  PG_CATCH();
132  {
133  PLy_spi_subtransaction_abort(oldcontext, oldowner);
134  return NULL;
135  }
136  PG_END_TRY();
137 
138  Assert(cursor->portalname != NULL);
139  return (PyObject *) cursor;
140 }
#define AllocSetContextCreate
Definition: memutils.h:170
void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:502
PyObject_HEAD char * portalname
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:674
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1221
PLyExecutionContext * PLy_current_execution_context(void)
Definition: plpy_main.c:410
PLyDatumToOb result
int SPI_result
Definition: spi.c:47
void PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:485
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:1705
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void PinPortal(Portal portal)
Definition: portalmem.c:368
void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, int32 typmod, PLyProcedure *proc)
Definition: plpy_typeio.c:417
Definition: type.h:130
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext TopMemoryContext
Definition: mcxt.c:44
PLyProcedure * curr_proc
Definition: plpy_main.h:20
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:801
void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner)
Definition: plpy_spi.c:493
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1914
#define PG_TRY()
Definition: elog.h:322
static PyTypeObject PLy_CursorType
#define PG_END_TRY()
Definition: elog.h:347

Variable Documentation

◆ PLy_cursor_doc

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

Definition at line 30 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 34 of file plpy_cursorobject.c.

◆ PLy_CursorType

PyTypeObject PLy_CursorType
static
Initial value:
= {
.tp_name = "PLyCursor",
.tp_basicsize = sizeof(PLyCursorObject),
.tp_dealloc = PLy_cursor_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_ITER,
.tp_doc = PLy_cursor_doc,
.tp_iter = PyObject_SelfIter,
.tp_iternext = PLy_cursor_iternext,
.tp_methods = PLy_cursor_methods,
}
static PyMethodDef PLy_cursor_methods[]
#define PyVarObject_HEAD_INIT(type, size)
Definition: plpython.h:113
static PyObject * PLy_cursor_iternext(PyObject *self)
static void PLy_cursor_dealloc(PyObject *arg)
static char PLy_cursor_doc[]
struct PLyCursorObject PLyCursorObject

Definition at line 40 of file plpy_cursorobject.c.

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