6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-02-02 02:40:42 +01:00

Added/Updated bugs\core_4386_test.py. Checked on 3.0.8.33535 (SS/CS), 4.0.1.2692 (SS/CS), 5.0.0.730

This commit is contained in:
zotov 2022-09-17 19:10:38 +03:00
parent 5cd7ceec6b
commit b55ab2e28c

View File

@ -5,14 +5,24 @@ ID: issue-4708
ISSUE: 4708
TITLE: Report more details for "object in use" errors
DESCRIPTION:
NOTES:
[22.11.2021] pcisar
This test requires READ_COMMITTED_NO_RECORD_VERSION transaction to work, which
requires ReadConsistency disabled in FB 4. However, it does not work as expected
because all drop commands pass without exception even with ReadConsistency disabled.
The same happens under 3.0.8 (no errors raised).
JIRA: CORE-4386
FBTEST: bugs.core_4386
NOTES:
[22.11.2021] pcisar
This test requires READ_COMMITTED_NO_RECORD_VERSION transaction to work, which
requires ReadConsistency disabled in FB 4. However, it does not work as expected
because all drop commands pass without exception even with ReadConsistency disabled.
The same happens under 3.0.8 (no errors raised).
[17.09.2022] pzotov
1. Test actually must work identical for *every* isolation mode of all possible set.
2. One need to be very careful with object that attempts to make COMMIT after DROP statement:
if we use custom TPB, start transaction explicitly and 'bind' DDL cursor to this transaction
then we have to run commit *exactly* by this TRANSACTION rather then connection whoch owns it!
See 'tx2.commit()' in the code. If we replace it with 'con2.commit()' then Tx2 will be
*silently* rolled back (!!despite that we issued con.commit() !!) and we will not get any
error messages. I'm not sure whether this correct or no.
Checked on 3.0.8.33535 (SS/CS), 4.0.1.2692 (SS/CS), 5.0.0.730
"""
import pytest
@ -24,126 +34,137 @@ db = db_factory()
act = python_act('db')
ddl_script = """
set bail on;
create or alter procedure sp_worker as begin end;
create or alter procedure sp_test as begin end;
create or alter view v_test as select 1 x from rdb$database;
commit;
set bail on;
create or alter procedure sp_worker as begin end;
create or alter procedure sp_test as begin end;
create or alter view v_test as select 1 x from rdb$database;
commit;
recreate table test1(id int,x int);
recreate table test2(id int,x int);
commit;
recreate table test1(id int,x int);
recreate table test2(id int,x int);
commit;
create index test1_id on test1(id);
commit;
create descending index test2_id_x_desc on test2(id,x);
commit;
create index test1_id on test1(id);
commit;
create descending index test2_id_x_desc on test2(id,x);
commit;
create or alter view v_test as select id,x from test1 where id between 15 and 30;
commit;
create or alter view v_test as select id,x from test1 where id between 15 and 30;
commit;
set term ^;
create or alter procedure sp_worker(a_id int) returns(x int) as
begin
for
execute statement ('select v.x from v_test v where v.id = ? and exists(select * from test2 b where b.id = v.id)') (:a_id)
into x
do
suspend;
end
^
create or alter procedure sp_test(a_id int) returns(x int) as
begin
for
execute statement ('select x from sp_worker(?)') (:a_id)
into x
do
suspend;
end
^
set term ;^
commit;
set term ^;
create or alter procedure sp_worker(a_id int) returns(x int) as
begin
for
execute statement ('select v.x from v_test v where v.id = ? and exists(select * from test2 b where b.id = v.id)') (:a_id)
into x
do
suspend;
end
^
create or alter procedure sp_test(a_id int) returns(x int) as
begin
for
execute statement ('select x from sp_worker(?)') (:a_id)
into x
do
suspend;
end
^
set term ;^
commit;
insert into test1 values(11,111);
insert into test1 values(21,222);
insert into test1 values(31,333);
insert into test1 values(41,444);
commit;
insert into test1 values(11,111);
insert into test1 values(21,222);
insert into test1 values(31,333);
insert into test1 values(41,444);
commit;
insert into test2 select * from test1;
commit;
insert into test2 select * from test1;
commit;
"""
expected_stdout = """
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object PROCEDURE "SP_TEST" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object PROCEDURE "SP_TEST" is in use
(335544345, 335544351, 335544453)
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object PROCEDURE "SP_WORKER" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object PROCEDURE "SP_WORKER" is in use
(335544345, 335544351, 335544453)
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object VIEW "V_TEST" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object VIEW "V_TEST" is in use
(335544345, 335544351, 335544453)
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object TABLE "TEST2" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object TABLE "TEST2" is in use
(335544345, 335544351, 335544453)
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object INDEX "TEST1_ID" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object INDEX "TEST1_ID" is in use
(335544345, 335544351, 335544453)
Error while commiting transaction:
- SQLCODE: -901
- lock conflict on no wait transaction
- unsuccessful metadata update
- object INDEX "TEST2_ID_X_DESC" is in use
335544345
lock conflict on no wait transaction
-unsuccessful metadata update
-object INDEX "TEST2_ID_X_DESC" is in use
(335544345, 335544351, 335544453)
"""
@pytest.mark.skip("FIXME: see notes")
@pytest.mark.version('>=3.0.6')
def test_1(act: Action, capsys):
act.isql(switches=[], input=ddl_script)
#
custom_tpb = tpb(isolation=Isolation.READ_COMMITTED_NO_RECORD_VERSION, lock_timeout=0)
with act.db.connect() as con:
cur1 = con.cursor()
cur1.execute('select x from sp_test(21)').fetchall()
drop_commands = ['drop procedure sp_test',
'drop procedure sp_worker',
'drop view v_test',
'drop table test2',
'drop index test1_id',
'drop index test2_id_x_desc']
for cmd in drop_commands:
with act.db.connect() as con2:
tx = con2.transaction_manager(custom_tpb)
tx.begin()
cur2 = tx.cursor()
try:
cur2.execute(cmd)
except Exception as exc:
print(exc)
#
act.reset()
act.expected_stdout = expected_stdout
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout
drop_commands = ['drop procedure sp_test',
'drop procedure sp_worker',
'drop view v_test',
'drop table test2',
'drop index test1_id',
'drop index test2_id_x_desc']
tx_isol_lst = [ Isolation.READ_COMMITTED_NO_RECORD_VERSION,
Isolation.READ_COMMITTED_RECORD_VERSION,
Isolation.SNAPSHOT,
Isolation.SERIALIZABLE,
]
if act.is_version('>=4'):
tx_isol_lst.append(Isolation.READ_COMMITTED_READ_CONSISTENCY)
# for any isolation mode attempt to drop object that is in use by another Tx must fail
# with the same error message. We check all possible Tx isolation modes for that:
for x_isol in tx_isol_lst:
with act.db.connect() as con1:
cur1 = con1.cursor()
cur1.execute('select x from sp_test(21)').fetchall()
for cmd in drop_commands:
with act.db.connect() as con2:
custom_tpb = tpb(isolation = x_isol, lock_timeout=0)
tx2 = con2.transaction_manager(custom_tpb)
tx2.begin()
cur2 = tx2.cursor()
try:
cur2.execute(cmd) # this will PASS because of DDL nature
##########################################################################
### We have to call commit() exactly by TRANSACTION object here. ###
### DO NOT use con2.commit() because this actually leads transaction ###
### to be 'silently rolled back', thus we will not get error messages! ###
##########################################################################
tx2.commit() # <<< this lead to FAILED_COMMIT in the trace <<<
except Exception as e:
print(e.__str__())
print(e.gds_codes)
act.expected_stdout = expected_stdout
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout
act.reset()