diff --git a/mysql-test/suite/innodb/r/snapshot.result b/mysql-test/suite/innodb/r/snapshot.result new file mode 100644 index 00000000000..dcb3d242fc2 --- /dev/null +++ b/mysql-test/suite/innodb/r/snapshot.result @@ -0,0 +1,8 @@ +START TRANSACTION WITH CONSISTENT SNAPSHOT; +CREATE TABLE IF NOT EXISTS t1 (pk INT PRIMARY KEY, i INT, KEY(i)) ENGINE=InnoDB; +UPDATE t1 SET i = 0; +ERROR HY000: Table definition has changed, please retry transaction +UPDATE t1 SET pk = 0; +ERROR HY000: Table definition has changed, please retry transaction +commit; +drop table t1; diff --git a/mysql-test/suite/innodb/t/snapshot.test b/mysql-test/suite/innodb/t/snapshot.test new file mode 100644 index 00000000000..8e3dc76fe54 --- /dev/null +++ b/mysql-test/suite/innodb/t/snapshot.test @@ -0,0 +1,18 @@ + +--source include/have_log_bin.inc +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc + +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connect (con1,localhost,root,,test) +CREATE TABLE IF NOT EXISTS t1 (pk INT PRIMARY KEY, i INT, KEY(i)) ENGINE=InnoDB; + +--connection default +--error 1412 +UPDATE t1 SET i = 0; +--error 1412 +UPDATE t1 SET pk = 0; +commit; + +drop table t1; diff --git a/sql/records.cc b/sql/records.cc index bfce2f83967..a37f7a18c11 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -66,10 +66,12 @@ static int rr_index_desc(READ_RECORD *info); @param reverse Scan in the reverse direction */ -void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, +bool init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx, bool reverse) { int error; + DBUG_ENTER("init_read_record_idx"); + empty_record(table); bzero((char*) info,sizeof(*info)); info->thd= thd; @@ -88,6 +90,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, /* read_record will be changed to rr_index in rr_index_first */ info->read_record= reverse ? rr_index_last : rr_index_first; + DBUG_RETURN(error != 0); } diff --git a/sql/records.h b/sql/records.h index 21477d4a30b..a3f0b5eb084 100644 --- a/sql/records.h +++ b/sql/records.h @@ -76,7 +76,7 @@ public: bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors, bool disable_rr_cache); -void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, +bool init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx, bool reverse); void end_read_record(READ_RECORD *info); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5292b964576..64f5c85ef22 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -508,17 +508,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, free_underlaid_joins(thd, select_lex); DBUG_RETURN(TRUE); } + if (query_plan.index == MAX_KEY || (select && select->quick)) - { - if (init_read_record(&info, thd, table, select, 1, 1, FALSE)) - { - delete select; - free_underlaid_joins(thd, select_lex); - DBUG_RETURN(TRUE); - } - } + error= init_read_record(&info, thd, table, select, 1, 1, FALSE); else - init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse); + error= init_read_record_idx(&info, thd, table, 1, query_plan.index, + reverse); + if (error) + { + delete select; + free_underlaid_joins(thd, select_lex); + DBUG_RETURN(TRUE); + } init_ftfuncs(thd, select_lex, 1); THD_STAGE_INFO(thd, stage_updating); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 03d8e0205ff..2a39e4a1f5e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -459,7 +459,8 @@ int mysql_update(THD *thd, query_plan.scanned_rows= select? select->records: table->file->stats.records; if (select && select->quick && select->quick->unique_key_range()) - { // Single row select (always "ordered"): Ok to use with key field UPDATE + { + /* Single row select (always "ordered"): Ok to use with key field UPDATE */ need_sort= FALSE; query_plan.index= MAX_KEY; used_key_is_modified= FALSE; @@ -468,7 +469,8 @@ int mysql_update(THD *thd, { ha_rows scanned_limit= query_plan.scanned_rows; query_plan.index= get_index_for_order(order, table, select, limit, - &scanned_limit, &need_sort, &reverse); + &scanned_limit, &need_sort, + &reverse); if (!need_sort) query_plan.scanned_rows= scanned_limit; @@ -481,12 +483,15 @@ int mysql_update(THD *thd, else { if (need_sort) - { // Assign table scan index to check below for modified key fields: + { + /* Assign table scan index to check below for modified key fields: */ query_plan.index= table->file->key_used_on_scan; } if (query_plan.index != MAX_KEY) - { // Check if we are modifying a key that we are used to search with: - used_key_is_modified= is_key_used(table, query_plan.index, table->write_set); + { + /* Check if we are modifying a key that we are used to search with: */ + used_key_is_modified= is_key_used(table, query_plan.index, + table->write_set); } } } @@ -597,19 +602,20 @@ int mysql_update(THD *thd, B. query_plan.index != MAX_KEY B.1 quick select is used, start the scan with init_read_record B.2 quick select is not used, this is full index scan (with LIMIT) - Full index scan must be started with init_read_record_idx + Full index scan must be started with init_read_record_idx */ if (query_plan.index == MAX_KEY || (select && select->quick)) - { - if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) - { - close_cached_file(&tempfile); - goto err; - } - } + error= init_read_record(&info, thd, table, select, 0, 1, FALSE); else - init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse); + error= init_read_record_idx(&info, thd, table, 1, query_plan.index, + reverse); + + if (error) + { + close_cached_file(&tempfile); + goto err; + } THD_STAGE_INFO(thd, stage_searching_rows_for_update); ha_rows tmp_limit= limit;