From fa4994e471c7487489ac7abb93bafb6f1fa507b6 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 15 Aug 2012 00:30:54 +0100 Subject: [PATCH] Added scrollable cursor implementation Patch provided by Jon Nelson (ticket #108). --- psycopg/connection_type.c | 18 ++++++++++++--- psycopg/cursor.h | 1 + psycopg/cursor_type.c | 48 +++++++++++++++++++++++++++++++++++---- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c index c4b88b3e..1b476c6c 100644 --- a/psycopg/connection_type.c +++ b/psycopg/connection_type.c @@ -56,11 +56,14 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs) PyObject *name = Py_None; PyObject *factory = (PyObject *)&cursorType; PyObject *withhold = Py_False; + PyObject *scrollable = Py_False; - static char *kwlist[] = {"name", "cursor_factory", "withhold", NULL}; + static char *kwlist[] = { + "name", "cursor_factory", "withhold", "scrollable", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO", kwlist, - &name, &factory, &withhold)) { + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OOOO", kwlist, + &name, &factory, &withhold, &scrollable)) { return NULL; } @@ -70,6 +73,12 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs) return NULL; } + if (PyObject_IsTrue(scrollable) && (name == Py_None)) { + PyErr_SetString(ProgrammingError, + "'scrollable=True can be specified only for named cursors"); + return NULL; + } + EXC_IF_CONN_CLOSED(self); if (self->status != CONN_STATUS_READY && @@ -104,6 +113,9 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs) if (PyObject_IsTrue(withhold)) ((cursorObject*)obj)->withhold = 1; + if (PyObject_IsTrue(scrollable)) + ((cursorObject*)obj)->scrollable = 1; + Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = " FORMAT_CODE_PY_SSIZE_T, obj, Py_REFCNT(obj) diff --git a/psycopg/cursor.h b/psycopg/cursor.h index 723bd170..e234f29c 100644 --- a/psycopg/cursor.h +++ b/psycopg/cursor.h @@ -43,6 +43,7 @@ struct cursorObject { int closed:1; /* 1 if the cursor is closed */ int notuples:1; /* 1 if the command was not a SELECT query */ int withhold:1; /* 1 if the cursor is named and uses WITH HOLD */ + int scrollable:1; /* 1 if the cursor is named as SCROLLABLE */ long int rowcount; /* number of rows affected by last execute */ long int columns; /* number of columns fetched from the db */ diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 2a653cf7..50fe8211 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -403,8 +403,9 @@ _psyco_curs_execute(cursorObject *self, if (self->name != NULL) { self->query = Bytes_FromFormat( - "DECLARE \"%s\" CURSOR %s HOLD FOR %s", + "DECLARE \"%s\" %sSCROLL CURSOR %s HOLD FOR %s", self->name, + self->scrollable ? "":"NO ", self->withhold ? "WITH" : "WITHOUT", Bytes_AS_STRING(fquery)); Py_DECREF(fquery); @@ -416,8 +417,9 @@ _psyco_curs_execute(cursorObject *self, else { if (self->name != NULL) { self->query = Bytes_FromFormat( - "DECLARE \"%s\" CURSOR %s HOLD FOR %s", + "DECLARE \"%s\" %sSCROLL CURSOR %s HOLD FOR %s", self->name, + self->scrollable ? "":"NO ", self->withhold ? "WITH" : "WITHOUT", Bytes_AS_STRING(operation)); } @@ -1575,12 +1577,43 @@ psyco_curs_withhold_set(cursorObject *self, PyObject *pyvalue) "trying to set .withhold on unnamed cursor"); return -1; } - - if ((value = PyObject_IsTrue(pyvalue)) == -1) + + if ((value = PyObject_IsTrue(pyvalue)) == -1) return -1; self->withhold = value; - + + return 0; +} + +#define psyco_curs_scrollable_doc \ +"Set or return cursor use of SCROLL" + +static PyObject * +psyco_curs_scrollable_get(cursorObject *self) +{ + PyObject *ret; + ret = self->scrollable ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +static int +psyco_curs_scrollable_set(cursorObject *self, PyObject *pyvalue) +{ + int value; + + if (self->name == NULL) { + PyErr_SetString(ProgrammingError, + "trying to set .scrollable on unnamed cursor"); + return -1; + } + + if ((value = PyObject_IsTrue(pyvalue)) == -1) + return -1; + + self->scrollable = value; + return 0; } @@ -1710,6 +1743,10 @@ static struct PyGetSetDef cursorObject_getsets[] = { (getter)psyco_curs_withhold_get, (setter)psyco_curs_withhold_set, psyco_curs_withhold_doc, NULL }, + { "scrollable", + (getter)psyco_curs_scrollable_get, + (setter)psyco_curs_scrollable_set, + psyco_curs_scrollable_doc, NULL }, #endif {NULL} }; @@ -1740,6 +1777,7 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name) self->closed = 0; self->withhold = 0; + self->scrollable = 0; self->mark = conn->mark; self->pgres = NULL; self->notuples = 1;