Skip to content

Commit 406c557

Browse files
author
James William Pye
committed
Raise Error when operations are performed on closed cursors.
spec says so, and the recent portal change was causing a failure on close, so wrap it up with better spec compliance yay
1 parent 48ddb2f commit 406c557

2 files changed

Lines changed: 49 additions & 8 deletions

File tree

postgresql/driver/dbapi20.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,19 @@ def __init__(self, C):
144144
def _portal():
145145
def fget(self):
146146
if self.__portals is None:
147-
raise Error("access on closed cursor")
147+
raise Error("cursor is closed",
148+
source = 'CLIENT', creator = self.database
149+
)
148150
try:
149151
p = self.__portals[0]
150152
except IndexError:
151153
raise InterfaceError("no portal on stack")
152154
return p
153155
def fdel(self):
156+
if self.__portals is None:
157+
raise Error("cursor is closed",
158+
source = 'CLIENT', creator = self.database
159+
)
154160
try:
155161
del self.__portals[0]
156162
except IndexError:
@@ -159,15 +165,23 @@ def fdel(self):
159165
_portal = property(**_portal())
160166

161167
def setinputsizes(self, sizes):
162-
pass
168+
if self.__portals is None:
169+
raise Error("cursor is closed",
170+
source = 'CLIENT', creator = self.database)
163171

164172
def setoutputsize(self, sizes, columns = None):
165-
pass
173+
if self.__portals is None:
174+
raise Error("cursor is closed",
175+
source = 'CLIENT', creator = self.database)
166176

167177
def callproc(self, proname, args):
178+
if self.__portals is None:
179+
raise Error("cursor is closed",
180+
source = 'CLIENT', creator = self.database)
181+
168182
p = self.database.prepare("SELECT %s(%s)" %(
169183
proname, ','.join([
170-
'$%d' %(x,) for x in range(1, len(args) + 1)
184+
'$' + str(x) for x in range(1, len(args) + 1)
171185
])
172186
))
173187
self.__portals.insert(0, Portal(p.chunks(*args)))
@@ -245,6 +259,10 @@ def _convert_query(self, string):
245259
return (pg_str.unsplit(rparts) if rparts else string, transformer, count)
246260

247261
def execute(self, statement, parameters = ()):
262+
if self.__portals is None:
263+
raise Error("cursor is closed",
264+
source = 'CLIENT', creator = self.database)
265+
248266
sql, pxf, nparams = self._convert_query(statement)
249267
if nparams != -1 and len(parameters) != nparams:
250268
raise TypeError(
@@ -274,6 +292,10 @@ def execute(self, statement, parameters = ()):
274292
return self
275293

276294
def executemany(self, statement, parameters):
295+
if self.__portals is None:
296+
raise Error("cursor is closed",
297+
source = 'CLIENT', creator = self.database)
298+
277299
sql, pxf, nparams = self._convert_query(statement)
278300
ps = self.database.prepare(sql)
279301
if ps._input is not None:
@@ -284,11 +306,11 @@ def executemany(self, statement, parameters):
284306
return self
285307

286308
def close(self):
309+
if self.__portals is None:
310+
raise Error("cursor is closed",
311+
source = 'CLIENT', creator = self.database)
287312
self.description = None
288-
ps = self.__portals
289-
if self.__portals is not None:
290-
self.__portals = None
291-
for p in ps: p.close()
313+
self.__portals = None
292314

293315
class Connection(Connection):
294316
"""

postgresql/test/test_dbapi20.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,25 @@ def test_close(self):
342342
# connection.close should raise an Error if called more than once
343343
self.assertRaises(self.driver.Error,con.close)
344344

345+
def test_cursor_close(self):
346+
con = self._connect()
347+
try:
348+
cur = con.cursor()
349+
cur.close()
350+
# cursor.execute should raise an Error if called after cursor.close
351+
# closed
352+
self.assertRaises(self.driver.Error,self.executeDDL1,cur)
353+
# cursor.executemany should raise an Error if called after connection'
354+
# closed.'
355+
self.assertRaises(self.driver.Error,cur.executemany,'foo', [])
356+
357+
self.assertRaises(self.driver.Error,cur.callproc,'generate_series', [1, 10])
358+
359+
# cursor.close should raise an Error if called more than once
360+
self.assertRaises(self.driver.Error,cur.close)
361+
finally:
362+
con.close()
363+
345364
def test_execute(self):
346365
con = self._connect()
347366
try:

0 commit comments

Comments
 (0)