Subject | Re: [firebird-python] FDB Blocking Cursor |
---|---|
Author | Pavel Cisar |
Post date | 2013-05-07T11:07:29Z |
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):
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
>
>