|
| 1 | +#coding:utf-8 |
| 2 | + |
| 3 | +""" |
| 4 | +ID: issue-7863 |
| 5 | +ISSUE: 7863 |
| 6 | +TITLE: Non-correlated sub-query is evaluated multiple times if it is based on a VIEW rathe than on appropriate derived table. |
| 7 | +DESCRIPTION: |
| 8 | +NOTES: |
| 9 | + Confirmed bug on 6.0.0.222 |
| 10 | + Checked on 6.0.0.223, 5.0.1.1322. |
| 11 | +""" |
| 12 | + |
| 13 | +import pytest |
| 14 | +from pathlib import Path |
| 15 | +from firebird.qa import * |
| 16 | + |
| 17 | +init_sql = """ |
| 18 | + create view v_test_nr as select 1 i from rdb$fields rows 50; |
| 19 | + create view v_test_ir1 as select 1 i from rdb$fields where rdb$field_name > '' rows 50; |
| 20 | + create view v_test_ir2 as select 1 i from rdb$fields where rdb$field_name > '' order by rdb$field_name rows 50; |
| 21 | + |
| 22 | + create table test(id int); |
| 23 | + insert into test(id) select row_number()over() from rdb$types rows 100; |
| 24 | + commit; |
| 25 | +""" |
| 26 | +db = db_factory(init = init_sql) |
| 27 | + |
| 28 | +act = python_act('db') |
| 29 | + |
| 30 | +@pytest.mark.version('>=5.0.1') |
| 31 | +def test_1(act: Action, capsys): |
| 32 | + |
| 33 | + t_map = { 'rdb$fields' : -1, } |
| 34 | + |
| 35 | + query1 = """ |
| 36 | + select /* case-2 */ count(*) as cnt_via_view from test where (select i from v_test_nr rows 1) >= 0; |
| 37 | + """ |
| 38 | + |
| 39 | + query2 = """ |
| 40 | + select /* case-3b */ count(*) as cnt_via_view from test where (select i from v_test_ir2 rows 1) >= 0; |
| 41 | + """ |
| 42 | + |
| 43 | + query3 = """ |
| 44 | + select /* case-3a */ count(*) as cnt_via_view from test where (select i from v_test_ir1 rows 1) >= 0; |
| 45 | + """ |
| 46 | + q_map = {query1 : '', query2 : '', query3 : ''} |
| 47 | + |
| 48 | + with act.db.connect() as con: |
| 49 | + cur = con.cursor() |
| 50 | + for k in t_map.keys(): |
| 51 | + cur.execute(f"select rdb$relation_id from rdb$relations where rdb$relation_name = upper('{k}')") |
| 52 | + test_rel_id = None |
| 53 | + for r in cur: |
| 54 | + test_rel_id = r[0] |
| 55 | + assert test_rel_id, f"Could not find ID for relation '{k}'. Check its name!" |
| 56 | + t_map[ k ] = test_rel_id |
| 57 | + |
| 58 | + result_map = {} |
| 59 | + |
| 60 | + for qry_txt in q_map.keys(): |
| 61 | + with cur.prepare(qry_txt) as ps: |
| 62 | + q_map[qry_txt] = ps.detailed_plan |
| 63 | + for tab_nm,tab_id in t_map.items(): |
| 64 | + tabstat1 = [ p for p in con.info.get_table_access_stats() if p.table_id == tab_id ] |
| 65 | + cur.execute(qry_txt) |
| 66 | + for r in cur: |
| 67 | + pass |
| 68 | + tabstat2 = [ p for p in con.info.get_table_access_stats() if p.table_id == tab_id ] |
| 69 | + |
| 70 | + result_map[qry_txt, tab_nm] = \ |
| 71 | + ( |
| 72 | + tabstat2[0].sequential if tabstat2[0].sequential else 0 |
| 73 | + ,tabstat2[0].indexed if tabstat2[0].indexed else 0 |
| 74 | + ) |
| 75 | + if tabstat1: |
| 76 | + seq, idx = result_map[qry_txt, tab_nm] |
| 77 | + seq -= (tabstat1[0].sequential if tabstat1[0].sequential else 0) |
| 78 | + idx -= (tabstat1[0].indexed if tabstat1[0].indexed else 0) |
| 79 | + result_map[qry_txt, tab_nm] = (seq, idx) |
| 80 | + |
| 81 | + for k,v in result_map.items(): |
| 82 | + print(k[0]) # query |
| 83 | + print(f'seq={v[0]}, idx={v[1]}') |
| 84 | + print('') |
| 85 | + |
| 86 | + act.expected_stdout = f""" |
| 87 | + {query1} |
| 88 | + seq=1, idx=0 |
| 89 | +
|
| 90 | + {query2} |
| 91 | + seq=0, idx=1 |
| 92 | +
|
| 93 | + {query3} |
| 94 | + seq=0, idx=1 |
| 95 | + """ |
| 96 | + act.stdout = capsys.readouterr().out |
| 97 | + assert act.clean_stdout == act.clean_expected_stdout |
0 commit comments