From c5722891f9da74a087f303fac984b58886f73459 Mon Sep 17 00:00:00 2001 From: pavel-zotov Date: Sat, 18 Jan 2025 18:21:45 +0300 Subject: [PATCH] Added/Updated tests\bugs\core_1315_test.py: 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 can raises when Python runs garbage collection. --- tests/bugs/core_1315_test.py | 57 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/tests/bugs/core_1315_test.py b/tests/bugs/core_1315_test.py index 7b547cc2..a1800765 100644 --- a/tests/bugs/core_1315_test.py +++ b/tests/bugs/core_1315_test.py @@ -6,9 +6,17 @@ ISSUE: 1734 TITLE: Data type unknown DESCRIPTION: JIRA: CORE-1315 -FBTEST: bugs.core_1315 +NOTES: + [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"). """ +from firebird.driver import DatabaseError + import pytest from firebird.qa import * @@ -16,26 +24,45 @@ db = db_factory() act = python_act('db') -expected_stdout = """COALESCE ------------ -2 +expected_stdout = """ + COALESCE + ----------- + 2 -COALESCE ------------ -1 + COALESCE + ----------- + 1 """ @pytest.mark.version('>=3') def test_1(act: Action, capsys): with act.db.connect() as con: - c = con.cursor() - statement = c.prepare('select coalesce(?,1) from RDB$DATABASE') - c.execute(statement,[2]) - act.print_data(c) - c.execute(statement,[None]) - act.print_data(c) + cur = con.cursor() + ps, rs = None, None + try: + ps = cur.prepare('select coalesce(?,1) from RDB$DATABASE') + + # ::: 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 + rs = cur.execute(ps,[2]) + act.print_data(rs) + + rs = cur.execute(ps,[None]) + act.print_data(rs) + + except DatabaseError as e: + print( e.__str__() ) + print(e.gds_codes) + finally: + if rs: + rs.close() # <<< EXPLICITLY CLOSING CURSOR RESULTS + if ps: + ps.free() + act.stdout = capsys.readouterr().out act.expected_stdout = expected_stdout assert act.clean_stdout == act.clean_expected_stdout - -