####################################################################################### # # Executes REPLACE statements (effectively INSERT, or DELETE then INSERT if # a duplicate value for a unique index or primary key is specified. # # Transaction 1: REPLACE INTO # Transaction 2: REPLACE INTO SELECT # # NOTE: We should not delete rows where pk MOD 5 = 0 AND pk < 1001 # (consistency check, see rr_c_count_not_zero). # So, make sure to insert/replace rows with pk > 1000, etc. # # Note that one REPLACE insert may replace more than one row, if we have # multiple columns with unique indexes. # Vary the values for unique columns so that we don't replace the same row every time. ###################################################################################### SET autocommit = 0; ########################### # Transaction 1 ########################### START TRANSACTION; # In order to avoid replacing a "reserved" row (pk mod 5 = 0 AND pk <= 1000), we need # to pick a row to replace which fulfills this requirement (we cannot replace an arbitrary row). # We also should not replace internally inconsistent rows, as this would not be a zero-sum transaction. # We select a pk between 200 and 1200 depending on conn_id, not including those where pk MOD 5 = 0. # This will cost an extra roundtrip and reduce concurency, but there is not much else to do apart # from not having unique indexes in the table. # Using FOR UPDATE to avoid letting other treads change the uniques values or the row's consistency # properties in the mean time. --echo *** Disabling result log --disable_result_log --error 0, ER_LOCK_DEADLOCK, ER_LOCK_WAIT_TIMEOUT, ER_CHECKREAD SELECT @pk:=`pk`, @unique:=`int1_unique` FROM t1 WHERE `pk` MOD 5 <> 0 AND `pk` > 200 + (CONNECTION_ID() MOD 1000) AND `int1_unique` NOT IN (SELECT `int1_unique` FROM t1 WHERE (`pk` < 1000 AND `pk` MOD 5 = 0) OR `is_consistent` = 0) AND -`int1_unique` NOT IN (SELECT `int2_unique` FROM t1 WHERE (`pk` < 1000 AND `pk` MOD 5 = 0) OR `is_consistent` = 0) AND `is_consistent`= 1 LIMIT 1 FOR UPDATE; --echo *** Enabling result log --enable_result_log --source suite/engines/rr_trx/include/check_for_error_rollback_skip.inc --error 0, ER_LOCK_DEADLOCK, ER_LOCK_WAIT_TIMEOUT, ER_CHECKREAD REPLACE INTO t1 SET `pk` = @pk, `id` = 7, `int1` = 7, `int1_key` = -7, `int1_unique` = @unique, `int2` = -7, `int2_key` = 7, `int2_unique` = -@unique, `connection_id` = CONNECTION_ID(), `is_consistent` = 1; COMMIT; ########################### # Transaction 2 ########################### START TRANSACTION; # Same rules apply as in previous transaction. Do not replace a "reserved" or inconsistent row. # We get Warning "1592: Statement is not safe to log in statement mode" with server 5.1 # due to LIMIT (see Bug#42415 and Bug#42851). --disable_warnings --error 0, ER_LOCK_DEADLOCK, ER_LOCK_WAIT_TIMEOUT, ER_CHECKREAD REPLACE INTO t1 SELECT * FROM t1 WHERE `pk` > 1000 + CONNECTION_ID() MOD 777 AND `int1_unique` NOT IN (SELECT `int1_unique` FROM t1 WHERE `pk` < 1000 OR `is_consistent` = 0) AND `int2_unique` NOT IN (SELECT `int2_unique` FROM t1 WHERE `pk` < 1000 OR `is_consistent` = 0) AND `pk` MOD 5 <> 0 AND `is_consistent` = 1 ORDER BY `pk` LIMIT 1; --enable_warnings # Conditional, so skip query log: --disable_query_log --echo *** Updating replaced row (if applicable) # Update id, conn_id if we successfully replaced a row. if (`SELECT IF(ROW_COUNT() > 0, 1, 0)`) { --error 0, ER_LOCK_DEADLOCK, ER_LOCK_WAIT_TIMEOUT, ER_CHECKREAD UPDATE t1 SET `id` = 8, `connection_id` = CONNECTION_ID() WHERE `pk` = @@last_insert_id; --source suite/engines/rr_trx/include/check_for_error_rollback.inc } --enable_query_log COMMIT;