Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  plpy_cursorobject.c

  Sprache: C
 

/*
 * the PLyCursor class
 *
 * src/pl/plpython/plpy_cursorobject.c
 */


#include "postgres.h"

#include <limits.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_resultobject.h"
#include "plpy_spi.h"
#include "plpy_util.h"
#include "utils/memutils.h"

static PyObject *PLy_cursor_query(const char *query);
static void PLy_cursor_dealloc(PLyCursorObject *self);
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);

static const char PLy_cursor_doc[] = "Wrapper around a PostgreSQL cursor";

static PyMethodDef PLy_cursor_methods[] = {
 {"fetch", PLy_cursor_fetch, METH_VARARGS, NULL},
 {"close", PLy_cursor_close, METH_NOARGS, NULL},
 {NULL, NULL, 0, NULL}
};

static PyType_Slot PLyCursor_slots[] =
{
 {
  Py_tp_dealloc, PLy_cursor_dealloc
 },
 {
  Py_tp_doc, (char *) PLy_cursor_doc
 },
 {
  Py_tp_iter, PyObject_SelfIter
 },
 {
  Py_tp_iternext, PLy_cursor_iternext
 },
 {
  Py_tp_methods, PLy_cursor_methods
 },
 {
  0, NULL
 }
};

static PyType_Spec PLyCursor_spec =
{
 .name = "PLyCursor",
 .basicsize = sizeof(PLyCursorObject),
 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 .slots = PLyCursor_slots,
};

static PyTypeObject *PLy_CursorType;

void
PLy_cursor_init_type(void)
{
 PLy_CursorType = (PyTypeObject *) PyType_FromSpec(&PLyCursor_spec);
 if (!PLy_CursorType)
  elog(ERROR, "could not initialize PLy_CursorType");
}

PyObject *
PLy_cursor(PyObject *self, PyObject *args)
{
 char    *query;
 PyObject   *plan;
 PyObject   *planargs = NULL;

 if (PyArg_ParseTuple(args, "s", &query))
  return PLy_cursor_query(query);

 PyErr_Clear();

 if (PyArg_ParseTuple(args, "O|O", &plan, &planargs))
  return PLy_cursor_plan(plan, planargs);

 PLy_exception_set(PLy_exc_error, "plpy.cursor expected a query or a plan");
 return NULL;
}


static PyObject *
PLy_cursor_query(const char *query)
{
 PLyCursorObject *cursor;
 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
 volatile MemoryContext oldcontext;
 volatile ResourceOwner oldowner;

 if ((cursor = PyObject_New(PLyCursorObject, PLy_CursorType)) == NULL)
  return NULL;
#if PY_VERSION_HEX < 0x03080000
 /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
 Py_INCREF(PLy_CursorType);
#endif
 cursor->portalname = NULL;
 cursor->closed = false;
 cursor->mcxt = AllocSetContextCreate(TopMemoryContext,
           "PL/Python cursor context",
           ALLOCSET_DEFAULT_SIZES);

 /* Initialize for converting result tuples to Python */
 PLy_input_setup_func(&cursor->result, cursor->mcxt,
       RECORDOID, -1,
       exec_ctx->curr_proc);

 oldcontext = CurrentMemoryContext;
 oldowner = CurrentResourceOwner;

 PLy_spi_subtransaction_begin(oldcontext, oldowner);

 PG_TRY();
 {
  SPIPlanPtr plan;
  Portal  portal;

  pg_verifymbstr(query, strlen(query), false);

  plan = SPI_prepare(query, 0, NULL);
  if (plan == NULL)
   elog(ERROR, "SPI_prepare failed: %s",
     SPI_result_code_string(SPI_result));

  portal = SPI_cursor_open(NULL, plan, NULL, NULL,
         exec_ctx->curr_proc->fn_readonly);
  SPI_freeplan(plan);

  if (portal == NULL)
   elog(ERROR, "SPI_cursor_open() failed: %s",
     SPI_result_code_string(SPI_result));

  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);

  PinPortal(portal);

  PLy_spi_subtransaction_commit(oldcontext, oldowner);
 }
 PG_CATCH();
 {
  PLy_spi_subtransaction_abort(oldcontext, oldowner);
  return NULL;
 }
 PG_END_TRY();

 Assert(cursor->portalname != NULL);
 return (PyObject *) cursor;
}

PyObject *
PLy_cursor_plan(PyObject *ob, PyObject *args)
{
 PLyCursorObject *cursor;
 volatile int nargs;
 PLyPlanObject *plan;
 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
 volatile MemoryContext oldcontext;
 volatile ResourceOwner oldowner;

 if (args)
 {
  if (!PySequence_Check(args) || PyUnicode_Check(args))
  {
   PLy_exception_set(PyExc_TypeError, "plpy.cursor takes a sequence as its second argument");
   return NULL;
  }
  nargs = PySequence_Length(args);
 }
 else
  nargs = 0;

 plan = (PLyPlanObject *) ob;

 if (nargs != plan->nargs)
 {
  char    *sv;
  PyObject   *so = PyObject_Str(args);

  if (!so)
   PLy_elog(ERROR, "could not execute plan");
  sv = PLyUnicode_AsString(so);
  PLy_exception_set_plural(PyExc_TypeError,
         "Expected sequence of %d argument, got %d: %s",
         "Expected sequence of %d arguments, got %d: %s",
         plan->nargs,
         plan->nargs, nargs, sv);
  Py_DECREF(so);

  return NULL;
 }

 if ((cursor = PyObject_New(PLyCursorObject, PLy_CursorType)) == NULL)
  return NULL;
#if PY_VERSION_HEX < 0x03080000
 /* Workaround for Python issue 35810; no longer necessary in Python 3.8 */
 Py_INCREF(PLy_CursorType);
#endif
 cursor->portalname = NULL;
 cursor->closed = false;
 cursor->mcxt = AllocSetContextCreate(TopMemoryContext,
           "PL/Python cursor context",
           ALLOCSET_DEFAULT_SIZES);

 /* Initialize for converting result tuples to Python */
 PLy_input_setup_func(&cursor->result, cursor->mcxt,
       RECORDOID, -1,
       exec_ctx->curr_proc);

 oldcontext = CurrentMemoryContext;
 oldowner = CurrentResourceOwner;

 PLy_spi_subtransaction_begin(oldcontext, oldowner);

 PG_TRY();
 {
  Portal  portal;
  MemoryContext tmpcontext;
  Datum    *volatile values;
  char    *volatile nulls;
  volatile int j;

  /*
   * Converted arguments and associated cruft will be in this context,
   * which is local to our subtransaction.
 */

  tmpcontext = AllocSetContextCreate(CurTransactionContext,
             "PL/Python temporary context",
             ALLOCSET_SMALL_SIZES);
  MemoryContextSwitchTo(tmpcontext);

  if (nargs > 0)
  {
   values = (Datum *) palloc(nargs * sizeof(Datum));
   nulls = (char *) palloc(nargs * sizeof(char));
  }
  else
  {
   values = NULL;
   nulls = NULL;
  }

  for (j = 0; j < nargs; j++)
  {
   PLyObToDatum *arg = &plan->args[j];
   PyObject   *elem;

   elem = PySequence_GetItem(args, j);
   PG_TRY(2);
   {
    bool  isnull;

    values[j] = PLy_output_convert(arg, elem, &isnull);
    nulls[j] = isnull ? 'n' : ' ';
   }
   PG_FINALLY(2);
   {
    Py_DECREF(elem);
   }
   PG_END_TRY(2);
  }

  MemoryContextSwitchTo(oldcontext);

  portal = SPI_cursor_open(NULL, plan->plan, values, nulls,
         exec_ctx->curr_proc->fn_readonly);
  if (portal == NULL)
   elog(ERROR, "SPI_cursor_open() failed: %s",
     SPI_result_code_string(SPI_result));

  cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name);

  PinPortal(portal);

  MemoryContextDelete(tmpcontext);
  PLy_spi_subtransaction_commit(oldcontext, oldowner);
 }
 PG_CATCH();
 {
  Py_DECREF(cursor);
  /* Subtransaction abort will remove the tmpcontext */
  PLy_spi_subtransaction_abort(oldcontext, oldowner);
  return NULL;
 }
 PG_END_TRY();

 Assert(cursor->portalname != NULL);
 return (PyObject *) cursor;
}

static void
PLy_cursor_dealloc(PLyCursorObject *self)
{
#if PY_VERSION_HEX >= 0x03080000
 PyTypeObject *tp = Py_TYPE(self);
#endif
 Portal  portal;

 if (!self->closed)
 {
  portal = GetPortalByName(self->portalname);

  if (PortalIsValid(portal))
  {
   UnpinPortal(portal);
   SPI_cursor_close(portal);
  }
  self->closed = true;
 }
 if (self->mcxt)
 {
  MemoryContextDelete(self->mcxt);
  self->mcxt = NULL;
 }

 PyObject_Free(self);
#if PY_VERSION_HEX >= 0x03080000
 /* This was not needed before Python 3.8 (Python issue 35810) */
 Py_DECREF(tp);
#endif
}

static PyObject *
PLy_cursor_iternext(PyObject *self)
{
 PLyCursorObject *cursor;
 PyObject   *ret;
 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
 volatile MemoryContext oldcontext;
 volatile ResourceOwner oldowner;
 Portal  portal;

 cursor = (PLyCursorObject *) self;

 if (cursor->closed)
 {
  PLy_exception_set(PyExc_ValueError, "iterating a closed cursor");
  return NULL;
 }

 portal = GetPortalByName(cursor->portalname);
 if (!PortalIsValid(portal))
 {
  PLy_exception_set(PyExc_ValueError,
        "iterating a cursor in an aborted subtransaction");
  return NULL;
 }

 oldcontext = CurrentMemoryContext;
 oldowner = CurrentResourceOwner;

 PLy_spi_subtransaction_begin(oldcontext, oldowner);

 PG_TRY();
 {
  SPI_cursor_fetch(portal, true1);
  if (SPI_processed == 0)
  {
   PyErr_SetNone(PyExc_StopIteration);
   ret = NULL;
  }
  else
  {
   PLy_input_setup_tuple(&cursor->result, SPI_tuptable->tupdesc,
          exec_ctx->curr_proc);

   ret = PLy_input_from_tuple(&cursor->result, SPI_tuptable->vals[0],
            SPI_tuptable->tupdesc, true);
  }

  SPI_freetuptable(SPI_tuptable);

  PLy_spi_subtransaction_commit(oldcontext, oldowner);
 }
 PG_CATCH();
 {
  PLy_spi_subtransaction_abort(oldcontext, oldowner);
  return NULL;
 }
 PG_END_TRY();

 return ret;
}

static PyObject *
PLy_cursor_fetch(PyObject *self, PyObject *args)
{
 PLyCursorObject *cursor;
 int   count;
 PLyResultObject *ret;
 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
 volatile MemoryContext oldcontext;
 volatile ResourceOwner oldowner;
 Portal  portal;

 if (!PyArg_ParseTuple(args, "i:fetch", &count))
  return NULL;

 cursor = (PLyCursorObject *) self;

 if (cursor->closed)
 {
  PLy_exception_set(PyExc_ValueError, "fetch from a closed cursor");
  return NULL;
 }

 portal = GetPortalByName(cursor->portalname);
 if (!PortalIsValid(portal))
 {
  PLy_exception_set(PyExc_ValueError,
        "iterating a cursor in an aborted subtransaction");
  return NULL;
 }

 ret = (PLyResultObject *) PLy_result_new();
 if (ret == NULL)
  return NULL;

 oldcontext = CurrentMemoryContext;
 oldowner = CurrentResourceOwner;

 PLy_spi_subtransaction_begin(oldcontext, oldowner);

 PG_TRY();
 {
  SPI_cursor_fetch(portal, true, count);

  Py_DECREF(ret->status);
  ret->status = PyLong_FromLong(SPI_OK_FETCH);

  Py_DECREF(ret->nrows);
  ret->nrows = PyLong_FromUnsignedLongLong(SPI_processed);

  if (SPI_processed != 0)
  {
   uint64  i;

   /*
    * PyList_New() and PyList_SetItem() use Py_ssize_t for list size
    * and list indices; so we cannot support a result larger than
    * PY_SSIZE_T_MAX.
 */

   if (SPI_processed > (uint64) PY_SSIZE_T_MAX)
    ereport(ERROR,
      (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
       errmsg("query result has too many rows to fit in a Python list")));

   Py_DECREF(ret->rows);
   ret->rows = PyList_New(SPI_processed);
   if (!ret->rows)
   {
    Py_DECREF(ret);
    ret = NULL;
   }
   else
   {
    PLy_input_setup_tuple(&cursor->result, SPI_tuptable->tupdesc,
           exec_ctx->curr_proc);

    for (i = 0; i < SPI_processed; i++)
    {
     PyObject   *row = PLy_input_from_tuple(&cursor->result,
                 SPI_tuptable->vals[i],
                 SPI_tuptable->tupdesc,
                 true);

     PyList_SetItem(ret->rows, i, row);
    }
   }
  }

  SPI_freetuptable(SPI_tuptable);

  PLy_spi_subtransaction_commit(oldcontext, oldowner);
 }
 PG_CATCH();
 {
  PLy_spi_subtransaction_abort(oldcontext, oldowner);
  return NULL;
 }
 PG_END_TRY();

 return (PyObject *) ret;
}

static PyObject *
PLy_cursor_close(PyObject *self, PyObject *unused)
{
 PLyCursorObject *cursor = (PLyCursorObject *) self;

 if (!cursor->closed)
 {
  Portal  portal = GetPortalByName(cursor->portalname);

  if (!PortalIsValid(portal))
  {
   PLy_exception_set(PyExc_ValueError,
         "closing a cursor in an aborted subtransaction");
   return NULL;
  }

  UnpinPortal(portal);
  SPI_cursor_close(portal);
  cursor->closed = true;
 }

 Py_RETURN_NONE;
}

Messung V0.5 in Prozent
C=99 H=97 G=97

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-08-05) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002