From 100dd45ec45c7bf6394a1ea0cc2fc865400c4ae3 Mon Sep 17 00:00:00 2001 From: "andrey@example.com" <> Date: Tue, 28 Nov 2006 18:27:32 +0100 Subject: [PATCH 1/3] Fix for bug#24395: ALTER TABLE DISABLE KEYS doesn't work when modifying the table ENABLE|DISABLE KEYS combined with another ALTER TABLE option, different than RENAME TO did nothing. Also, if the table had disabled keys and was ALTER-ed then the end table was with enabled keys. Fixed by checking whether the table had disabled keys and enabling them in the copied table. --- myisam/mi_open.c | 21 +++++- mysql-test/r/alter_table.result | 121 ++++++++++++++++++++++++++++++++ mysql-test/t/alter_table.test | 97 +++++++++++++++++++++++++ sql/sql_table.cc | 73 +++++++++++++++++-- 4 files changed, 304 insertions(+), 8 deletions(-) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 4f298397615..db15f39c84a 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -1233,13 +1233,30 @@ int mi_enable_indexes(MI_INFO *info) RETURN 0 indexes are not disabled 1 all indexes are disabled - [2 non-unique indexes are disabled - NOT YET IMPLEMENTED] + 2 non-unique indexes are disabled */ int mi_indexes_are_disabled(MI_INFO *info) { MYISAM_SHARE *share= info->s; - return (! share->state.key_map && share->base.keys); + /* + No keys or all are enabled. keys is the number of keys. Left shifted + gives us only one bit set. When decreased by one, gives us all all bits + up to this one set and it gets unset. + */ + if (!share->base.keys || + (share->state.key_map == (ULL(1) << share->base.keys) - ULL(1))) + return 0; + + /* All are disabled */ + if (!share->state.key_map) + return 1; + + /* + We have keys. Some enabled, some disabled. + Don't check for any non-unique disabled but return directly 2 + */ + return 2; } diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index eade19e85df..6c670af88a2 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -528,6 +528,127 @@ create table t1 ( a timestamp ); alter table t1 add unique ( a(1) ); ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys drop table t1; +drop table if exists t1; +create table t1 (a int, key(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this used not to disable the index" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 add b char(10), disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 add c decimal(10,2), enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this however did" +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +desc t1; +Field Type Null Key Default Extra +a bigint(20) YES MUL NULL +b char(10) YES NULL +c decimal(10,2) YES NULL +alter table t1 add d decimal(15,5); +"The key should still be disabled" +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +drop table t1; +"Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"Unique index, no change" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +"Change the type implying data copy" +"Unique index, no change" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a bigint; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +drop table t1; +"Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"The non-unique index will be disabled" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +"Change the type implying data copy" +"The non-unique index will be disabled" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +"Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +"Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +drop table t1; create database mysqltest1; create table t1 (c1 int); alter table t1 rename mysqltest1.t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index eba456982c8..f4624eda053 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -361,6 +361,103 @@ create table t1 ( a timestamp ); alter table t1 add unique ( a(1) ); drop table t1; +# +# Bug #24395: ALTER TABLE DISABLE KEYS doesn't work when modifying the table +# +# This problem happens if the data change is compatible. +# Changing to the same type is compatible for example. +# +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int, key(a)); +show indexes from t1; +--echo "this used not to disable the index" +alter table t1 modify a int, disable keys; +show indexes from t1; + +alter table t1 enable keys; +show indexes from t1; + +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +alter table t1 enable keys; +show indexes from t1; + +alter table t1 add b char(10), disable keys; +show indexes from t1; + +alter table t1 add c decimal(10,2), enable keys; +show indexes from t1; + +--echo "this however did" +alter table t1 disable keys; +show indexes from t1; + +desc t1; + +alter table t1 add d decimal(15,5); +--echo "The key should still be disabled" +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +alter table t1 disable keys; +show indexes from t1; +alter table t1 enable keys; + +--echo "If no copy on noop change, this won't touch the data file" +--echo "Unique index, no change" +alter table t1 modify a int, disable keys; +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "Unique index, no change" +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +alter table t1 modify a bigint; +show indexes from t1; + +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +alter table t1 disable keys; +show indexes from t1; +alter table t1 enable keys; + + +--echo "If no copy on noop change, this won't touch the data file" +--echo "The non-unique index will be disabled" +alter table t1 modify a int, disable keys; +show indexes from t1; +alter table t1 enable keys; +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "The non-unique index will be disabled" +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +--echo "Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +--echo "Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + + # # Bug#11493 - Alter table rename to default database does not work without # db name qualifying diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 256b9281e9f..f82dd627101 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -34,11 +34,12 @@ const char *primary_key_name="PRIMARY"; static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end); static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end); static int copy_data_between_tables(TABLE *from,TABLE *to, - List &create, - enum enum_duplicates handle_duplicates, + List &create, + enum enum_duplicates handle_duplicates, bool ignore, - uint order_num, ORDER *order, - ha_rows *copied,ha_rows *deleted); + uint order_num, ORDER *order, + ha_rows *copied, ha_rows *deleted, + enum enum_enable_or_disable keys_onoff); /* @@ -2836,6 +2837,54 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list, #endif /* NOT_USED */ +/* + Manages enabling/disabling of indexes for ALTER TABLE + + SYNOPSIS + alter_table_manage_keys() + table Target table + indexes_were_disabled Whether the indexes of the from table + were disabled + keys_onoff ENABLE | DISABLE | LEAVE_AS_IS + + RETURN VALUES + FALSE OK + TRUE Error +*/ + +static +bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, + enum enum_enable_or_disable keys_onoff) +{ + int error= 0; + DBUG_ENTER("alter_table_manage_keys"); + DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d", + table, indexes_were_disabled, keys_onoff)); + + switch (keys_onoff) { + case ENABLE: + error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + break; + case LEAVE_AS_IS: + if (!indexes_were_disabled) + break; + /* fall-through: disabled indexes */ + case DISABLE: + error= table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + } + + if (error == HA_ERR_WRONG_COMMAND) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->table_name); + error= 0; + } else if (error) + table->file->print_error(error, MYF(0)); + + DBUG_RETURN(error); +} + + /* Alter table */ @@ -3375,7 +3424,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!new_table->is_view) error=copy_data_between_tables(table,new_table,create_list, handle_duplicates, ignore, - order_num, order, &copied, &deleted); + order_num, order, &copied, &deleted, + alter_info->keys_onoff); + /* + No need to have call to alter_table_manage_keys() in the else because + in 4.1 we always copy data, except for views. In 5.0 it could happen + that no data is copied and only frm is modified. Then we have to handle + alter_info->keys_onoff outside of copy_data_between_tables + */ thd->last_insert_id=next_insert_id; // Needed for correct log thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -3598,7 +3654,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, bool ignore, uint order_num, ORDER *order, ha_rows *copied, - ha_rows *deleted) + ha_rows *deleted, + enum enum_enable_or_disable keys_onoff) { int error; Copy_field *copy,*copy_end; @@ -3630,6 +3687,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (to->file->external_lock(thd, F_WRLCK)) DBUG_RETURN(-1); + + /* We need external lock before we can disable/enable keys */ + alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); + from->file->info(HA_STATUS_VARIABLE); to->file->start_bulk_insert(from->file->records); From b4575723852ba85feb165c18577d91bc7a94065a Mon Sep 17 00:00:00 2001 From: "iggy@rolltop.ignatz42.dyndns.org" <> Date: Thu, 30 Nov 2006 21:04:02 -0500 Subject: [PATCH 2/3] Bug#17951: myisampack --force --silent : abnormal end in Windows XP -myisampack wrote to a block on the heap that it did not allocate. --- myisam/myisampack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/myisam/myisampack.c b/myisam/myisampack.c index e80a3ffacd9..4582044009f 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -2922,6 +2922,8 @@ static void flush_bits(void) bits-= 8; *file_buffer.pos++= (uchar) (bit_buffer >> bits); } + if (file_buffer.pos >= file_buffer.end) + VOID(flush_buffer(~ (ulong) 0)); file_buffer.bits= BITS_SAVED; file_buffer.bitbucket= 0; } From b201d4ef9382429b32c2da56121754014e48de01 Mon Sep 17 00:00:00 2001 From: "thek@kpdesk.mysql.com" <> Date: Fri, 1 Dec 2006 12:50:57 +0100 Subject: [PATCH 3/3] Bug#22043 MySQL don't add "USE " before "DROP PROCEDURE IF EXISTS" - Refactoring of duplicate code - Modified bad test cases - Changed expected error when operating on information_schema. --- mysql-test/r/information_schema.result | 2 +- mysql-test/r/rpl_sp.result | 21 ++--- mysql-test/t/information_schema.test | 2 +- mysql-test/t/rpl_sp.test | 3 +- sql/sql_parse.cc | 125 ++++++++++--------------- 5 files changed, 64 insertions(+), 89 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 3fffce73aa9..4de6e3c823d 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1027,7 +1027,7 @@ CREATE PROCEDURE p1 () BEGIN SELECT 'foo' FROM DUAL; END | -ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' +ERROR 42000: Unknown database 'information_schema' select ROUTINE_NAME from routines; ROUTINE_NAME grant all on information_schema.* to 'user1'@'localhost'; diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index d6f9880de17..5c35cd8097f 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -465,6 +465,7 @@ RETURN 0 DROP PROCEDURE p1; DROP FUNCTION f1; drop table t1; +reset master; drop database if exists mysqltest; drop database if exists mysqltest2; create database mysqltest; @@ -473,19 +474,15 @@ use mysqltest2; create table t ( t integer ); create procedure mysqltest.test() begin end; insert into t values ( 1 ); -show binlog events in 'master-bin.000001' from 8186; +show binlog events in 'master-bin.000001' from 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 8186 Query 1 8317 use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION f1() RETURNS INT RETURN 0 -master-bin.000001 8317 Query 1 8397 use `test`; DROP PROCEDURE p1 -master-bin.000001 8397 Query 1 8476 use `test`; DROP FUNCTION f1 -master-bin.000001 8476 Query 1 8552 use `test`; drop table t1 -master-bin.000001 8552 Query 1 8653 drop database if exists mysqltest -master-bin.000001 8653 Query 1 8756 drop database if exists mysqltest2 -master-bin.000001 8756 Query 1 8849 create database mysqltest -master-bin.000001 8849 Query 1 8944 create database mysqltest2 -master-bin.000001 8944 Query 1 9041 use `mysqltest2`; create table t ( t integer ) -master-bin.000001 9041 Query 1 9180 use `mysqltest2`; CREATE DEFINER=`root`@`localhost` procedure mysqltest.test() begin end -master-bin.000001 9180 Query 1 9275 use `mysqltest2`; insert into t values ( 1 ) +master-bin.000001 98 Query 1 199 drop database if exists mysqltest +master-bin.000001 199 Query 1 302 drop database if exists mysqltest2 +master-bin.000001 302 Query 1 395 create database mysqltest +master-bin.000001 395 Query 1 490 create database mysqltest2 +master-bin.000001 490 Query 1 587 use `mysqltest2`; create table t ( t integer ) +master-bin.000001 587 Query 1 726 use `mysqltest2`; CREATE DEFINER=`root`@`localhost` procedure mysqltest.test() begin end +master-bin.000001 726 Query 1 821 use `mysqltest2`; insert into t values ( 1 ) create procedure `\\`.test() begin end; ERROR 42000: Incorrect database name '\\' drop database mysqltest; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 27007bbe16a..18e5faf7178 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -715,7 +715,7 @@ create temporary table schemata(f1 char(10)); # Bug #10708 SP's can use INFORMATION_SCHEMA as ROUTINE_SCHEMA # delimiter |; ---error 1044 +--error ER_BAD_DB_ERROR CREATE PROCEDURE p1 () BEGIN SELECT 'foo' FROM DUAL; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index b7a9036908c..5dc4ba5a4db 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -524,6 +524,7 @@ sync_slave_with_master; # Bug22043: MySQL don't add "USE " before "DROP PROCEDURE IF EXISTS" # connection master; +reset master; --disable_warnings drop database if exists mysqltest; drop database if exists mysqltest2; @@ -534,7 +535,7 @@ use mysqltest2; create table t ( t integer ); create procedure mysqltest.test() begin end; insert into t values ( 1 ); -show binlog events in 'master-bin.000001' from 8186; +show binlog events in 'master-bin.000001' from 98; --error ER_WRONG_DB_NAME create procedure `\\`.test() begin end; # Clean up diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2feaebdde25..434ba3aa94f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4221,11 +4221,10 @@ end_with_restore_list: { uint namelen; char *name; - int result; + int result= SP_INTERNAL_ERROR; DBUG_ASSERT(lex->sphead != 0); DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ - /* Verify that the database name is allowed, optionally lowercase it. @@ -4233,37 +4232,26 @@ end_with_restore_list: if (check_db_name(lex->sphead->m_db.str)) { my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); - delete lex->sphead; - lex->sphead= 0; - goto error; + goto create_sp_error; } /* - Check that a database with this name - exists. + Check that a database directory with this name + exists. Design note: This won't work on virtual databases + like information_schema. */ if (check_db_dir_existence(lex->sphead->m_db.str)) { my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); - delete lex->sphead; - lex->sphead= 0; - goto error; + goto create_sp_error; } if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0, is_schema_db(lex->sphead->m_db.str))) - { - delete lex->sphead; - lex->sphead= 0; - goto error; - } + goto create_sp_error; - if (end_active_trans(thd)) - { - delete lex->sphead; - lex->sphead= 0; - goto error; - } + if (end_active_trans(thd)) + goto create_sp_error; name= lex->sphead->name(&namelen); #ifdef HAVE_DLOPEN @@ -4273,10 +4261,8 @@ end_with_restore_list: if (udf) { - my_error(ER_UDF_EXISTS, MYF(0), name); - delete lex->sphead; - lex->sphead= 0; - goto error; + my_error(ER_UDF_EXISTS, MYF(0), name); + goto create_sp_error; } } #endif @@ -4284,7 +4270,7 @@ end_with_restore_list: /* If the definer is not specified, this means that CREATE-statement missed DEFINER-clause. DEFINER-clause can be missed in two cases: - + - The user submitted a statement w/o the clause. This is a normal case, we should assign CURRENT_USER as definer. @@ -4293,7 +4279,7 @@ end_with_restore_list: CURRENT_USER as definer here, but also we should mark this routine as NON-SUID. This is essential for the sake of backward compatibility. - + The problem is the slave thread is running under "special" user (@), that actually does not exist. In the older versions we do not fail execution of a stored routine if its definer does not exist and @@ -4318,13 +4304,9 @@ end_with_restore_list: if (ps_arena) thd->restore_active_arena(ps_arena, &original_arena); + /* Error has been already reported. */ if (res) - { - /* Error has been already reported. */ - delete lex->sphead; - lex->sphead= 0; - goto error; - } + goto create_sp_error; if (thd->slave_thread) lex->sphead->m_chistics->suid= SP_IS_NOT_SUID; @@ -4335,7 +4317,7 @@ end_with_restore_list: that the current user has SUPER privilege (in order to create a stored routine under another user one must have SUPER privilege). */ - + else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) || my_strcasecmp(system_charset_info, lex->definer->host.str, @@ -4344,9 +4326,7 @@ end_with_restore_list: if (check_global_access(thd, SUPER_ACL)) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); - delete lex->sphead; - lex->sphead= 0; - goto error; + goto create_sp_error; } } @@ -4366,54 +4346,51 @@ end_with_restore_list: #endif /* NO_EMBEDDED_ACCESS_CHECKS */ res= (result= lex->sphead->create(thd)); - if (result == SP_OK) - { + switch (result) { + case SP_OK: #ifndef NO_EMBEDDED_ACCESS_CHECKS /* only add privileges if really neccessary */ if (sp_automatic_privileges && !opt_noacl && check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, - lex->sphead->m_db.str, name, + lex->sphead->m_db.str, name, lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) { - close_thread_tables(thd); if (sp_grant_privileges(thd, lex->sphead->m_db.str, name, lex->sql_command == SQLCOM_CREATE_PROCEDURE)) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_PROC_AUTO_GRANT_FAIL, - ER(ER_PROC_AUTO_GRANT_FAIL)); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_PROC_AUTO_GRANT_FAIL, + ER(ER_PROC_AUTO_GRANT_FAIL)); + close_thread_tables(thd); } #endif - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - send_ok(thd); - } - else - { - switch (result) { - case SP_WRITE_ROW_FAILED: - my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); - break; - case SP_NO_DB_ERROR: - my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); - break; - case SP_BAD_IDENTIFIER: - my_error(ER_TOO_LONG_IDENT, MYF(0), name); - break; - case SP_BODY_TOO_LONG: - my_error(ER_TOO_LONG_BODY, MYF(0), name); - break; - default: - my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); - break; - } - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - } break; - } + case SP_WRITE_ROW_FAILED: + my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); + break; + case SP_BAD_IDENTIFIER: + my_error(ER_TOO_LONG_IDENT, MYF(0), name); + break; + case SP_BODY_TOO_LONG: + my_error(ER_TOO_LONG_BODY, MYF(0), name); + break; + default: + my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); + break; + } /* end switch */ + + /* + Capture all errors within this CASE and + clean up the environment. + */ +create_sp_error: + lex->unit.cleanup(); + delete lex->sphead; + lex->sphead= 0; + if (result != SP_OK ) + goto error; + send_ok(thd); + break; /* break super switch */ + } /* end case group bracket */ case SQLCOM_CALL: { sp_head *sp;