Added scrollable cursor implementation

Patch provided by Jon Nelson (ticket #108).
This commit is contained in:
Daniele Varrazzo 2012-08-15 00:30:54 +01:00
parent 91c2ff9296
commit fa4994e471
3 changed files with 59 additions and 8 deletions

View File

@ -56,11 +56,14 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
PyObject *name = Py_None; PyObject *name = Py_None;
PyObject *factory = (PyObject *)&cursorType; PyObject *factory = (PyObject *)&cursorType;
PyObject *withhold = Py_False; 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, if (!PyArg_ParseTupleAndKeywords(
&name, &factory, &withhold)) { args, kwargs, "|OOOO", kwlist,
&name, &factory, &withhold, &scrollable)) {
return NULL; return NULL;
} }
@ -70,6 +73,12 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
return NULL; 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); EXC_IF_CONN_CLOSED(self);
if (self->status != CONN_STATUS_READY && if (self->status != CONN_STATUS_READY &&
@ -104,6 +113,9 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
if (PyObject_IsTrue(withhold)) if (PyObject_IsTrue(withhold))
((cursorObject*)obj)->withhold = 1; ((cursorObject*)obj)->withhold = 1;
if (PyObject_IsTrue(scrollable))
((cursorObject*)obj)->scrollable = 1;
Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = " Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = "
FORMAT_CODE_PY_SSIZE_T, FORMAT_CODE_PY_SSIZE_T,
obj, Py_REFCNT(obj) obj, Py_REFCNT(obj)

View File

@ -43,6 +43,7 @@ struct cursorObject {
int closed:1; /* 1 if the cursor is closed */ int closed:1; /* 1 if the cursor is closed */
int notuples:1; /* 1 if the command was not a SELECT query */ 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 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 rowcount; /* number of rows affected by last execute */
long int columns; /* number of columns fetched from the db */ long int columns; /* number of columns fetched from the db */

View File

@ -403,8 +403,9 @@ _psyco_curs_execute(cursorObject *self,
if (self->name != NULL) { if (self->name != NULL) {
self->query = Bytes_FromFormat( self->query = Bytes_FromFormat(
"DECLARE \"%s\" CURSOR %s HOLD FOR %s", "DECLARE \"%s\" %sSCROLL CURSOR %s HOLD FOR %s",
self->name, self->name,
self->scrollable ? "":"NO ",
self->withhold ? "WITH" : "WITHOUT", self->withhold ? "WITH" : "WITHOUT",
Bytes_AS_STRING(fquery)); Bytes_AS_STRING(fquery));
Py_DECREF(fquery); Py_DECREF(fquery);
@ -416,8 +417,9 @@ _psyco_curs_execute(cursorObject *self,
else { else {
if (self->name != NULL) { if (self->name != NULL) {
self->query = Bytes_FromFormat( self->query = Bytes_FromFormat(
"DECLARE \"%s\" CURSOR %s HOLD FOR %s", "DECLARE \"%s\" %sSCROLL CURSOR %s HOLD FOR %s",
self->name, self->name,
self->scrollable ? "":"NO ",
self->withhold ? "WITH" : "WITHOUT", self->withhold ? "WITH" : "WITHOUT",
Bytes_AS_STRING(operation)); Bytes_AS_STRING(operation));
} }
@ -1584,6 +1586,37 @@ psyco_curs_withhold_set(cursorObject *self, PyObject *pyvalue)
return 0; 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;
}
#endif #endif
@ -1710,6 +1743,10 @@ static struct PyGetSetDef cursorObject_getsets[] = {
(getter)psyco_curs_withhold_get, (getter)psyco_curs_withhold_get,
(setter)psyco_curs_withhold_set, (setter)psyco_curs_withhold_set,
psyco_curs_withhold_doc, NULL }, psyco_curs_withhold_doc, NULL },
{ "scrollable",
(getter)psyco_curs_scrollable_get,
(setter)psyco_curs_scrollable_set,
psyco_curs_scrollable_doc, NULL },
#endif #endif
{NULL} {NULL}
}; };
@ -1740,6 +1777,7 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name)
self->closed = 0; self->closed = 0;
self->withhold = 0; self->withhold = 0;
self->scrollable = 0;
self->mark = conn->mark; self->mark = conn->mark;
self->pgres = NULL; self->pgres = NULL;
self->notuples = 1; self->notuples = 1;