#coding:utf-8 """ ID: issue-7137 ISSUE: https://github.com/FirebirdSQL/firebird/issues/7137 TITLE: Optimizer regression: bad plan (HASH instead of JOIN) is chosen for some inner joins NOTES: [26.04.2022] pzotov Confirmed bug (ineffective execution plan) on 3.0.9.33560 (09.02.2022). Checked on 6.0.0.336, 5.0.1.1383, 4.0.5.3086, 3.0.10.33569 (24.02.2022) - all fine. """ import pytest from firebird.qa import * init_sql = """ recreate table test_c(x int); commit; recreate table test_a( id int unique using index test_a_pk ,ico int ,name varchar(50) ); create index test_a_name on test_a(name); recreate table test_b( id int primary key using index test_b_pk ,ico int ,name varchar(50) ); recreate table test_c( id int primary key using index test_c_pk ,pid_a int references test_a(id) using index test_c_fk ); insert into test_a(id, ico, name) select row_number()over(), mod( row_number()over(), 10 ), ascii_char(64 + mod( row_number()over(), 10 )) from rdb$types rows 200; insert into test_b(id, ico, name) select row_number()over()-1, mod( row_number()over(), 10 ), ascii_char(64 + mod( row_number()over(), 10 )) from rdb$types, rdb$types rows 10000; insert into test_c(id, pid_a) select row_number()over(), 1 + mod( row_number()over(), 100 ) from rdb$types, rdb$types rows 10000; commit; set statistics index test_a_pk; set statistics index test_a_name; set statistics index test_b_pk; set statistics index test_c_pk; set statistics index test_c_fk; commit; """ db = db_factory(init = init_sql) query_lst = [ """ select 1 from test_a a join test_b b on b.ico = a.ico join test_c c on c.pid_a = a.id where b.id = 0 and a.name = b.name """, ] act = python_act('db') #--------------------------------------------------------- def replace_leading(source, char="."): stripped = source.lstrip() return char * (len(source) - len(stripped)) + stripped #--------------------------------------------------------- @pytest.mark.version('>=3.0.9') def test_1(act: Action, capsys): with act.db.connect() as con: cur = con.cursor() for q in query_lst: with cur.prepare(q) as ps: print( '\n'.join([replace_leading(s) for s in ps.detailed_plan .split('\n')]) ) expected_stdout = """ Select Expression ....-> Nested Loop Join (inner) ........-> Filter ............-> Table "TEST_B" as "B" Access By ID ................-> Bitmap ....................-> Index "TEST_B_PK" Unique Scan ........-> Filter ............-> Table "TEST_A" as "A" Access By ID ................-> Bitmap ....................-> Index "TEST_A_NAME" Range Scan (full match) ........-> Filter ............-> Table "TEST_C" as "C" Access By ID ................-> Bitmap ....................-> Index "TEST_C_FK" Range Scan (full match) """ act.expected_stdout = expected_stdout act.stdout = capsys.readouterr().out assert act.clean_stdout == act.clean_expected_stdout