diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 94d33f8090b..8882b95f2d8 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -638,3 +638,15 @@ No Field Count 0 1 100 0 2 100 drop table t1, t2; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +NO int(11) NOT NULL default '0', +SEQ int(11) NOT NULL default '0', +PRIMARY KEY (ID), +KEY t1$NO (SEQ,NO) +) ENGINE=MyISAM; +INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1 AS NO FROM t1 WHERE (SEQ = 1); +select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1); +ID NO SEQ +1 1 1 +drop table t1; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 15509b06679..a5b163b3533 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -180,3 +180,18 @@ insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2 select * from t2; drop table t1, t2; + +# +# BUG#6034 - Error code 124: Wrong medium type +# +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NO int(11) NOT NULL default '0', + SEQ int(11) NOT NULL default '0', + PRIMARY KEY (ID), + KEY t1$NO (SEQ,NO) +) ENGINE=MyISAM; +INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1 AS NO FROM t1 WHERE (SEQ = 1); +select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1); +drop table t1; + diff --git a/sql/sql_class.h b/sql/sql_class.h index ca65f011b9d..8e6204ab3a3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1280,6 +1280,7 @@ public: unit= u; return 0; } + virtual int prepare2(void) { return 0; } /* Because of peculiarities of prepared statements protocol we need to know number of columns in the result set (if @@ -1379,6 +1380,7 @@ class select_insert :public select_result_interceptor { enum_duplicates duplic, bool ignore); ~select_insert(); int prepare(List &list, SELECT_LEX_UNIT *u); + int prepare2(void); bool send_data(List &items); virtual void store_values(List &values); void send_error(uint errcode,const char *err); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ceb31f76953..4cb62d5e9d7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1802,13 +1802,22 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) thd->lex->current_select->options|= OPTION_BUFFER_RESULT; thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT; } - + else + { + /* + We must not yet prepare the result table if it is the same as one of the + source tables (INSERT SELECT). The preparation may disable + indexes on the result table, which may be used during the select, if it + is the same table (Bug #6034). Do the preparation after the select phase + in select_insert::prepare2(). + */ + if (info.ignore || info.handle_duplicates != DUP_ERROR) + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + table->file->start_bulk_insert((ha_rows) 0); + } restore_record(table,s->default_values); // Get empty record table->next_number_field=table->found_next_number_field; thd->cuted_fields=0; - if (info.ignore || info.handle_duplicates != DUP_ERROR) - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - table->file->start_bulk_insert((ha_rows) 0); thd->no_trans_update= 0; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & @@ -1819,6 +1828,36 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) } +/* + Finish the preparation of the result table. + + SYNOPSIS + select_insert::prepare2() + void + + DESCRIPTION + If the result table is the same as one of the source tables (INSERT SELECT), + the result table is not finally prepared at the join prepair phase. + Do the final preparation now. + + RETURN + 0 OK +*/ + +int select_insert::prepare2(void) +{ + DBUG_ENTER("select_insert::prepare2"); + + if (thd->lex->current_select->options & OPTION_BUFFER_RESULT) + { + if (info.ignore || info.handle_duplicates != DUP_ERROR) + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + table->file->start_bulk_insert((ha_rows) 0); + } + return 0; +} + + void select_insert::cleanup() { /* select_insert/select_create are never re-used in prepared statement */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 94a2390324c..0fc4616749c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1164,6 +1164,7 @@ JOIN::exec() DBUG_VOID_RETURN; } } + (void) result->prepare2(); // Currently, this cannot fail. if (!tables_list) { // Only test of functions @@ -13149,7 +13150,8 @@ bool JOIN::change_result(select_result *res) { DBUG_ENTER("JOIN::change_result"); result= res; - if (!procedure && result->prepare(fields_list, select_lex->master_unit())) + if (!procedure && (result->prepare(fields_list, select_lex->master_unit()) || + result->prepare2())) { DBUG_RETURN(TRUE); }