Commit d546d1cc authored by Monty's avatar Monty

Fixed MDEV-8408

Assertion `inited==INDEX' failed in int handler::ha_index_first(uchar*)

The crash was because errors from init_read_record_idx() was not taken care of.
parent df8832ca
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;
--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;
...@@ -66,10 +66,12 @@ static int rr_index_desc(READ_RECORD *info); ...@@ -66,10 +66,12 @@ static int rr_index_desc(READ_RECORD *info);
@param reverse Scan in the reverse direction @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) bool print_error, uint idx, bool reverse)
{ {
int error; int error;
DBUG_ENTER("init_read_record_idx");
empty_record(table); empty_record(table);
bzero((char*) info,sizeof(*info)); bzero((char*) info,sizeof(*info));
info->thd= thd; info->thd= thd;
...@@ -88,6 +90,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, ...@@ -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 */ /* read_record will be changed to rr_index in rr_index_first */
info->read_record= reverse ? rr_index_last : rr_index_first; info->read_record= reverse ? rr_index_last : rr_index_first;
DBUG_RETURN(error != 0);
} }
......
...@@ -76,7 +76,7 @@ public: ...@@ -76,7 +76,7 @@ public:
bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select, int use_record_cache, SQL_SELECT *select, int use_record_cache,
bool print_errors, bool disable_rr_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); bool print_error, uint idx, bool reverse);
void end_read_record(READ_RECORD *info); void end_read_record(READ_RECORD *info);
......
...@@ -508,17 +508,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -508,17 +508,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (query_plan.index == MAX_KEY || (select && select->quick)) if (query_plan.index == MAX_KEY || (select && select->quick))
error= init_read_record(&info, thd, table, select, 1, 1, FALSE);
else
error= init_read_record_idx(&info, thd, table, 1, query_plan.index,
reverse);
if (error)
{ {
if (init_read_record(&info, thd, table, select, 1, 1, FALSE)) delete select;
{ free_underlaid_joins(thd, select_lex);
delete select; DBUG_RETURN(TRUE);
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(TRUE);
}
} }
else
init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse);
init_ftfuncs(thd, select_lex, 1); init_ftfuncs(thd, select_lex, 1);
THD_STAGE_INFO(thd, stage_updating); THD_STAGE_INFO(thd, stage_updating);
......
...@@ -459,7 +459,8 @@ int mysql_update(THD *thd, ...@@ -459,7 +459,8 @@ int mysql_update(THD *thd,
query_plan.scanned_rows= select? select->records: table->file->stats.records; query_plan.scanned_rows= select? select->records: table->file->stats.records;
if (select && select->quick && select->quick->unique_key_range()) 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; need_sort= FALSE;
query_plan.index= MAX_KEY; query_plan.index= MAX_KEY;
used_key_is_modified= FALSE; used_key_is_modified= FALSE;
...@@ -468,7 +469,8 @@ int mysql_update(THD *thd, ...@@ -468,7 +469,8 @@ int mysql_update(THD *thd,
{ {
ha_rows scanned_limit= query_plan.scanned_rows; ha_rows scanned_limit= query_plan.scanned_rows;
query_plan.index= get_index_for_order(order, table, select, limit, query_plan.index= get_index_for_order(order, table, select, limit,
&scanned_limit, &need_sort, &reverse); &scanned_limit, &need_sort,
&reverse);
if (!need_sort) if (!need_sort)
query_plan.scanned_rows= scanned_limit; query_plan.scanned_rows= scanned_limit;
...@@ -481,12 +483,15 @@ int mysql_update(THD *thd, ...@@ -481,12 +483,15 @@ int mysql_update(THD *thd,
else else
{ {
if (need_sort) 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; query_plan.index= table->file->key_used_on_scan;
} }
if (query_plan.index != MAX_KEY) 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, ...@@ -597,19 +602,20 @@ int mysql_update(THD *thd,
B. query_plan.index != MAX_KEY B. query_plan.index != MAX_KEY
B.1 quick select is used, start the scan with init_read_record 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) 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 (query_plan.index == MAX_KEY || (select && select->quick))
error= init_read_record(&info, thd, table, select, 0, 1, FALSE);
else
error= init_read_record_idx(&info, thd, table, 1, query_plan.index,
reverse);
if (error)
{ {
if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) close_cached_file(&tempfile);
{ goto err;
close_cached_file(&tempfile);
goto err;
}
} }
else
init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse);
THD_STAGE_INFO(thd, stage_searching_rows_for_update); THD_STAGE_INFO(thd, stage_searching_rows_for_update);
ha_rows tmp_limit= limit; ha_rows tmp_limit= limit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment