diff --git a/tests/bugs/core_5020_test.py b/tests/bugs/core_5020_test.py index 154befeb..8f1a84fd 100644 --- a/tests/bugs/core_5020_test.py +++ b/tests/bugs/core_5020_test.py @@ -5,16 +5,25 @@ ID: issue-5308 ISSUE: 5308 TITLE: Regression: ORDER BY clause on compound index may disable usage of other indices DESCRIPTION: + Plan in 3.0.0.32179 (before fix): PLAN (ZF ORDER IXA_FK__ID__KONT_ID) + Fixed in 3.0 since: http://sourceforge.net/p/firebird/code/62570 + Checked on 2.5.5.26952 - plans are the same now. JIRA: CORE-5020 FBTEST: bugs.core_5020 +NOTES: + [17.11.2024] pzotov + Re-implemented after https://github.com/FirebirdSQL/firebird/commit/26e64e9c08f635d55ac7a111469498b3f0c7fe81 + ( Cost-based decision between ORDER and SORT plans (#8316) ). + Execution plan was replaced with explained. Plans are splitted for versions up to 5.x and 6.x+. + Discussed with dimitr, letters 16.11.2024. + + Checked on 6.0.0.532; 5.0.2.1567; 4.0.6.3168; 3.0.13.33794. """ import pytest from firebird.qa import * -db = db_factory() - -test_script = """ +init_sql = """ recreate table zf( id integer not null primary key, kont_id integer not null @@ -76,28 +85,64 @@ test_script = """ create index ixa_fk__id__kont_id on zf(id, kont_id); commit; - - set planonly; - select zf.* - from zf - where zf.kont_id=5 - order by zf.id, kont_id; - - -- Plan in 3.0.0.32179 (before fix): PLAN (ZF ORDER IXA_FK__ID__KONT_ID) - -- Fixed in 3.0 since: http://sourceforge.net/p/firebird/code/62570 - -- Checked on 2.5.5.26952 - plans are the same now. - """ -act = isql_act('db', test_script) +db = db_factory(init = init_sql) +act = python_act('db', substitutions = [(r'record length: \d+, key length: \d+', 'record length: NN, key length: MM')]) -expected_stdout = """ - PLAN (ZF ORDER IXA_FK__ID__KONT_ID INDEX (FK_ZF__K)) -""" +#----------------------------------------------------------- + +def replace_leading(source, char="."): + stripped = source.lstrip() + return char * (len(source) - len(stripped)) + stripped + +#----------------------------------------------------------- @pytest.mark.version('>=3') -def test_1(act: Action): - act.expected_stdout = expected_stdout - act.execute() - assert act.clean_stdout == act.clean_expected_stdout +def test_1(act: Action, capsys): + test_sql = """ + select zf.* + from zf + where zf.kont_id=5 + order by zf.id, kont_id + """ + with act.db.connect() as con: + cur = con.cursor() + ps = None + try: + ps = cur.prepare(test_sql) + + # Print explained plan with padding eash line by dots in order to see indentations: + print( '\n'.join([replace_leading(s) for s in ps.detailed_plan.split('\n')]) ) + print('') + except DatabaseError as e: + print(e.__str__()) + print(e.gds_codes) + finally: + if ps: + ps.free() + + + expected_stdout_5x = """ + Select Expression + ....-> Filter + ........-> Table "ZF" Access By ID + ............-> Index "IXA_FK__ID__KONT_ID" Full Scan + ................-> Bitmap + ....................-> Index "FK_ZF__K" Range Scan (full match) + """ + + expected_stdout_6x = """ + Select Expression + ....-> Sort (record length: 36, key length: 16) + ........-> Filter + ............-> Table "ZF" Access By ID + ................-> Bitmap + ....................-> Index "FK_ZF__K" Range Scan (full match) + """ + + act.expected_stdout = expected_stdout_5x if act.is_version('<6') else expected_stdout_6x + + act.stdout = capsys.readouterr().out + assert act.clean_stdout == act.clean_expected_stdout