#coding:utf-8 # # id: bugs.core_4369 # title: BUGCHECK(177) for MERGE with multiple matches # decription: # Checked (again, 07.06.2020) on 3.0.6.33296. # # 07.06.2020. NOTE: separate section for FB 4.x was added since fix for core-2274 issued: # MERGE can not change the same record multiple times. # For this reason we have to check only presense of ERROR in 4.x and that result is the same after merge and rollback. # Checked on 4.0.0.2022 # # tracker_id: CORE-4369 # min_versions: ['3.0'] # versions: 3.0, 4.0 # qmid: None import pytest from firebird.qa import db_factory, isql_act, Action # version: 3.0 # resources: None substitutions_1 = [] init_script_1 = """""" db_1 = db_factory(sql_dialect=3, init=init_script_1) test_script_1 = """ recreate sequence g; recreate table t1 ( id int, val int ); recreate table t2 ( id int, val int, seq_inside_merge int ); commit; insert into t1 (id, val) select row_number() over(), 1000 from rdb$types rows 17; -- '17' ==> 'N', see below formula for seq_inside_merge insert into t2(id, val, seq_inside_merge) select id, val, 0 from t1; commit; alter sequence g restart with 0; commit; merge into t2 as t using t1 as s on 1 = 1 when matched then update set t.val = t.val + s.val, t.seq_inside_merge = next value for g ; set list on; select * from t2 order by id; -- 1st value of `SEQ_INSIDE_MERGE` = N * (N-1) + 1 -- All subsequent values are incremented by 1. -- Confirmed result in WI-T3.0.0.31374 Beta-1: -- "internal Firebird consistency check (applied differences will not fit in record (177), file: sqz.cpp line: 147)" """ act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1) expected_stdout_1 = """ ID 1 VAL 2000 SEQ_INSIDE_MERGE 273 ID 2 VAL 2000 SEQ_INSIDE_MERGE 274 ID 3 VAL 2000 SEQ_INSIDE_MERGE 275 ID 4 VAL 2000 SEQ_INSIDE_MERGE 276 ID 5 VAL 2000 SEQ_INSIDE_MERGE 277 ID 6 VAL 2000 SEQ_INSIDE_MERGE 278 ID 7 VAL 2000 SEQ_INSIDE_MERGE 279 ID 8 VAL 2000 SEQ_INSIDE_MERGE 280 ID 9 VAL 2000 SEQ_INSIDE_MERGE 281 ID 10 VAL 2000 SEQ_INSIDE_MERGE 282 ID 11 VAL 2000 SEQ_INSIDE_MERGE 283 ID 12 VAL 2000 SEQ_INSIDE_MERGE 284 ID 13 VAL 2000 SEQ_INSIDE_MERGE 285 ID 14 VAL 2000 SEQ_INSIDE_MERGE 286 ID 15 VAL 2000 SEQ_INSIDE_MERGE 287 ID 16 VAL 2000 SEQ_INSIDE_MERGE 288 ID 17 VAL 2000 SEQ_INSIDE_MERGE 289 """ @pytest.mark.version('>=3.0,<4.0') def test_1(act_1: Action): act_1.expected_stdout = expected_stdout_1 act_1.execute() assert act_1.clean_expected_stdout == act_1.clean_stdout # version: 4.0 # resources: None substitutions_2 = [] init_script_2 = """""" db_2 = db_factory(sql_dialect=3, init=init_script_2) test_script_2 = """ recreate sequence g; recreate table t1 ( id int, val int ); recreate table t2 ( id int, val int, seq_inside_merge int ); commit; insert into t1 (id, val) select row_number() over(), 1000 from rdb$types rows 17; -- '17' ==> 'N', see below formula for seq_inside_merge insert into t2(id, val, seq_inside_merge) select id, val, 0 from t1; commit; alter sequence g restart with 0; commit; merge into t2 as t using t1 as s on 1 = 1 when matched then update set t.val = t.val + s.val, t.seq_inside_merge = next value for g ; -- all values should remain unchanged: set list on; select * from t2 order by id; """ act_2 = isql_act('db_2', test_script_2, substitutions=substitutions_2) expected_stdout_2 = """ ID 1 VAL 1000 SEQ_INSIDE_MERGE 0 ID 2 VAL 1000 SEQ_INSIDE_MERGE 0 ID 3 VAL 1000 SEQ_INSIDE_MERGE 0 ID 4 VAL 1000 SEQ_INSIDE_MERGE 0 ID 5 VAL 1000 SEQ_INSIDE_MERGE 0 ID 6 VAL 1000 SEQ_INSIDE_MERGE 0 ID 7 VAL 1000 SEQ_INSIDE_MERGE 0 ID 8 VAL 1000 SEQ_INSIDE_MERGE 0 ID 9 VAL 1000 SEQ_INSIDE_MERGE 0 ID 10 VAL 1000 SEQ_INSIDE_MERGE 0 ID 11 VAL 1000 SEQ_INSIDE_MERGE 0 ID 12 VAL 1000 SEQ_INSIDE_MERGE 0 ID 13 VAL 1000 SEQ_INSIDE_MERGE 0 ID 14 VAL 1000 SEQ_INSIDE_MERGE 0 ID 15 VAL 1000 SEQ_INSIDE_MERGE 0 ID 16 VAL 1000 SEQ_INSIDE_MERGE 0 ID 17 VAL 1000 SEQ_INSIDE_MERGE 0 """ expected_stderr_2 = """ Statement failed, SQLSTATE = 21000 Multiple source records cannot match the same target during MERGE """ @pytest.mark.version('>=4.0') def test_2(act_2: Action): act_2.expected_stdout = expected_stdout_2 act_2.expected_stderr = expected_stderr_2 act_2.execute() assert act_2.clean_expected_stderr == act_2.clean_stderr assert act_2.clean_expected_stdout == act_2.clean_stdout