From ea8882be8060998510308c2528ce80229759edf1 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Wed, 19 Jan 2005 21:20:55 +0100 Subject: [PATCH] BUG#6034 - Error code 124: Wrong medium type. Version for 5.0. Committed for merge. If the result table is one of the select tables in INSERT SELECT, we must not disable the result tables indexes before selecting. Now the preparation is split into two prepare methods. The first detects the situation and defers some preparations until the second phase. --- mysql-test/r/insert_select.result | 12 ++++++++ mysql-test/t/insert_select.test | 15 ++++++++++ sql/sql_class.h | 2 ++ sql/sql_insert.cc | 47 ++++++++++++++++++++++++++++--- sql/sql_select.cc | 4 ++- 5 files changed, 75 insertions(+), 5 deletions(-) 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); }