Skip to content

Commit

Permalink
Fix multiple calls of getresult() after send_query()
Browse files Browse the repository at this point in the history
  • Loading branch information
Cito committed Aug 26, 2023
1 parent 8a358e1 commit 53e8f10
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/contents/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Version 5.2.5 (to be released)
- generated columns can be requested with the `get_generated()` method
- generated columns are ignored by the insert, update and upsert method
- Avoid internal query and error when casting the `sql_identifier` type (#82)
- Fix issue with multiple calls of `getresult()` after `send_query()` (#80)

Version 5.2.4 (2022-03-26)
--------------------------
Expand Down
13 changes: 9 additions & 4 deletions pgquery.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ _get_async_result(queryObject *self, int keep) {
Py_END_ALLOW_THREADS
if (!self->result) {
/* end of result set, return None */
Py_DECREF(self->pgcnx);
self->pgcnx = NULL;
self->max_row = 0;
self->num_fields = 0;
self->col_types = NULL;
Py_INCREF(Py_None);
return Py_None;
}
Expand All @@ -161,7 +162,7 @@ _get_async_result(queryObject *self, int keep) {
}
}
else if (result == Py_None) {
/* It's would be confusing to return None here because the
/* It would be confusing to return None here because the
caller has to call again until we return None. We can't
just consume that final None because we don't know if there
are additional statements following this one, so we return
Expand All @@ -180,7 +181,12 @@ _get_async_result(queryObject *self, int keep) {
Py_DECREF(self);
return NULL;
}
} else if (self->async == 2 &&
!self->max_row && !self->num_fields && !self->col_types) {
Py_INCREF(Py_None);
return Py_None;
}

/* return the query object itself as sentinel for a normal query result */
return (PyObject *)self;
}
Expand Down Expand Up @@ -722,7 +728,6 @@ query_namedresult(queryObject *self, PyObject *noargs)
}

if ((res_list = _get_async_result(self, 1)) == (PyObject *)self) {

res = PyObject_CallFunction(namediter, "(O)", self);
if (!res) return NULL;
if (PyList_Check(res)) return res;
Expand Down
11 changes: 11 additions & 0 deletions tests/test_classic_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,17 @@ def testNamedresultAsync(self):
self.assertEqual(v._fields, ('alias0',))
self.assertEqual(v.alias0, 0)
self.assertIsNone(query.namedresult())
self.assertIsNone(query.namedresult())

def testListFieldsAfterSecondGetResultAsync(self):
q = "select 1 as one"
query = self.c.send_query(q)
self.assertEqual(query.getresult(), [(1,)])
self.assertEqual(query.listfields(), ('one',))
self.assertIsNone(query.getresult())
self.assertEqual(query.listfields(), ())
self.assertIsNone(query.getresult())
self.assertEqual(query.listfields(), ())

def testGet3Cols(self):
q = "select 1,2,3"
Expand Down
17 changes: 17 additions & 0 deletions tests/test_classic_dbwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,23 @@ def testDeleteDb(self):
self.assertRaises(pg.InternalError, db.close)
del db

def testAsyncQueryBeforeDeletion(self):
db = DB()
query = db.send_query('select 1')
self.assertEqual(query.getresult(), [(1,)])
self.assertIsNone(query.getresult())
self.assertIsNone(query.getresult())
del db
gc.collect()

def testAsyncQueryAfterDeletion(self):
db = DB()
query = db.send_query('select 1')
del db
gc.collect()
self.assertIsNone(query.getresult())
self.assertIsNone(query.getresult())


class TestDBClassBasic(unittest.TestCase):
"""Test existence of the DB class wrapped pg connection methods."""
Expand Down

0 comments on commit 53e8f10

Please sign in to comment.