Subject Re: [firebird-python] FDB Blocking Cursor
Author Pavel Cisar
Hi,

You're right, fetch should report correct error for statements that
doesn't return any result. However, your proposed fix is not correct.

Bug logged (PYFB-35), fixed and fix & test committed.

best regards
Pavel Cisar
IBPhoenix

Dne 6.5.2013 16:55, josef_gschwendtner napsal(a):
>
> We depend on a third party framework which uses one Cursor Instance for
> the execution of many queries. There are some select queries and also
> ddl statements which get executed with one Cursor instance.
>
> After each execution of a statement the fetch method gets called. Also
> for the ddl statements which produces no result. But in fdb this leads
> to an exception "WindowsError: exception: access violation reading
> 0x0000000000000000". After this exception the cursor is no longer
> usable. The next call of cur.execute() with a select statement blocks
> and never returns.
>
> This situation can be simulated with the following script. Instead of a
> ddl statement it is also possible to use an update statement.
>
>
>
> import fdb
>
> import traceback
>
>
>
>
>
> def execute(cur, stmt, parameters = None):
>
> print "-----------------------------------"
>
> print "Execute ", stmt
>
> cur.execute(stmt, parameters)
>
> try:
>
> for row in cur.fetchall():
>
> print row
>
> except Exception, e:
>
> print traceback.format_exc()
>
>
>
>
>
> def main():
>
> con = fdb.connect(dsn='localhost/3050:employee', user='sysdba',
> password='masterkey')
>
> cur = con.cursor()
>
>
>
>
>
> execute(cur, "select * from COUNTRY")
>
> #execute(cur, "UPDATE COUNTRY SET CURRENCY = 'Euro' where COUNTRY =
> 'Germany'")
>
> execute(cur, "CREATE SEQUENCE TEST_SEQ_1")
>
> execute(cur, "select * from COUNTRY")
>
>
>
> con.commit()
>
> con.close()
>
> print "Finished"
>
>
>
> main()
>
>
>
>
>
>
>
> We got the following output:
>
>
>
> -----------------------------------
>
> Execute select * from COUNTRY
>
> ('USA', 'Dollar')
>
> ('England', 'Pound')
>
> ('Canada', 'CdnDlr')
>
> ('Switzerland', 'SFranc')
>
> ('Japan', 'Yen')
>
> ('Italy', 'Lira')
>
> ('France', 'FFranc')
>
> ('Germany', 'Euro')
>
> ('Australia', 'ADollar')
>
> ('Hong Kong', 'HKDollar')
>
> ('Netherlands', 'Guilder')
>
> ('Belgium', 'BFranc')
>
> ('Austria', 'Schilling')
>
> ('Fiji', 'FDollar')
>
> -----------------------------------
>
> Execute CREATE SEQUENCE TEST_SEQ_1
>
> Traceback (most recent call last):
>
> File "C:\Development\Workspaces\PySnippets\fdb_fetch_problem.py", line
> 10, in execute
>
> for row in cur.fetchall():
>
> File
> "C:\Development\VirtualEnvs\web\lib\site-packages\fdb-1.1-py2.7.egg\fdb\\
> fbcore.py", line 3188, in fetchall
>
> return [row for row in self]
>
> File
> "C:\Development\VirtualEnvs\web\lib\site-packages\fdb-1.1-py2.7.egg\fdb\\
> fbcore.py", line 2951, in next
>
> row = self.fetchone()
>
> File
> "C:\Development\VirtualEnvs\web\lib\site-packages\fdb-1.1-py2.7.egg\fdb\\
> fbcore.py", line 3148, in fetchone
>
> return self._ps._fetchone()
>
> File
> "C:\Development\VirtualEnvs\web\lib\site-packages\fdb-1.1-py2.7.egg\fdb\\
> fbcore.py", line 2820, in _fetchone
>
> ctypes.cast(ctypes.pointer(self.out_sqlda), XSQLDA_PTR))
>
> WindowsError: exception: access violation reading 0x0000000000000000
>
>
>
> -----------------------------------
>
> Execute select * from COUNTRY
>
>
>
> The execution of the second select statement never returns. The
> application is still running.
>
>
>
> We think that a call to fetch after a sql statement without a result
> should not lead to an access violation.
>
> The same test with kinterbasdb leads to an exception like this:
>
>
>
> Error (0L, 'Attempt to fetch row of results after statement that does
> not produce result set. That statement was: CREATE SEQUENCE
> TEST_SEQ_1')
>
>
>
> After this exception the cursor from kinterbasdb is still usable.
>
>
>
> This behavior seems to be conform to PEP 249 -- Python Database API
> Specification v2.0
>
>
>
> From: http://www.python.org/dev/peps/pep-0249/#id19
> <http://www.python.org/dev/peps/pep-0249/#id19>
>
>
>
> .fetchone <http://www.python.org/dev/peps/pep-0249/#fetchone> ()
>
> Fetch the next row of a query result set, returning a single sequence,
> or None when no more data is available. [6]
> <http://www.python.org/dev/peps/pep-0249/#id45>
>
> An Error <http://www.python.org/dev/peps/pep-0249/#error> (or subclass)
> exception is raised if the previous call to .execute*()
> <http://www.python.org/dev/peps/pep-0249/#id14> did not produce any
> result set or no call was issued yet.
>
>
>
> One solution could be, that inside the fetchone operation of the Cursor
> is a check like this:
>
> if not self._ps.statement_type in [isc_info_sql_stmt_select,
> isc_info_sql_stmt_select_for_upd,
>
>
> isc_info_sql_stmt_exec_procedure]:
>
> raise Database.Error("Attempt to fetch row of results after
> statement that does not
> produce result set.")
>
>
> We found a similar check inside the C source of kinterbasdb (see
> function *_Cursor_fetchtuple from
> http://python-kinterbasdb.sourcearchive.com/documentation/3.2/__kicore__\
> cursor_8c-source.html
> <http://python-kinterbasdb.sourcearchive.com/documentation/3.2/__kicore_\
> _cursor_8c-source.html> ).
> Is it possible that a patch like this could be integrated to fdb?
>
> Thank you,
>
> Josef
>
>