# name : innodb_fake_changes.patch # introduced : 5.5.15 # maintainer : Yasufumi # #!!! notice !!! # Any small change to this file in the main branch # should be done or reviewed by the maintainer! --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1158,6 +1158,11 @@ rec_t* rec; roll_ptr_t roll_ptr; + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO */ + return(DB_SUCCESS); + } + /* Check if we have to wait for a lock: enqueue an explicit lock request if yes */ @@ -1289,7 +1294,7 @@ } #endif /* UNIV_DEBUG */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); max_size = page_get_max_insert_size_after_reorganize(page, 1); leaf = page_is_leaf(page); @@ -1384,6 +1389,12 @@ goto fail_err; } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + *big_rec = big_rec_vec; + return(err); /* == DB_SUCCESS */ + } + page_cursor = btr_cur_get_page_cur(cursor); /* Now, try the insert */ @@ -1526,10 +1537,10 @@ *big_rec = NULL; - ut_ad(mtr_memo_contains(mtr, + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); /* Try first an optimistic insert; reset the cursor flag: we do not @@ -1595,6 +1606,16 @@ } } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + if (n_extents > 0) { + fil_space_release_free_extents(index->space, + n_reserved); + } + *big_rec = big_rec_vec; + return(DB_SUCCESS); + } + if (dict_index_get_page(index) == buf_block_get_page_no(btr_cur_get_block(cursor))) { @@ -1651,6 +1672,11 @@ ut_ad(cursor && update && thr && roll_ptr); + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO */ + return(DB_SUCCESS); + } + rec = btr_cur_get_rec(cursor); index = cursor->index; @@ -1950,6 +1976,14 @@ return(err); } + if (trx->fake_changes) { + /* skip CHANGE, LOG */ + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return(err); /* == DB_SUCCESS */ + } + if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_rec_sys_fields(rec, NULL, index, offsets, trx, roll_ptr); @@ -2059,7 +2093,7 @@ rec = btr_cur_get_rec(cursor); index = cursor->index; ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); /* The insert buffer tree should never be updated in place. */ ut_ad(!dict_index_is_ibuf(index)); @@ -2172,6 +2206,11 @@ goto err_exit; } + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip CHANGE, LOG */ + goto err_exit; /* == DB_SUCCESS */ + } + /* Ok, we may do the replacement. Store on the page infimum the explicit locks on rec, before deleting rec (see the comment in btr_cur_pessimistic_update). */ @@ -2322,9 +2361,9 @@ rec = btr_cur_get_rec(cursor); index = cursor->index; - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ @@ -2412,6 +2451,9 @@ ut_ad(big_rec_vec == NULL); + /* fake_changes should not cause undo. so never reaches here */ + ut_ad(!(trx->fake_changes)); + btr_rec_free_updated_extern_fields( index, rec, page_zip, offsets, update, trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr); @@ -2446,6 +2488,12 @@ } } + if (trx->fake_changes) { + /* skip CHANGE, LOG */ + err = DB_SUCCESS; + goto return_after_reservations; + } + /* Store state of explicit locks on rec on the page infimum record, before deleting rec. The page infimum acts as a dummy carrier of the locks, taking care also of lock releases, before we can move the locks @@ -2748,6 +2796,11 @@ ut_ad(dict_index_is_clust(index)); ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, UNDO, CHANGE, LOG */ + return(DB_SUCCESS); + } + err = lock_clust_rec_modify_check_and_lock(flags, block, rec, index, offsets, thr); @@ -2882,6 +2935,11 @@ rec_t* rec; ulint err; + if (thr && thr_get_trx(thr)->fake_changes) { + /* skip LOCK, CHANGE, LOG */ + return(DB_SUCCESS); + } + block = btr_cur_get_block(cursor); rec = btr_cur_get_rec(cursor); --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -488,6 +488,12 @@ " or 2 (write at commit, flush once per second).", NULL, NULL, 1, 0, 2, 0); +static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG, + "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records " + "and do nothing other operations (no changes, no ibuf, no undo, no transaction log) in the transaction. " + "This is to cause replication prefetch IO. ATTENTION: the transaction started after enabled is affected.", + NULL, NULL, FALSE); + static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -1689,6 +1695,8 @@ trx->check_unique_secondary = !thd_test_options( thd, OPTION_RELAXED_UNIQUE_CHECKS); + trx->fake_changes = THDVAR(thd, fake_changes); + #ifdef EXTENDED_SLOWLOG if (thd_log_slow_verbosity(thd) & SLOG_V_INNODB) { trx->take_stats = TRUE; @@ -3195,6 +3203,11 @@ trx_search_latch_release_if_reserved(trx); } + if (trx->fake_changes && (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { + innobase_rollback(hton, thd, all); /* rollback implicitly */ + thd->stmt_da->reset_diagnostics_area(); /* because debug assertion code complains, if something left */ + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } /* Transaction is deregistered only in a commit or a rollback. If it is deregistered we know there cannot be resources to be freed and we could return immediately. For the time being, we play safe @@ -7543,6 +7556,12 @@ trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Latch the InnoDB data dictionary exclusively so that no deadlocks or lock waits can happen in it during a table create operation. Drop table etc. do this latching in row0mysql.c. */ @@ -7763,6 +7782,10 @@ DBUG_RETURN(HA_ERR_CRASHED); } + if (prebuilt->trx->fake_changes) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Truncate the table in InnoDB */ error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); @@ -7819,6 +7842,12 @@ trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + name_len = strlen(name); ut_a(name_len < 1000); @@ -7905,6 +7934,12 @@ trx->mysql_thd = NULL; #else trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + my_free(namebuf); + innobase_commit_low(trx); + trx_free_for_mysql(trx); + return; /* ignore */ + } #endif row_drop_database_for_mysql(namebuf, trx); my_free(namebuf); @@ -8010,6 +8045,11 @@ trx_search_latch_release_if_reserved(parent_trx); trx = innobase_trx_allocate(thd); + if (trx->fake_changes) { + innobase_commit_low(trx); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } error = innobase_rename_table(trx, from, to, TRUE); @@ -10880,6 +10920,10 @@ return(0); } + if (trx->fake_changes) { + return(0); + } + thd_get_xid(thd, (MYSQL_XID*) &trx->xid); /* Release a possible FIFO ticket and search latch. Since we will @@ -12480,6 +12524,7 @@ #endif MYSQL_SYSVAR(corrupt_table_action), MYSQL_SYSVAR(lazy_drop_table), + MYSQL_SYSVAR(fake_changes), NULL }; --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -695,6 +695,10 @@ possible adaptive hash latch to avoid deadlocks of threads. */ trx_search_latch_release_if_reserved(prebuilt->trx); + if (prebuilt->trx->fake_changes) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Check if the index name is reserved. */ if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) { DBUG_RETURN(-1); @@ -732,6 +736,13 @@ /* Create a background transaction for the operations on the data dictionary tables. */ trx = innobase_trx_allocate(user_thd); + if (trx->fake_changes) { + mem_heap_free(heap); + trx_general_rollback_for_mysql(trx, NULL); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + trx_start_if_not_started(trx); /* Create table containing all indexes to be built in this @@ -1092,6 +1103,10 @@ trx_search_latch_release_if_reserved(prebuilt->trx); trx = prebuilt->trx; + if (trx->fake_changes) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); @@ -1296,6 +1311,12 @@ /* Create a background transaction for the operations on the data dictionary tables. */ trx = innobase_trx_allocate(user_thd); + if (trx->fake_changes) { + trx_general_rollback_for_mysql(trx, NULL); + trx_free_for_mysql(trx); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + trx_start_if_not_started(trx); /* Flag this transaction as a dictionary operation, so that --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -3424,6 +3424,8 @@ ut_a(trx_sys_multiple_tablespace_format); + ut_ad(!(thr_get_trx(thr)->fake_changes)); + do_merge = FALSE; /* Perform dirty reads of ibuf->size and ibuf->max_size, to --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -512,6 +512,7 @@ FALSE, one can save CPU time and about 150 bytes in the undo log size as then we skip XA steps */ + ulint fake_changes; ulint flush_log_later;/* In 2PC, we hold the prepare_commit mutex across both phases. In that case, we --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -3912,6 +3912,10 @@ trx = thr_get_trx(thr); + if (trx->fake_changes && mode == LOCK_IX) { + mode = LOCK_IS; + } + lock_mutex_enter_kernel(); /* Look for stronger locks the same trx already has on the table */ @@ -5114,6 +5118,11 @@ } trx = thr_get_trx(thr); + + if (trx->fake_changes) { + return(DB_SUCCESS); + } + next_rec = page_rec_get_next_const(rec); next_rec_heap_no = page_rec_get_heap_no(next_rec); @@ -5282,6 +5291,10 @@ return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes) { + return(DB_SUCCESS); + } + heap_no = rec_offs_comp(offsets) ? rec_get_heap_no_new(rec) : rec_get_heap_no_old(rec); @@ -5340,6 +5353,10 @@ return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes) { + return(DB_SUCCESS); + } + heap_no = page_rec_get_heap_no(rec); /* Another transaction cannot have an implicit lock on the record, @@ -5427,6 +5444,10 @@ return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { + mode = LOCK_S; + } + heap_no = page_rec_get_heap_no(rec); lock_mutex_enter_kernel(); @@ -5503,6 +5524,10 @@ return(DB_SUCCESS); } + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { + mode = LOCK_S; + } + heap_no = page_rec_get_heap_no(rec); lock_mutex_enter_kernel(); --- a/storage/innobase/que/que0que.c +++ b/storage/innobase/que/que0que.c @@ -1417,6 +1417,12 @@ ut_a(trx->error_state == DB_SUCCESS); + if (trx->fake_changes) { + /* fake_changes should not access to system tables */ + fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n"); + return(DB_ERROR); + } + if (reserve_dict_mutex) { mutex_enter(&dict_sys->mutex); } --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1505,6 +1505,11 @@ if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + + if (trx->fake_changes) { + err = DB_SUCCESS; + } + return(err); } @@ -2010,7 +2015,7 @@ } btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - search_mode, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : search_mode, &cursor, 0, __FILE__, __LINE__, &mtr); if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { @@ -2070,7 +2075,7 @@ btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - mode | BTR_INSERT, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT), &cursor, 0, __FILE__, __LINE__, &mtr); } @@ -2124,6 +2129,22 @@ if (UNIV_LIKELY_NULL(big_rec)) { rec_t* rec; ulint* offsets; + + if (thr_get_trx(thr)->fake_changes) { + /* skip store extern */ + if (modify) { + dtuple_big_rec_free(big_rec); + } else { + dtuple_convert_back_big_rec(index, entry, big_rec); + } + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + return(err); + } + mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1246,6 +1246,7 @@ prebuilt->table->stat_n_rows--; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); trx->op_info = ""; @@ -1505,6 +1506,7 @@ that changes indexed columns, UPDATEs that change only non-indexed columns would not affect statistics. */ if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); } @@ -1722,6 +1724,7 @@ srv_n_rows_updated++; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(table); return(err); --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1603,7 +1603,8 @@ mode |= BTR_DELETE_MARK; } - search_result = row_search_index_entry(index, entry, mode, + search_result = row_search_index_entry(index, entry, + trx->fake_changes ? BTR_SEARCH_LEAF : mode, &pcur, &mtr); btr_cur = btr_pcur_get_btr_cur(&pcur); @@ -1850,9 +1851,11 @@ the previous invocation of this function. Mark the off-page columns in the entry inherited. */ + if (!(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( NULL, NULL, entry, node->update); ut_a(change_ownership); + } /* fall through */ case UPD_NODE_INSERT_CLUSTERED: /* A lock wait occurred in row_ins_index_entry() in @@ -1882,7 +1885,7 @@ delete-marked old record, mark them disowned by the old record and owned by the new entry. */ - if (rec_offs_any_extern(offsets)) { + if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( rec, offsets, entry, node->update); @@ -2012,7 +2015,8 @@ the same transaction do not modify the record in the meantime. Therefore we can assert that the restoration of the cursor succeeds. */ - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); + ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE, + pcur, mtr)); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); @@ -2022,7 +2026,8 @@ node->cmpl_info, thr, mtr); mtr_commit(mtr); - if (err == DB_SUCCESS && big_rec) { + /* skip store extern for fake_changes */ + if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); @@ -2146,7 +2151,8 @@ ut_a(pcur->rel_pos == BTR_PCUR_ON); - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); + success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, + pcur, mtr); if (!success) { err = DB_RECORD_NOT_FOUND; --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -121,6 +121,8 @@ trx->support_xa = TRUE; + trx->fake_changes = FALSE; + trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; --- /dev/null +++ b/mysql-test/r/percona_innodb_fake_changes.result @@ -0,0 +1,55 @@ +DROP TABLE IF EXISTS t1; +# Checking variables +SHOW VARIABLES LIKE 'innodb_fake_changes'; +Variable_name Value +innodb_fake_changes OFF +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; +VARIABLE_VALUE +OFF +SET innodb_fake_changes=1; +SHOW VARIABLES LIKE 'innodb_fake_changes'; +Variable_name Value +innodb_fake_changes ON +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; +VARIABLE_VALUE +ON +SET innodb_fake_changes=default; +SHOW VARIABLES LIKE 'innodb_fake_changes'; +Variable_name Value +innodb_fake_changes OFF +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; +VARIABLE_VALUE +OFF +# Explicit COMMIT should fail when innodb_fake_changes is enabled +# DML should be fine +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +INSERT INTO t1 VALUES (2); +UPDATE t1 SET a=0; +DELETE FROM t1 LIMIT 1; +SELECT * FROM t1; +a +1 +COMMIT; +ERROR HY000: Got error 131 during COMMIT +SET innodb_fake_changes=default; +DROP TABLE t1; +# DDL must result in error +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +ERROR HY000: Can't create table 'test.t2' (errno: 131) +DROP TABLE t1; +ERROR 42S02: Unknown table 't1' +TRUNCATE TABLE t1; +ERROR HY000: Got error 131 during COMMIT +ALTER TABLE t1 ENGINE=MyISAM; +ERROR HY000: Got error 131 during COMMIT +ROLLBACK; +SET innodb_fake_changes=default; +DROP TABLE t1; --- /dev/null +++ b/mysql-test/r/percona_innodb_fake_changes_locks.result @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS t1; +# Verifying that X_LOCK not acquired +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +SELECT * FROM t1 FOR UPDATE; +a +1 +SET innodb_lock_wait_timeout=3; +UPDATE t1 SET a=2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SELECT * FROM t1 LOCK IN SHARE MODE; +a +1 +ROLLBACK; +SET innodb_fake_changes=default; +DROP TABLE t1; --- /dev/null +++ b/mysql-test/t/percona_innodb_fake_changes.test @@ -0,0 +1,49 @@ +--source include/have_innodb.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + + +--echo # Checking variables +SHOW VARIABLES LIKE 'innodb_fake_changes'; +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; +SET innodb_fake_changes=1; +SHOW VARIABLES LIKE 'innodb_fake_changes'; +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; +SET innodb_fake_changes=default; +SHOW VARIABLES LIKE 'innodb_fake_changes'; +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; + +--echo # Explicit COMMIT should fail when innodb_fake_changes is enabled +--echo # DML should be fine +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +INSERT INTO t1 VALUES (2); +UPDATE t1 SET a=0; +DELETE FROM t1 LIMIT 1; +SELECT * FROM t1; +--error 1180 +COMMIT; +SET innodb_fake_changes=default; +DROP TABLE t1; + +--echo # DDL must result in error +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +--error 1005 +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +--error 1051 +DROP TABLE t1; +--error 1180 +TRUNCATE TABLE t1; +--error 1180 +ALTER TABLE t1 ENGINE=MyISAM; +ROLLBACK; +SET innodb_fake_changes=default; +DROP TABLE t1; --- /dev/null +++ b/mysql-test/t/percona_innodb_fake_changes_locks.test @@ -0,0 +1,24 @@ +--source include/have_innodb.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo # Verifying that X_LOCK not acquired +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +--connect (conn1,localhost,root,,) +--connection conn1 +SET autocommit=0; +SET innodb_fake_changes=1; +BEGIN; +SELECT * FROM t1 FOR UPDATE; +--connection default +SET innodb_lock_wait_timeout=3; +--error 1205 +UPDATE t1 SET a=2; +SELECT * FROM t1 LOCK IN SHARE MODE; +--connection conn1 +ROLLBACK; +SET innodb_fake_changes=default; +DROP TABLE t1;