6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00
firebird-qa/tests/bugs/core_5020_test.py

149 lines
4.6 KiB
Python

#coding:utf-8
"""
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 *
init_sql = """
recreate table zf(
id integer not null primary key,
kont_id integer not null
);
recreate table u(
id integer not null primary key,
kont_id integer not null
);
recreate table k(
id integer not null primary key
);
commit;
insert into zf (id, kont_id) values ('1', '1');
insert into zf (id, kont_id) values ('2', '7');
insert into zf (id, kont_id) values ('3', '3');
insert into zf (id, kont_id) values ('4', '5');
insert into zf (id, kont_id) values ('5', '5');
insert into zf (id, kont_id) values ('6', '1');
insert into zf (id, kont_id) values ('7', '4');
insert into zf (id, kont_id) values ('8', '2');
insert into zf (id, kont_id) values ('9', '9');
insert into zf (id, kont_id) values ('10', '1');
insert into k (id) values ('1');
insert into k (id) values ('2');
insert into k (id) values ('3');
insert into k (id) values ('4');
insert into k (id) values ('5');
insert into k (id) values ('6');
insert into k (id) values ('7');
insert into k (id) values ('8');
insert into k (id) values ('9');
insert into k (id) values ('10');
insert into u (id, kont_id) values ('1', '4');
insert into u (id, kont_id) values ('2', '6');
insert into u (id, kont_id) values ('3', '3');
insert into u (id, kont_id) values ('4', '2');
insert into u (id, kont_id) values ('5', '5');
insert into u (id, kont_id) values ('6', '2');
insert into u (id, kont_id) values ('7', '9');
insert into u (id, kont_id) values ('8', '2');
insert into u (id, kont_id) values ('9', '10');
insert into u (id, kont_id) values ('10', '1');
commit;
alter table zf add constraint fk_zf__k
foreign key(kont_id)
references k(id)
using index fk_zf__k
;
set statistics index fk_zf__k;
create index ixa_fk__id__kont_id on zf(id, kont_id);
commit;
"""
db = db_factory(init = init_sql)
act = python_act('db', substitutions = [(r'record length: \d+, key length: \d+', 'record length: NN, key length: MM')])
#-----------------------------------------------------------
def replace_leading(source, char="."):
stripped = source.lstrip()
return char * (len(source) - len(stripped)) + stripped
#-----------------------------------------------------------
@pytest.mark.version('>=3')
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