diff -ur psycopg2-2.4.5.orig/psycopg/connection_type.c psycopg2-2.4.5/psycopg/connection_type.c --- psycopg2-2.4.5.orig/psycopg/connection_type.c 2012-03-28 16:09:15.000000000 -0500 +++ psycopg2-2.4.5/psycopg/connection_type.c 2012-04-13 12:33:46.217028844 -0500 @@ -42,7 +42,7 @@ /* cursor method - allocate a new cursor */ #define psyco_conn_cursor_doc \ -"cursor(name=None, cursor_factory=extensions.cursor, withhold=None) -- new cursor\n\n" \ +"cursor(name=None, cursor_factory=extensions.cursor, withhold=None, scrollable=False) -- new cursor\n\n" \ "Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n" \ "create non-standard cursors by passing a class different from the\n" \ "default. Note that the new class *should* be a sub-class of\n" \ @@ -53,12 +53,12 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds) { const char *name = NULL; - PyObject *obj, *factory = NULL, *withhold = NULL; + PyObject *obj, *factory = NULL, *withhold = NULL, *scrollable = NULL; - static char *kwlist[] = {"name", "cursor_factory", "withhold", NULL}; + static char *kwlist[] = {"name", "cursor_factory", "withhold", "scrollable", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sOO", kwlist, - &name, &factory, &withhold)) { + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sOOO", kwlist, + &name, &factory, &withhold, &scrollable)) { return NULL; } @@ -69,7 +69,15 @@ return NULL; } } - + + if (scrollable != NULL) { + if (PyObject_IsTrue(scrollable) && name == NULL) { + 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 && @@ -103,10 +111,13 @@ Py_DECREF(obj); return NULL; } - + if (withhold != NULL && PyObject_IsTrue(withhold)) ((cursorObject*)obj)->withhold = 1; + if (scrollable != NULL && 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 -ur psycopg2-2.4.5.orig/psycopg/cursor.h psycopg2-2.4.5/psycopg/cursor.h --- psycopg2-2.4.5.orig/psycopg/cursor.h 2012-03-28 16:09:15.000000000 -0500 +++ psycopg2-2.4.5/psycopg/cursor.h 2012-04-13 12:28:29.293024091 -0500 @@ -43,6 +43,7 @@ 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; long int rowcount; /* number of rows affected by last execute */ long int columns; /* number of columns fetched from the db */ diff -ur psycopg2-2.4.5.orig/psycopg/cursor_type.c psycopg2-2.4.5/psycopg/cursor_type.c --- psycopg2-2.4.5.orig/psycopg/cursor_type.c 2012-03-28 16:09:15.000000000 -0500 +++ psycopg2-2.4.5/psycopg/cursor_type.c 2012-04-13 12:30:00.537025458 -0500 @@ -403,8 +403,9 @@ 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 @@ 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 @@ "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 @@ (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 @@ self->closed = 0; self->withhold = 0; + self->scrollable = 0; self->mark = conn->mark; self->pgres = NULL; self->notuples = 1;