From: Greg W. <gwa...@py...> - 2006-07-06 10:02:56
|
On 22 June 2006, I said: > Back in May 2002, Ralph Heinkel reported a mysterious error, "This > routine cannot be called because another command structure has results > pending". Here's his post: > > http://www.object-craft.com.au/pipermail/python-sybase/2002-May/000034.html > > He posted a test program that reproduces the problem, and it still > reproduces perfectly for me. It appears that any error on a connection > renders that connection unusable, or at least un-commit()able and > un-rollback()able. I'm connecting to Sybase ASE 11.0.3.3 (using > libct.so and libcs.so supplied with the Sybase engine) and python-sybase > 0.37. I've done a bit more digging into this problem and discovered a crude workaround. All I have to do is add one line of code after my failed query but before closing the cursor: cur = db.cursor() try: # produce an error - THE TABLE 'DUMMY' DOES NOT EXIST cur.execute('select * from dummy') print "WTF?!? select should have failed!" except Sybase.Error, err: print "select failed as expected: %s" % err cur._fetcher._close() <--- CRUDE WORKAROUND cur.close() db.commit() That suggests to me that the bug lies in python-sybase rather than in my code or in ctlib. I think the bug is that Sybase.py assumes that self._fetcher = None is sufficient to close the fetcher object and release all of its resources, most importantly by calling ct_cancel() on the underlying ctlib command structure. Here's a narrow-minded patch that fixes the particular problem I'm seeing: --- Sybase.py.orig 2005-04-06 18:46:43.000000000 -0400 +++ Sybase.py.hacked 2006-07-05 12:41:55.000000000 -0400 @@ -735,10 +735,12 @@ def close(self): '''DB-API Cursor.close() ''' if self._closed: raise ProgrammingError('cursor is closed') + if self._fetcher: + self._fetcher._close() self._fetcher = None self._closed = 1 def execute(self, sql, params = {}): '''DB-API Cursor.execute() However, I suspect a more appropriate fix would be to factor out a _close_fetcher() method of Cursor: def _close_fetcher(self): if self._fetcher: self._fetcher._close() self._fetcher = None and replace every occurence of "self._fetcher = None" with "self._close_fetcher()". Does this sound close? If so, I'll happily provide a patch. Greg |