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

278 lines
8.6 KiB
Python

#coding:utf-8
"""
ID: issue-5116
ISSUE: 5116
TITLE: EXECUTE PROCEDURE's RETURNING_VALUES and EXECUTE STATEMENT's INTO does not
check validity of assignments targets leading to bugcheck
DESCRIPTION:
JIRA: CORE-4819
FBTEST: bugs.core_4819
"""
import pytest
from firebird.qa import *
db = db_factory()
test_script = """
create or alter procedure sp_test(a_x int) as begin end;
recreate table test(id int primary key, x bigint, y bigint);
insert into test values(1, 3, 7);
set list on;
---------------------
select 'initial state' msg, t.* from test t;
---------------------
commit;
set term ^;
create or alter procedure sp_test(a_x int) returns(o_y int) as
begin
o_y = 7 * a_x;
suspend;
end
^
commit
^
create or alter trigger test_aud1 for test active after insert or update or delete as
begin
-- Since WI-T3.0.0.31846 following must produce:
-- Statement failed, SQLSTATE = 42000
-- attempted update of read-only column
if (not inserting) then
begin
execute procedure sp_test(old.x) returning_values(old.x);
execute procedure sp_test(old.x) returning_values(old.y);
end
else
begin
execute procedure sp_test(new.x) returning_values(new.x);
execute procedure sp_test(new.x) returning_values(new.y);
end
rdb$set_context( 'USER_SESSION', 'X_TRG_AIUD1', iif( inserting, new.x, old.x ) );
rdb$set_context( 'USER_SESSION', 'Y_TRG_AIUD1', iif( inserting, new.y, old.y ) );
end
^
create or alter trigger test_aud2 for test active after insert or update or delete as
begin
-- Since WI-T3.0.0.31846 following must produce:
-- Statement failed, SQLSTATE = 42000
-- attempted update of read-only column
if (not inserting) then
begin
execute statement ('execute procedure sp_test( ? )') ( 2 * old.x ) into old.x;
execute statement ('execute procedure sp_test( ? )') ( 2 * old.x ) into old.y;
end
else
begin
execute statement ('execute procedure sp_test( ? )') ( 2 * new.x ) into new.x;
execute statement ('execute procedure sp_test( ? )') ( 2 * new.x ) into new.y;
end
rdb$set_context( 'USER_SESSION', 'X_TRG_AIUD2', iif( inserting, new.x, old.x ) );
rdb$set_context( 'USER_SESSION', 'Y_TRG_AIUD2', iif( inserting, new.y, old.y ) );
end
^
set term ;^
commit;
-- ######################################################################
-- 1. Check when 'execute proc returning_values' is called from trigger,
-- making invalid update of old. & new. variables:
delete from test where id = 1
returning 'delete-returning:' as msg,
x as old_x,
y as old_y;
select
'after delete' msg,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD1') as int) as X_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD1') as int) as Y_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD2') as int) as X_TRG_AIUD2,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD2') as int) as Y_TRG_AIUD2
from rdb$database;
rollback;
update test set x = 17 where id = 1
returning 'update-returning:' as msg,
old.x as old_x,
new.x as new_x,
old.y as old_y,
new.y as new_y;
select
'after update' msg,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD1') as int) as X_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD1') as int) as Y_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD2') as int) as X_TRG_AIUD2,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD2') as int) as Y_TRG_AIUD2,
t.*
from test t;
rollback;
---------------------
insert into test(id, x) values(2, 19)
returning 'insert-returning:' as msg, x as new_x, y as new_y;
select
'after insert' msg,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD1') as int) as X_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD1') as int) as Y_TRG_AIUD1,
cast(rdb$get_context('USER_SESSION', 'X_TRG_AIUD2') as int) as X_TRG_AIUD2,
cast(rdb$get_context('USER_SESSION', 'Y_TRG_AIUD2') as int) as Y_TRG_AIUD2,
t.*
from test t where id=2;
rollback;
-- ######################################################################
-- 2. Check when call 'execute proc returning_values' inside implicit cursor:
set term ^;
execute block returns(msg varchar(20), old_y int, new_y int) as
begin
msg='within cursor-1:';
for
select x, y from test
as cursor ce
do begin
old_y = ce.y;
-- WI-T3.0.0.31845. Following leads to:
-- Statement failed, SQLSTATE = XX000
-- internal Firebird consistency check (EVL_assign_to: invalid operation (229), file: evl.cpp line: 205)
-- Since WI-T3.0.0.31846 must produce:
-- Statement failed, SQLSTATE = 42000
-- attempted update of read-only column
execute procedure sp_test(ce.x) returning_values(ce.y);
new_y = ce.y;
suspend;
end
end
^
set term ;^
rollback;
-- ######################################################################
-- 3. Check when call 'execute statement' inside implicit cursor:
set term ^;
execute block returns(msg varchar(20), old_y int, new_y int) as
begin
msg='within cursor-2:';
for
select x, y from test
as cursor ce
do begin
old_y = ce.y;
-- Since WI-T3.0.0.31846 following must produce:
-- Statement failed, SQLSTATE = 42000
-- attempted update of read-only column
execute statement ('execute procedure sp_test( ? )') ( ce.x ) into ce.y;
new_y = ce.y;
suspend;
end
end
^
set term ;^
rollback;
"""
act = isql_act('db', test_script)
expected_stdout = """
MSG initial state
ID 1
X 3
Y 7
MSG after delete
X_TRG_AIUD1 <null>
Y_TRG_AIUD1 <null>
X_TRG_AIUD2 <null>
Y_TRG_AIUD2 <null>
MSG after update
X_TRG_AIUD1 <null>
Y_TRG_AIUD1 <null>
X_TRG_AIUD2 <null>
Y_TRG_AIUD2 <null>
ID 1
X 3
Y 7
"""
# version: 3.0
expected_stderr_1 = """
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
Statement failed, SQLSTATE = 42000
attempted update of read-only column
"""
@pytest.mark.version('>=3.0,<4.0')
def test_1(act: Action):
act.expected_stdout = expected_stdout
act.expected_stderr = expected_stderr_1
act.execute()
assert (act.clean_stderr == act.clean_expected_stderr and
act.clean_stdout == act.clean_expected_stdout)
# version: 4.0
expected_stderr_2 = """
Statement failed, SQLSTATE = 42000
attempted update of read-only column TEST.X
Statement failed, SQLSTATE = 42000
attempted update of read-only column TEST.X
Statement failed, SQLSTATE = 42000
attempted update of read-only column TEST.X
Statement failed, SQLSTATE = 42000
attempted update of read-only column TEST.X
Statement failed, SQLSTATE = 42000
attempted update of read-only column TEST.X
Statement failed, SQLSTATE = 42000
attempted update of read-only column CE.Y
Statement failed, SQLSTATE = 42000
attempted update of read-only column CE.Y
"""
@pytest.mark.version('>=4.0')
def test_2(act: Action):
act.expected_stdout = expected_stdout
act.expected_stderr = expected_stderr_2
act.execute()
assert (act.clean_stderr == act.clean_expected_stderr and
act.clean_stdout == act.clean_expected_stdout)