6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 13:33:07 +01:00

Added/Updated tests\bugs\gh_8091_test.py: Checked on 6.0.0.508-67d8e39 (intermediate build).

This commit is contained in:
pavel-zotov 2024-10-25 18:58:49 +03:00
parent 8d4f444954
commit 2c41272f32

144
tests/bugs/gh_8091_test.py Normal file
View File

@ -0,0 +1,144 @@
#coding:utf-8
"""
ID: issue-8091
ISSUE: https://github.com/FirebirdSQL/firebird/issues/8091
TITLE: Ability to create an inactive index
DESCRIPTION:
Test creates a table with several indices, all of them are specified as INACTIVE.
Then we check that these indices actually can *not* be used: explained plans for any query
to this table that could relate to indexed columns must now contain 'Full Scan'.
After this we extract metadata (with saving it to 'init_meta' variable) and drop test table.
Applying of metada to the test database (which is empty now) must pass without errors and,
more important, all indices must remain inactive after that.
Finally, we change DB dialect to 1, make b/r and again do same actions.
Result must be the same as for iteration with default dialect = 3.
NOTES:
[25.10.2024] pzotov
Checked on 6.0.0.508-67d8e39 (intermediate build).
"""
import time
from io import BytesIO
from firebird.driver import SrvRestoreFlag
import pytest
from firebird.qa import *
init_sql = """
set bail on;
recreate table test(id int generated by default as identity, x int, y int, z int);
set term ^;
execute block as
declare n int = 100000;
declare i int = 0;
begin
while (i < n) do
begin
insert into test(x, y, z) values( :i, null, :i);
i = i + 1;
end
end^
set term ;^
commit;
create unique ascending index test_x_asc inactive on test(x);
create descending index test_y_desc inactive on test(y);
create unique descending index test_x_plus_y inactive on test computed by (x+y);
create index test_z_partial inactive on test(z) where mod(id,2) = 0;
create unique index test_x_minus_y_partial inactive on test computed by (x-y) where mod(id,3) <= 1;
commit;
"""
db = db_factory(init = init_sql)
act = python_act('db')
#-----------------------------------------------------------
def replace_leading(source, char="."):
stripped = source.lstrip()
return char * (len(source) - len(stripped)) + stripped
#-----------------------------------------------------------
def check_indices_inactive(act, qry_map, nr_block, capsys):
with act.db.connect() as con:
cur = con.cursor()
for k,v in qry_map.items():
ps = cur.prepare(v)
# Print explained plan with padding eash line by dots in order to see indentations:
print(v)
print( '\n'.join([replace_leading(s) for s in ps.detailed_plan.split('\n')]) )
print('')
ps.free()
expected_out = '\n'.join( [''.join( (qry_map[i],'\n',nr_block) ) for i in range(len(qry_map))] )
act.expected_stdout = expected_out
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout
act.reset()
#-----------------------------------------------------------
@pytest.mark.version('>=6.0')
def test_1(act: Action, capsys):
qry_map = {
0 : 'select count(*) from test where x is null'
,1 : 'select count(*) from test where y is null'
,2 : 'select count(*) from test where x+y is null'
,3 : 'select count(*) from test where z is null and mod(id,2) = 0'
,4 : 'select count(*) from test where x-y is null and mod(id,3) <= 1'
,5 : 'select count(*) from test where x is not distinct from null'
,6 : 'select count(*) from test where y is not distinct from null'
,7 : 'select count(*) from test where x+y is not distinct from null'
,8 : 'select count(*) from test where z is not distinct from null and mod(id,2) = 0'
,9 : 'select count(*) from test where x-y is not distinct from null and mod(id,3) <= 1'
}
nr_block = """
Select Expression
....-> Aggregate
........-> Filter
............-> Table "TEST" Full Scan
"""
for iter in range(2):
# check-1: ensure that all indices actually are INACTIVE, i.e. all queries will use full scan.
##########
check_indices_inactive(act, qry_map, nr_block, capsys)
#---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---
# check-2: extract metadata, drop table and apply metadata which now contains 'INACTIVE' clause for indices.
##########
act.isql(switches=['-x'])
init_meta = '\n'.join( ('set bail on;', act.stdout) )
with act.db.connect() as con:
con.execute_immediate('drop table test')
con.commit()
# Apply metadata to main test database.
act.isql(switches = [], input = init_meta)
# NO errors must occur now:
assert act.clean_stdout == ''
act.reset()
#---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---===+++---
# check-3: ensure that all indices REMAIN INACTIVE, i.e. all queries will use full scan.
##########
check_indices_inactive(act, qry_map, nr_block, capsys)
if iter == 0:
# change dialect to 1, make backup / restore and repeat all prev actions.
act.gfix(switches = ['-sql_dialect', '1', act.db.dsn], combine_output = True)
assert act.clean_stdout == ''
act.reset()
backup = BytesIO()
with act.connect_server() as srv:
srv.database.local_backup(database = act.db.db_path, backup_stream = backup)
backup.seek(0)
srv.database.local_restore(backup_stream = backup, database = act.db.db_path, flags = SrvRestoreFlag.REPLACE)