Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

plpy_cursorobject.c File Reference

#include "postgres.h"
#include "access/xact.h"
#include "mb/pg_wchar.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 PyObject * PLy_cursor_plan (PyObject *ob, PyObject *args)
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)

Variables

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

Function Documentation

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

Definition at line 84 of file plpy_cursorobject.c.

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

{
    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_close ( PyObject *  self,
PyObject *  unused 
) [static]

Definition at line 475 of file plpy_cursorobject.c.

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

{
    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;
        }

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

    Py_INCREF(Py_None);
    return Py_None;
}

static void PLy_cursor_dealloc ( PyObject *  arg  )  [static]
static PyObject * PLy_cursor_fetch ( PyObject *  self,
PyObject *  args 
) [static]

Definition at line 391 of file plpy_cursorobject.c.

References PLyCursorObject::closed, CurrentMemoryContext, CurrentResourceOwner, GetPortalByName(), i, PLyTypeInfo::is_rowtype, PLyResultObject::nrows, NULL, PG_CATCH, PG_END_TRY, PG_TRY, PLy_exception_set(), PLy_input_tuple_funcs(), PLy_result_new(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyDict_FromTuple(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, PLyResultObject::rows, SPI_cursor_fetch(), SPI_freetuptable(), SPI_OK_FETCH, SPI_processed, SPI_tuptable, PLyResultObject::status, SPITupleTable::tupdesc, and SPITupleTable::vals.

{
    PLyCursorObject *cursor;
    int         count;
    PLyResultObject *ret;
    volatile MemoryContext oldcontext;
    volatile ResourceOwner oldowner;
    Portal      portal;

    if (!PyArg_ParseTuple(args, "i", &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);

        if (cursor->result.is_rowtype != 1)
            PLy_input_tuple_funcs(&cursor->result, SPI_tuptable->tupdesc);

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

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

        if (SPI_processed != 0)
        {
            int         i;

            Py_DECREF(ret->rows);
            ret->rows = PyList_New(SPI_processed);

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

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

        SPI_freetuptable(SPI_tuptable);

        PLy_spi_subtransaction_commit(oldcontext, oldowner);
    }
    PG_CATCH();
    {
        SPI_freetuptable(SPI_tuptable);

        PLy_spi_subtransaction_abort(oldcontext, oldowner);
        return NULL;
    }
    PG_END_TRY();

    return (PyObject *) ret;
}

void PLy_cursor_init_type ( void   ) 

Definition at line 77 of file plpy_cursorobject.c.

References elog, ERROR, and PLy_CursorType.

Referenced by PLy_init_plpy().

{
    if (PyType_Ready(&PLy_CursorType) < 0)
        elog(ERROR, "could not initialize PLy_CursorType");
}

static PyObject * PLy_cursor_iternext ( PyObject *  self  )  [static]

Definition at line 328 of file plpy_cursorobject.c.

References PLyCursorObject::closed, CurrentMemoryContext, CurrentResourceOwner, GetPortalByName(), PLyTypeInfo::is_rowtype, PG_CATCH, PG_END_TRY, PG_TRY, PLy_exception_set(), PLy_input_tuple_funcs(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLyDict_FromTuple(), PortalIsValid, PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_fetch(), SPI_freetuptable(), SPI_processed, SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.

{
    PLyCursorObject *cursor;
    PyObject   *ret;
    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, true, 1);
        if (SPI_processed == 0)
        {
            PyErr_SetNone(PyExc_StopIteration);
            ret = NULL;
        }
        else
        {
            if (cursor->result.is_rowtype != 1)
                PLy_input_tuple_funcs(&cursor->result, SPI_tuptable->tupdesc);

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

        SPI_freetuptable(SPI_tuptable);

        PLy_spi_subtransaction_commit(oldcontext, oldowner);
    }
    PG_CATCH();
    {
        SPI_freetuptable(SPI_tuptable);

        PLy_spi_subtransaction_abort(oldcontext, oldowner);
        return NULL;
    }
    PG_END_TRY();

    return ret;
}

static PyObject * PLy_cursor_plan ( PyObject *  ob,
PyObject *  args 
) [static]

Definition at line 158 of file plpy_cursorobject.c.

References PLyPlanObject::args, Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, PLyTypeOutput::d, DatumGetPointer, elog, ERROR, PLyProcedure::fn_readonly, PLyObToDatum::func, i, InputFunctionCall(), PortalData::name, PLyPlanObject::nargs, NULL, PLyTypeInfo::out, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PLyPlanObject::plan, PLy_current_execution_context(), PLy_CursorType, PLy_elog(), PLy_exception_set(), PLy_exception_set_plural(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_strdup(), PLy_typeinfo_init(), PointerGetDatum, PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_open(), SPI_result, SPI_result_code_string(), PLyObToDatum::typbyval, PLyObToDatum::typfunc, PLyObToDatum::typioparam, and PLyPlanObject::values.

Referenced by PLy_cursor().

{
    PLyCursorObject *cursor;
    volatile int nargs;
    int         i;
    PLyPlanObject *plan;
    volatile MemoryContext oldcontext;
    volatile ResourceOwner oldowner;

    if (args)
    {
        if (!PySequence_Check(args) || PyString_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 = PyString_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;
    cursor->portalname = NULL;
    cursor->closed = false;
    PLy_typeinfo_init(&cursor->result);

    oldcontext = CurrentMemoryContext;
    oldowner = CurrentResourceOwner;

    PLy_spi_subtransaction_begin(oldcontext, oldowner);

    PG_TRY();
    {
        PLyExecutionContext *exec_ctx = PLy_current_execution_context();
        Portal      portal;
        char       *volatile nulls;
        volatile int j;

        if (nargs > 0)
            nulls = palloc(nargs * sizeof(char));
        else
            nulls = NULL;

        for (j = 0; j < nargs; j++)
        {
            PyObject   *elem;

            elem = PySequence_GetItem(args, j);
            if (elem != Py_None)
            {
                PG_TRY();
                {
                    plan->values[j] =
                        plan->args[j].out.d.func(&(plan->args[j].out.d),
                                                 -1,
                                                 elem);
                }
                PG_CATCH();
                {
                    Py_DECREF(elem);
                    PG_RE_THROW();
                }
                PG_END_TRY();

                Py_DECREF(elem);
                nulls[j] = ' ';
            }
            else
            {
                Py_DECREF(elem);
                plan->values[j] =
                    InputFunctionCall(&(plan->args[j].out.d.typfunc),
                                      NULL,
                                      plan->args[j].out.d.typioparam,
                                      -1);
                nulls[j] = 'n';
            }
        }

        portal = SPI_cursor_open(NULL, plan->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 = PLy_strdup(portal->name);

        PLy_spi_subtransaction_commit(oldcontext, oldowner);
    }
    PG_CATCH();
    {
        int         k;

        /* cleanup plan->values array */
        for (k = 0; k < nargs; k++)
        {
            if (!plan->args[k].out.d.typbyval &&
                (plan->values[k] != PointerGetDatum(NULL)))
            {
                pfree(DatumGetPointer(plan->values[k]));
                plan->values[k] = PointerGetDatum(NULL);
            }
        }

        Py_DECREF(cursor);

        PLy_spi_subtransaction_abort(oldcontext, oldowner);
        return NULL;
    }
    PG_END_TRY();

    for (i = 0; i < nargs; i++)
    {
        if (!plan->args[i].out.d.typbyval &&
            (plan->values[i] != PointerGetDatum(NULL)))
        {
            pfree(DatumGetPointer(plan->values[i]));
            plan->values[i] = PointerGetDatum(NULL);
        }
    }

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

static PyObject * PLy_cursor_query ( const char *  query  )  [static]

Definition at line 104 of file plpy_cursorobject.c.

References Assert, PLyCursorObject::closed, PLyExecutionContext::curr_proc, CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, PLyProcedure::fn_readonly, PortalData::name, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), PLy_current_execution_context(), PLy_CursorType, PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_begin(), PLy_spi_subtransaction_commit(), PLy_strdup(), PLy_typeinfo_init(), PLyCursorObject::portalname, PLyCursorObject::result, SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_result, and SPI_result_code_string().

Referenced by PLy_cursor().

{
    PLyCursorObject *cursor;
    volatile MemoryContext oldcontext;
    volatile ResourceOwner oldowner;

    if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL)
        return NULL;
    cursor->portalname = NULL;
    cursor->closed = false;
    PLy_typeinfo_init(&cursor->result);

    oldcontext = CurrentMemoryContext;
    oldowner = CurrentResourceOwner;

    PLy_spi_subtransaction_begin(oldcontext, oldowner);

    PG_TRY();
    {
        PLyExecutionContext *exec_ctx = PLy_current_execution_context();
        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 = PLy_strdup(portal->name);

        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;
}


Variable Documentation

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

Definition at line 31 of file plpy_cursorobject.c.

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}
}

Definition at line 35 of file plpy_cursorobject.c.

PyTypeObject PLy_CursorType [static]

Definition at line 41 of file plpy_cursorobject.c.

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