diff --git a/tests/bugs/core_2477_test.py b/tests/bugs/core_2477_test.py index ebaec7bc..adb14aad 100644 --- a/tests/bugs/core_2477_test.py +++ b/tests/bugs/core_2477_test.py @@ -21,20 +21,30 @@ DESCRIPTION: JIRA: CORE-2477 FBTEST: bugs.core_2477 NOTES: -[16.11.2021] pcisar + [16.11.2021] pcisar This test is too complicated and fragile, and it's IMHO not worth to be implemented -[24.07.2022] pzotov + + [24.07.2022] pzotov Test was totally re-implemented. No async call of ISQL, waiting/killing etc. Checked on Windows: 3.0.8.33535 (SS/CS), 4.0.1.2692 (SS/CS), 5.0.0.591 Checked on Linux: 4.0.1.2692 (SS/CS) - needed to increase number of rows to be sorted. + + [18.01.2025] pzotov + Resultset of cursor that executes using instance of selectable PreparedStatement must be stored + in some variable in order to have ability close it EXPLICITLY (before PS will be freed). + Otherwise access violation raises during Python GC and pytest hangs at final point (does not return control to OS). + This occurs at least for: Python 3.11.2 / pytest: 7.4.4 / firebird.driver: 1.10.6 / Firebird.Qa: 0.19.3 + The reason of that was explained by Vlad, 26.10.24 17:42 ("oddities when use instances of selective statements"). """ import subprocess from pathlib import Path +from firebird.driver import DatabaseError +import time + import pytest from firebird.qa import * -import time init_script = """ create or alter view v_mon as @@ -108,27 +118,47 @@ def test_1(act: Action, capsys): with act.db.connect() as con_worker: cur_worker = con_worker.cursor() - cur_wrk_ps = cur_worker.prepare(heavy_sql_sttm) + cur_wrk_ps, cur_wrk_rs = None, None - for m in ('beg','end'): - with act.db.connect() as con_monitor: - cur_monitor=con_monitor.cursor() - cur_monitor.execute('select * from v_gather_mon') - - for r in cur_monitor: - map_result[m] = (r[3], r[7]) # ('idle' | 'stalled', memo_used) + try: + cur_wrk_ps = cur_worker.prepare(heavy_sql_sttm) - assert map_result.get(m), f"No rows returned from v_gather_mon for m='{m}'" - - if m == 'beg': - cur_worker.execute(cur_wrk_ps) - for i in range(0, ROWS_TO_BE_SORTED): - r = cur_worker.fetchone() + for m in ('beg','end'): + with act.db.connect() as con_monitor: + cur_monitor=con_monitor.cursor() + cur_monitor.execute('select * from v_gather_mon') + + for r in cur_monitor: + map_result[m] = (r[3], r[7]) # ('idle' | 'stalled', memo_used) - # After this loop statement with huge sort will remain in stalled state - # (its mon$statements.mon$state must be 2). - # We can now gather mon$ info second time (in a NEW connection) - # and then evaluate DIFFERENCE. + assert map_result.get(m), f"No rows returned from v_gather_mon for m='{m}'" + + if m == 'beg': + + # ::: NB ::: 'ps' returns data, i.e. this is SELECTABLE expression. + # We have to store result of cur.execute() in order to + # close it explicitly. + # Otherwise AV can occur during Python garbage collection and this + # causes pytest to hang on its final point. + # Explained by hvlad, email 26.10.24 17:42 + + cur_wrk_rs = cur_worker.execute(cur_wrk_ps) + for i in range(0, ROWS_TO_BE_SORTED): + r = cur_worker.fetchone() + + # After this loop statement with huge sort will remain in stalled state + # (its mon$statements.mon$state must be 2). + # We can now gather mon$ info second time (in a NEW connection) + # and then evaluate DIFFERENCE. + + except DatabaseError as e: + print( e.__str__() ) + print(e.gds_codes) + finally: + if cur_wrk_rs: + cur_wrk_rs.close() # <<< EXPLICITLY CLOSING CURSOR RESULTS + if cur_wrk_ps: + cur_wrk_ps.free() #------------------------------------------------------------------------------------------