diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 75c732c44d4..2afacf6d2a8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -189,7 +189,7 @@ innobase_index_name_is_reserved( /*============================*/ /* out: true if index name matches a reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ + THD* thd, /* in/out: MySQL connection */ const TABLE* form, /* in: information on table columns and indexes */ const char* norm_name); /* in: table name */ @@ -5285,10 +5285,6 @@ create_table_def( DBUG_PRINT("enter", ("table_name: %s", table_name)); ut_a(trx->mysql_thd != NULL); - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, - (THD*) trx->mysql_thd)) { - DBUG_RETURN(HA_ERR_GENERIC); - } n_cols = form->s->fields; @@ -5397,6 +5393,8 @@ err_col: col_len); } + srv_lower_case_table_names = lower_case_table_names; + error = row_create_table_for_mysql(table, trx); innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error); @@ -5642,6 +5640,35 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } + strcpy(name2, name); + + normalize_table_name(norm_name, name2); + + /* Create the table definition in InnoDB */ + + flags = form->s->row_type != ROW_TYPE_REDUNDANT ? DICT_TF_COMPACT : 0; + + /* Look for a primary key */ + + primary_key_no= (form->s->primary_key != MAX_KEY ? + (int) form->s->primary_key : + -1); + + /* Our function row_get_mysql_key_number_for_index assumes + the primary key is always number 0, if it exists */ + + DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); + + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(thd, form, norm_name)) { + DBUG_RETURN(-1); + } + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); + } + /* Get the transaction associated with the current thd, or create one if not yet created */ @@ -5665,48 +5692,12 @@ ha_innobase::create( trx->check_unique_secondary = FALSE; } - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - - strcpy(name2, name); - - normalize_table_name(norm_name, name2); - /* Latch the InnoDB data dictionary exclusively so that no deadlocks or lock waits can happen in it during a table create operation. Drop table etc. do this latching in row0mysql.c. */ row_mysql_lock_data_dictionary(trx); - /* Create the table definition in InnoDB */ - - flags = 0; - - if (form->s->row_type != ROW_TYPE_REDUNDANT) { - flags |= DICT_TF_COMPACT; - } - - /* Look for a primary key */ - - primary_key_no= (form->s->primary_key != MAX_KEY ? - (int) form->s->primary_key : - -1); - - /* Our function row_get_mysql_key_number_for_index assumes - the primary key is always number 0, if it exists */ - - DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); - - /* Check for name conflicts (with reserved name) for - any user indices to be created. */ - if (innobase_index_name_is_reserved(trx, form, norm_name)) { - error = -1; - goto cleanup; - } - error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -5936,12 +5927,6 @@ ha_innobase::delete_table( trx_search_latch_release_if_reserved(parent_trx); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; @@ -5961,6 +5946,8 @@ ha_innobase::delete_table( /* Drop the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); @@ -6089,12 +6076,6 @@ ha_innobase::rename_table( trx_search_latch_release_if_reserved(parent_trx); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; INNOBASE_COPY_STMT(thd, trx); @@ -6114,6 +6095,8 @@ ha_innobase::rename_table( /* Rename the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_rename_table_for_mysql(norm_from, norm_to, trx); /* Flush the log to reduce probability that the .frm files and @@ -8826,7 +8809,7 @@ innobase_index_name_is_reserved( /*============================*/ /* out: true if an index name matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ + THD* thd, /* in/out: MySQL connection */ const TABLE* form, /* in: information on table columns and indexes */ const char* norm_name) /* in: table name */ @@ -8840,7 +8823,7 @@ innobase_index_name_is_reserved( if (innobase_strcasecmp(key->name, innobase_index_reserve_name) == 0) { /* Push warning to mysql */ - push_warning_printf((THD*) trx->mysql_thd, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_CANT_CREATE_TABLE, "Cannot Create Index with name " diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index d062fc7e648..0b201816819 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-04-07 The InnoDB Team + + * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: + Fix Bug #52409 Assertion failure: long semaphore wait + 2011-04-07 The InnoDB Team * handler/ha_innodb.cc, include/trx0trx.h, include/trx0undo.h, diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 7f92d797d30..2b0dbf82b34 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -6023,10 +6023,6 @@ create_table_def( DBUG_PRINT("enter", ("table_name: %s", table_name)); ut_a(trx->mysql_thd != NULL); - if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, - (THD*) trx->mysql_thd)) { - DBUG_RETURN(HA_ERR_GENERIC); - } /* MySQL does the name length check. But we do additional check on the name length here */ @@ -6146,6 +6142,8 @@ err_col: col_len); } + srv_lower_case_table_names = lower_case_table_names; + error = row_create_table_for_mysql(table, trx); if (error == DB_DUPLICATE_KEY) { @@ -6562,42 +6560,17 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } - /* Get the transaction associated with the current thd, or create one - if not yet created */ - - parent_trx = check_trx_exists(thd); - - /* In case MySQL calls this in the middle of a SELECT query, release - possible adaptive hash latch to avoid deadlocks of threads */ - - trx_search_latch_release_if_reserved(parent_trx); - - trx = innobase_trx_allocate(thd); - - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - strcpy(name2, name); normalize_table_name(norm_name, name2); - /* Latch the InnoDB data dictionary exclusively so that no deadlocks - or lock waits can happen in it during a table create operation. - Drop table etc. do this latching in row0mysql.c. */ - - row_mysql_lock_data_dictionary(trx); - /* Create the table definition in InnoDB */ flags = 0; /* Validate create options if innodb_strict_mode is set. */ if (!create_options_are_valid(thd, form, create_info)) { - error = ER_ILLEGAL_HA_CREATE_OPTION; - goto cleanup; + DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION); } if (create_info->key_block_size) { @@ -6739,16 +6712,37 @@ ha_innobase::create( /* Check for name conflicts (with reserved name) for any user indices to be created. */ - if (innobase_index_name_is_reserved(trx, form->key_info, + if (innobase_index_name_is_reserved(thd, form->key_info, form->s->keys)) { - error = -1; - goto cleanup; + DBUG_RETURN(-1); + } + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); } if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT; } + /* Get the transaction associated with the current thd, or create one + if not yet created */ + + parent_trx = check_trx_exists(thd); + + /* In case MySQL calls this in the middle of a SELECT query, release + possible adaptive hash latch to avoid deadlocks of threads */ + + trx_search_latch_release_if_reserved(parent_trx); + + trx = innobase_trx_allocate(thd); + + /* Latch the InnoDB data dictionary exclusively so that no deadlocks + or lock waits can happen in it during a table create operation. + Drop table etc. do this latching in row0mysql.c. */ + + row_mysql_lock_data_dictionary(trx); + error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -6992,18 +6986,14 @@ ha_innobase::delete_table( trx = innobase_trx_allocate(thd); - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - name_len = strlen(name); ut_a(name_len < 1000); /* Drop the table in InnoDB */ + srv_lower_case_table_names = lower_case_table_names; + error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); @@ -7119,12 +7109,6 @@ innobase_rename_table( char* norm_to; char* norm_from; - if (lower_case_table_names) { - srv_lower_case_table_names = TRUE; - } else { - srv_lower_case_table_names = FALSE; - } - // Magic number 64 arbitrary norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0)); norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0)); @@ -7139,6 +7123,8 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); } + srv_lower_case_table_names = lower_case_table_names; + error = row_rename_table_for_mysql( norm_from, norm_to, trx, lock_and_commit); @@ -10700,19 +10686,19 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } -/*********************************************************************** +/*********************************************************************//** This function checks each index name for a table against reserved -system default primary index name 'GEN_CLUST_INDEX'. If a name matches, -this function pushes an warning message to the client, and returns true. */ +system default primary index name 'GEN_CLUST_INDEX'. If a name +matches, this function pushes an warning message to the client, +and returns true. +@return true if the index name matches the reserved name */ extern "C" UNIV_INTERN bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if an index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys) /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys) /*!< in: Number of indexes to be created. */ { const KEY* key; @@ -10724,7 +10710,7 @@ innobase_index_name_is_reserved( if (innobase_strcasecmp(key->name, innobase_index_reserve_name) == 0) { /* Push warning to mysql */ - push_warning_printf((THD*) trx->mysql_thd, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_NAME_FOR_INDEX, "Cannot Create Index with name " diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index 7a8f29853de..f7a5456b1a7 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -317,15 +317,14 @@ innobase_trx_allocate( This function checks each index name for a table against reserved system default primary index name 'GEN_CLUST_INDEX'. If a name matches, this function pushes an warning message to the client, -and returns true. */ +and returns true. +@return true if the index name matches the reserved name */ extern "C" bool innobase_index_name_is_reserved( /*============================*/ - /* out: true if the index name - matches the reserved name */ - const trx_t* trx, /* in: InnoDB transaction handle */ - const KEY* key_info, /* in: Indexes to be created */ - ulint num_of_keys); /* in: Number of indexes to + THD* thd, /*!< in/out: MySQL connection */ + const KEY* key_info, /*!< in: Indexes to be created */ + ulint num_of_keys); /*!< in: Number of indexes to be created. */ diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index dc1317d5c5a..485e03737e3 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -649,11 +649,30 @@ ha_innobase::add_index( update_thd(); - heap = mem_heap_create(1024); - /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads. */ trx_search_latch_release_if_reserved(prebuilt->trx); + + /* Check if the index name is reserved. */ + if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) { + DBUG_RETURN(-1); + } + + innodb_table = indexed_table + = dict_table_get(prebuilt->table->name, FALSE); + + if (UNIV_UNLIKELY(!innodb_table)) { + DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); + } + + /* Check that index keys are sensible */ + error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); + + if (UNIV_UNLIKELY(error)) { + DBUG_RETURN(error); + } + + heap = mem_heap_create(1024); trx_start_if_not_started(prebuilt->trx); /* Create a background transaction for the operations on @@ -661,32 +680,6 @@ ha_innobase::add_index( trx = innobase_trx_allocate(user_thd); trx_start_if_not_started(trx); - innodb_table = indexed_table - = dict_table_get(prebuilt->table->name, FALSE); - - if (UNIV_UNLIKELY(!innodb_table)) { - error = HA_ERR_NO_SUCH_TABLE; - goto err_exit; - } - - /* Check if the index name is reserved. */ - if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { - error = -1; - } else { - /* Check that index keys are sensible */ - error = innobase_check_index_keys(key_info, num_of_keys, - innodb_table); - } - - if (UNIV_UNLIKELY(error)) { -err_exit: - mem_heap_free(heap); - trx_general_rollback_for_mysql(trx, NULL); - trx_free_for_mysql(trx); - trx_commit_for_mysql(prebuilt->trx); - DBUG_RETURN(error); - } - /* Create table containing all indexes to be built in this alter table add index so that they are in the correct order in the table. */ @@ -758,8 +751,12 @@ err_exit: ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE)); + mem_heap_free(heap); + trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); - goto err_exit; + trx_free_for_mysql(trx); + trx_commit_for_mysql(prebuilt->trx); + DBUG_RETURN(error); } trx->table_id = indexed_table->id;