mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-07 21:00:33 +03:00
First try at curs.withhold implementation
This commit is contained in:
parent
cb1d163f4f
commit
2f6336ea78
|
@ -42,6 +42,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 */
|
||||||
|
|
||||||
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 */
|
||||||
|
@ -99,7 +100,7 @@ if ((self)->notuples && (self)->name == NULL) { \
|
||||||
return NULL; }
|
return NULL; }
|
||||||
|
|
||||||
#define EXC_IF_NO_MARK(self) \
|
#define EXC_IF_NO_MARK(self) \
|
||||||
if ((self)->mark != (self)->conn->mark) { \
|
if ((self)->mark != (self)->conn->mark && (self)->withhold == 0) { \
|
||||||
PyErr_SetString(ProgrammingError, "named cursor isn't valid anymore"); \
|
PyErr_SetString(ProgrammingError, "named cursor isn't valid anymore"); \
|
||||||
return NULL; }
|
return NULL; }
|
||||||
|
|
||||||
|
|
|
@ -391,8 +391,10 @@ _psyco_curs_execute(cursorObject *self,
|
||||||
|
|
||||||
if (self->name != NULL) {
|
if (self->name != NULL) {
|
||||||
self->query = Bytes_FromFormat(
|
self->query = Bytes_FromFormat(
|
||||||
"DECLARE \"%s\" CURSOR WITHOUT HOLD FOR %s",
|
"DECLARE \"%s\" CURSOR %s HOLD FOR %s",
|
||||||
self->name, Bytes_AS_STRING(fquery));
|
self->name,
|
||||||
|
self->withhold ? "WITH" : "WITHOUT",
|
||||||
|
Bytes_AS_STRING(fquery));
|
||||||
Py_DECREF(fquery);
|
Py_DECREF(fquery);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -402,8 +404,10 @@ _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 WITHOUT HOLD FOR %s",
|
"DECLARE \"%s\" CURSOR %s HOLD FOR %s",
|
||||||
self->name, Bytes_AS_STRING(operation));
|
self->name,
|
||||||
|
self->withhold ? "WITH" : "WITHOUT",
|
||||||
|
Bytes_AS_STRING(operation));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Transfer reference ownership of the str in operation to
|
/* Transfer reference ownership of the str in operation to
|
||||||
|
@ -461,11 +465,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
"can't use a named cursor outside of transactions", NULL, NULL);
|
"can't use a named cursor outside of transactions", NULL, NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (self->conn->mark != self->mark) {
|
EXC_IF_NO_MARK(self);
|
||||||
psyco_set_error(ProgrammingError, self,
|
|
||||||
"named cursor isn't valid anymore", NULL, NULL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXC_IF_CURS_CLOSED(self);
|
EXC_IF_CURS_CLOSED(self);
|
||||||
|
@ -1519,7 +1519,7 @@ exit:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extension: closed - return true if cursor is closed*/
|
/* extension: closed - return true if cursor is closed */
|
||||||
|
|
||||||
#define psyco_curs_closed_doc \
|
#define psyco_curs_closed_doc \
|
||||||
"True if cursor is closed, False if cursor is open"
|
"True if cursor is closed, False if cursor is open"
|
||||||
|
@ -1535,6 +1535,39 @@ psyco_curs_get_closed(cursorObject *self, void *closure)
|
||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* extension: withhold - get or set "WITH HOLD" for named cursors */
|
||||||
|
|
||||||
|
#define psyco_curs_withhold_doc \
|
||||||
|
"Set or return cursor use of WITH HOLD"
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
psyco_curs_withhold_get(cursorObject *self)
|
||||||
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
ret = self->withhold ? Py_True : Py_False;
|
||||||
|
Py_INCREF(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
psyco_curs_withhold_set(cursorObject *self, PyObject *pyvalue)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (self->name == NULL) {
|
||||||
|
PyErr_SetString(ProgrammingError,
|
||||||
|
"trying to set .withhold on unnamed cursor");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value = PyObject_IsTrue(pyvalue)) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
self->withhold = value;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -1657,6 +1690,10 @@ static struct PyGetSetDef cursorObject_getsets[] = {
|
||||||
#ifdef PSYCOPG_EXTENSIONS
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
{ "closed", (getter)psyco_curs_get_closed, NULL,
|
{ "closed", (getter)psyco_curs_get_closed, NULL,
|
||||||
psyco_curs_closed_doc, NULL },
|
psyco_curs_closed_doc, NULL },
|
||||||
|
{ "withhold",
|
||||||
|
(getter)psyco_curs_withhold_get,
|
||||||
|
(setter)psyco_curs_withhold_set,
|
||||||
|
psyco_curs_withhold_doc, NULL },
|
||||||
#endif
|
#endif
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
@ -1686,6 +1723,7 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name)
|
||||||
self->conn = conn;
|
self->conn = conn;
|
||||||
|
|
||||||
self->closed = 0;
|
self->closed = 0;
|
||||||
|
self->withhold = 0;
|
||||||
self->mark = conn->mark;
|
self->mark = conn->mark;
|
||||||
self->pgres = NULL;
|
self->pgres = NULL;
|
||||||
self->notuples = 1;
|
self->notuples = 1;
|
||||||
|
|
|
@ -202,6 +202,9 @@
|
||||||
<None Include="tests\dbapi20_tpc.py" />
|
<None Include="tests\dbapi20_tpc.py" />
|
||||||
<None Include="tests\test_cursor.py" />
|
<None Include="tests\test_cursor.py" />
|
||||||
<None Include="NEWS" />
|
<None Include="NEWS" />
|
||||||
|
<None Include="tests\test_cancel.py" />
|
||||||
|
<None Include="tests\testconfig.py" />
|
||||||
|
<None Include="tests\testutils.py" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="psycopg\adapter_asis.c" />
|
<Compile Include="psycopg\adapter_asis.c" />
|
||||||
|
|
|
@ -158,6 +158,27 @@ class CursorTests(unittest.TestCase):
|
||||||
curs.execute("select data from invname order by data")
|
curs.execute("select data from invname order by data")
|
||||||
self.assertEqual(curs.fetchall(), [(10,), (20,), (30,)])
|
self.assertEqual(curs.fetchall(), [(10,), (20,), (30,)])
|
||||||
|
|
||||||
|
def test_withhold(self):
|
||||||
|
curs = self.conn.cursor()
|
||||||
|
curs.execute("drop table if exists withhold")
|
||||||
|
curs.execute("create table withhold (data int)")
|
||||||
|
for i in (10, 20, 30):
|
||||||
|
curs.execute("insert into withhold values (%s)", (i,))
|
||||||
|
curs.close()
|
||||||
|
|
||||||
|
curs = self.conn.cursor("W")
|
||||||
|
self.assertEqual(curs.withhold, False);
|
||||||
|
curs.withhold = True
|
||||||
|
self.assertEqual(curs.withhold, True);
|
||||||
|
curs.execute("select data from withhold order by data")
|
||||||
|
self.conn.commit()
|
||||||
|
self.assertEqual(curs.fetchall(), [(10,), (20,), (30,)])
|
||||||
|
|
||||||
|
curs = self.conn.cursor()
|
||||||
|
curs.execute("drop table withhold")
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
|
||||||
@skip_before_postgres(8, 2)
|
@skip_before_postgres(8, 2)
|
||||||
def test_iter_named_cursor_efficient(self):
|
def test_iter_named_cursor_efficient(self):
|
||||||
curs = self.conn.cursor('tmp')
|
curs = self.conn.cursor('tmp')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user