From be8f5a6b5c46480719af0fd12e27338e883a06cb Mon Sep 17 00:00:00 2001 From: Murthy Narkedimilli Date: Tue, 7 May 2013 08:10:09 +0200 Subject: [PATCH 1/5] Merging the changes from 5.1 branch to release branch. Includes bug fixes for: Bug #16722314 FOREIGN KEY ID MODIFIED DURING EXPORT Bug #16754901 PARS_INFO_FREE NOT CALLED IN DICT_CREATE_ADD_FOREIGN_TO_DICTIONARY --- storage/innobase/dict/dict0crea.c | 56 ++++++++-- storage/innobase/dict/dict0dict.c | 105 +++++++++++++++--- storage/innobase/handler/ha_innodb.cc | 64 +++++++---- storage/innobase/include/dict0types.h | 3 + storage/innobase/include/ha_prototypes.h | 15 ++- storage/innobase/row/row0mysql.c | 36 ++++-- storage/innodb_plugin/dict/dict0crea.c | 58 ++++++++-- storage/innodb_plugin/dict/dict0dict.c | 102 +++++++++++++++-- storage/innodb_plugin/handler/ha_innodb.cc | 56 +++++++--- storage/innodb_plugin/include/dict0types.h | 3 + storage/innodb_plugin/include/ha_prototypes.h | 20 ++++ storage/innodb_plugin/row/row0mysql.c | 30 ++++- 12 files changed, 444 insertions(+), 104 deletions(-) diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 5e0fac8b411..aa34cadeb7a 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -27,6 +27,21 @@ Created 1/8/1996 Heikki Tuuri #include "ut0vec.h" #include "ha_prototypes.h" +/************************************************************************* +Checks if a table name contains the string TEMP_TABLE_PATH_PREFIX which +denotes temporary tables in MySQL. */ +static +ibool +row_is_mysql_tmp_table_name( +/*========================*/ + /* out: TRUE if temporary table */ + const char* name) /* in: table name in the form + 'database/tablename' */ +{ + return(strstr(name, TEMP_TABLE_PATH_PREFIX) != NULL); +} + + /********************************************************************* Based on a table object, this function builds the entry to be inserted in the SYS_TABLES system table. */ @@ -1347,26 +1362,47 @@ dict_create_add_foreign_to_dictionary( { ulint error; ulint i; - - pars_info_t* info = pars_info_create(); + pars_info_t* info; if (foreign->id == NULL) { - char* stripped_name; /* Generate a new constraint id */ ulint namelen = strlen(table->name); char* id = mem_heap_alloc(foreign->heap, namelen + 20); /* no overflow if number < 1e13 */ - sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); - foreign->id = id; - stripped_name = strchr(foreign->id, '/') + 1; - if (innobase_check_identifier_length(stripped_name)) { - fprintf(stderr, "InnoDB: Generated foreign key " - "name (%s) is too long\n", foreign->id); - return(DB_IDENTIFIER_TOO_LONG); + if (row_is_mysql_tmp_table_name(table->name)) { + sprintf(id, "%s_ibfk_%lu", table->name, + (ulong) (*id_nr)++); + } else { + char table_name[MAX_TABLE_NAME_LEN + 20] = ""; + uint errors = 0; + + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN + 20); + + innobase_convert_to_system_charset( + strchr(table_name, '/') + 1, + strchr(table->name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN + 20); + } + + sprintf(id, "%s_ibfk_%lu", table_name, + (ulong) (*id_nr)++); + + if (innobase_check_identifier_length( + strchr(id,'/') + 1)) { + return(DB_IDENTIFIER_TOO_LONG); + } } + foreign->id = id; } + info = pars_info_create(); + pars_info_add_str_literal(info, "id", foreign->id); pars_info_add_str_literal(info, "for_name", table->name); diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index a38b7224551..e580ffa3b3b 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1052,6 +1052,7 @@ dict_table_rename_in_cache( foreign = UT_LIST_GET_FIRST(table->foreign_list); while (foreign != NULL) { + if (ut_strlen(foreign->foreign_table_name) < ut_strlen(table->name)) { /* Allocate a longer name buffer; @@ -1065,34 +1066,115 @@ dict_table_rename_in_cache( strcpy(foreign->foreign_table_name, table->name); if (strchr(foreign->id, '/')) { + /* This is a >= 4.0.18 format id */ + ulint db_len; char* old_id; + char old_name_cs_filename[MAX_TABLE_NAME_LEN+20]; + uint errors = 0; - /* This is a >= 4.0.18 format id */ + /* All table names are internally stored in charset + my_charset_filename (except the temp tables and the + partition identifier suffix in partition tables). The + foreign key constraint names are internally stored + in UTF-8 charset. The variable fkid here is used + to store foreign key constraint name in charset + my_charset_filename for comparison further below. */ + char fkid[MAX_TABLE_NAME_LEN+20]; + ibool on_tmp = FALSE; + + /* The old table name in my_charset_filename is stored + in old_name_cs_filename */ + + strncpy(old_name_cs_filename, old_name, + MAX_TABLE_NAME_LEN); + if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) { + + innobase_convert_to_system_charset( + strchr(old_name_cs_filename, '/') + 1, + strchr(old_name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* There has been an error to convert + old table into UTF-8. This probably + means that the old table name is + actually in UTF-8. */ + innobase_convert_to_filename_charset( + strchr(old_name_cs_filename, + '/') + 1, + strchr(old_name, '/') + 1, + MAX_TABLE_NAME_LEN); + } else { + /* Old name already in + my_charset_filename */ + strncpy(old_name_cs_filename, old_name, + MAX_TABLE_NAME_LEN); + } + } + + strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN); + + if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) { + innobase_convert_to_filename_charset( + strchr(fkid, '/') + 1, + strchr(foreign->id, '/') + 1, + MAX_TABLE_NAME_LEN+20); + } else { + on_tmp = TRUE; + } old_id = mem_strdup(foreign->id); - if (ut_strlen(foreign->id) > ut_strlen(old_name) + if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename) + ((sizeof dict_ibfk) - 1) - && !memcmp(foreign->id, old_name, - ut_strlen(old_name)) - && !memcmp(foreign->id + ut_strlen(old_name), + && !memcmp(fkid, old_name_cs_filename, + ut_strlen(old_name_cs_filename)) + && !memcmp(fkid + ut_strlen(old_name_cs_filename), dict_ibfk, (sizeof dict_ibfk) - 1)) { + char table_name[MAX_TABLE_NAME_LEN] = ""; + uint errors = 0; + /* This is a generated >= 4.0.18 format id */ if (strlen(table->name) > strlen(old_name)) { - foreign->id = mem_heap_alloc( + foreign->id = mem_heap_zalloc( foreign->heap, strlen(table->name) + strlen(old_id) + 1); } + /* Convert the table name to UTF-8 */ + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN); + innobase_convert_to_system_charset( + strchr(table_name, '/') + 1, + strchr(table->name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted + from charset my_charset_filename to + UTF-8. This means that the table name + is already in UTF-8 (#mysql#50). */ + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN); + } + /* Replace the prefix 'databasename/tablename' with the new names */ - strcpy(foreign->id, table->name); - strcat(foreign->id, - old_id + ut_strlen(old_name)); + strcpy(foreign->id, table_name); + if (on_tmp) { + strcat(foreign->id, + old_id + ut_strlen(old_name)); + } else { + sprintf(strchr(foreign->id, '/') + 1, + "%s%s", + strchr(table_name, '/') +1, + strstr(old_id, "_ibfk_") ); + } + } else { /* This is a >= 4.0.18 format id where the user gave the id name */ @@ -4108,7 +4190,6 @@ dict_print_info_on_foreign_key_in_create_format( dict_foreign_t* foreign, /* in: foreign key constraint */ ibool add_newline) /* in: whether to add a newline */ { - char constraint_name[MAX_TABLE_NAME_LEN]; const char* stripped_id; ulint i; @@ -4130,9 +4211,7 @@ dict_print_info_on_foreign_key_in_create_format( } fputs(" CONSTRAINT ", file); - innobase_convert_to_system_charset(constraint_name, stripped_id, - MAX_TABLE_NAME_LEN); - ut_print_name(file, trx, FALSE, constraint_name); + ut_print_name(file, trx, FALSE, stripped_id); fputs(" FOREIGN KEY (", file); for (i = 0;;) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 36e0adddbe4..d7d1b457af9 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -901,33 +901,27 @@ innobase_convert_from_table_id( /********************************************************************** Check if the length of the identifier exceeds the maximum allowed. -The input to this function is an identifier in charset my_charset_filename. return true when length of identifier is too long. */ extern "C" my_bool innobase_check_identifier_length( /*=============================*/ - const char* id) /* in: identifier to check. it must belong - to charset my_charset_filename */ + const char* id) /* in: FK identifier to check excluding the + database portion. */ { - char tmp[MAX_TABLE_NAME_LEN + 10]; - uint errors; - uint len; int well_formed_error = 0; - CHARSET_INFO *cs1 = &my_charset_filename; - CHARSET_INFO *cs2 = thd_charset(current_thd); + CHARSET_INFO *cs = system_charset_info; + DBUG_ENTER("innobase_check_identifier_length"); - len = strconvert(cs1, id, cs2, tmp, MAX_TABLE_NAME_LEN + 10, &errors); + uint res = cs->cset->well_formed_len(cs, id, id + strlen(id), + NAME_CHAR_LEN, + &well_formed_error); - uint res = cs2->cset->well_formed_len(cs2, tmp, tmp + len, - NAME_CHAR_LEN, - &well_formed_error); - - if (well_formed_error || res != len) { - my_error(ER_TOO_LONG_IDENT, MYF(0), tmp); - return(true); + if (well_formed_error || res == NAME_CHAR_LEN) { + my_error(ER_TOO_LONG_IDENT, MYF(0), id); + DBUG_RETURN(true); } - return(false); + DBUG_RETURN(false); } /********************************************************************** @@ -957,17 +951,17 @@ innobase_convert_to_system_charset( /*===============================*/ char* to, /* out: converted identifier */ const char* from, /* in: identifier to convert */ - ulint len) /* in: length of 'to', in bytes */ + ulint len, /* in: length of 'to', in bytes */ + uint* errors) /* out: error return */ { - uint errors; uint rlen; CHARSET_INFO* cs1 = &my_charset_filename; CHARSET_INFO* cs2 = system_charset_info; - rlen = strconvert(cs1, from, cs2, to, len, &errors); + rlen = strconvert(cs1, from, cs2, to, len, errors); - if (errors) { - fprintf(stderr, " InnoDB: There was a problem in converting" + if (*errors) { + fprintf(stderr, "InnoDB: There was a problem in converting" "'%s' in charset %s to charset %s", from, cs1->name, cs2->name); } @@ -975,6 +969,32 @@ innobase_convert_to_system_charset( return(rlen); } +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +extern "C" +uint +innobase_convert_to_filename_charset( +/*=================================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len) /* in: length of 'to', in bytes */ +{ + uint errors; + uint rlen; + CHARSET_INFO* cs_to = &my_charset_filename; + CHARSET_INFO* cs_from = system_charset_info; + + rlen = strconvert(cs_from, from, cs_to, to, len, &errors); + + if (errors) { + fprintf(stderr, "InnoDB: There was a problem in converting" + "'%s' in charset %s to charset %s", from, cs_from->name, + cs_to->name); + } + + return(rlen); +} + /********************************************************************** Compares NUL-terminated UTF-8 strings case insensitively. diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 6674b5ff397..fe66725500b 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -19,4 +19,7 @@ typedef struct dict_foreign_struct dict_foreign_t; typedef struct ind_node_struct ind_node_t; typedef struct tab_node_struct tab_node_t; +#define TEMP_TABLE_PREFIX "#sql" +#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX + #endif diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 0ad3c82fffd..3aa70e8f4ae 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -92,10 +92,19 @@ Converts an identifier from my_charset_filename to UTF-8 charset. */ uint innobase_convert_to_system_charset( /*===============================*/ - char* to, /* out: converted identifier */ - const char* from, /* in: identifier to convert */ - ulint len); /* in: length of 'to', in bytes */ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len, /* in: length of 'to', in bytes */ + uint* errors); /* out: error return */ +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +uint +innobase_convert_to_filename_charset( +/*=================================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len); /* in: length of 'to', in bytes */ #endif #endif diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 6c2f910eec7..e513dd6f2a8 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -33,6 +33,7 @@ Created 9/17/2000 Heikki Tuuri #include "ibuf0ibuf.h" #include "m_string.h" #include "my_sys.h" +#include "ha_prototypes.h" /* A dummy variable used to fool the compiler */ ibool row_mysql_identically_false = FALSE; @@ -3657,6 +3658,7 @@ row_rename_table_for_mysql( ibool old_is_tmp, new_is_tmp; pars_info_t* info = NULL; ulint retry = 0; + DBUG_ENTER("row_rename_table_for_mysql"); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(old_name != NULL); @@ -3672,7 +3674,7 @@ row_rename_table_for_mysql( stderr); trx_commit_for_mysql(trx); - return(DB_ERROR); + DBUG_RETURN(DB_ERROR); } if (row_mysql_is_system_table(new_name)) { @@ -3685,7 +3687,7 @@ row_rename_table_for_mysql( new_name); trx_commit_for_mysql(trx); - return(DB_ERROR); + DBUG_RETURN(DB_ERROR); } trx->op_info = "renaming table"; @@ -3799,12 +3801,29 @@ row_rename_table_for_mysql( if (!new_is_tmp) { /* Rename all constraints. */ + char new_table_name[MAX_TABLE_NAME_LEN] = ""; + uint errors = 0; info = pars_info_create(); pars_info_add_str_literal(info, "new_table_name", new_name); pars_info_add_str_literal(info, "old_table_name", old_name); + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + innobase_convert_to_system_charset( + strchr(new_table_name, '/') + 1, + strchr(new_name, '/') +1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted from charset + my_charset_filename to UTF-8. This means that the + table name is already in UTF-8 (#mysql#50). */ + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + } + + pars_info_add_str_literal(info, "new_table_utf8", new_table_name); + err = que_eval_sql( info, "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" @@ -3816,6 +3835,7 @@ row_rename_table_for_mysql( "old_t_name_len INT;\n" "new_db_name_len INT;\n" "id_len INT;\n" + "offset INT;\n" "found INT;\n" "BEGIN\n" "found := 1;\n" @@ -3824,8 +3844,6 @@ row_rename_table_for_mysql( "new_db_name := SUBSTR(:new_table_name, 0,\n" " new_db_name_len);\n" "old_t_name_len := LENGTH(:old_table_name);\n" - "gen_constr_prefix := CONCAT(:old_table_name,\n" - " '_ibfk_');\n" "WHILE found = 1 LOOP\n" " SELECT ID INTO foreign_id\n" " FROM SYS_FOREIGN\n" @@ -3842,12 +3860,12 @@ row_rename_table_for_mysql( " id_len := LENGTH(foreign_id);\n" " IF (INSTR(foreign_id, '/') > 0) THEN\n" " IF (INSTR(foreign_id,\n" - " gen_constr_prefix) > 0)\n" + " '_ibfk_') > 0)\n" " THEN\n" + " offset := INSTR(foreign_id, '_ibfk_') - 1;\n" " new_foreign_id :=\n" - " CONCAT(:new_table_name,\n" - " SUBSTR(foreign_id, old_t_name_len,\n" - " id_len - old_t_name_len));\n" + " CONCAT(:new_table_utf8,\n" + " SUBSTR(foreign_id, offset, id_len - offset));\n" " ELSE\n" " new_foreign_id :=\n" " CONCAT(new_db_name,\n" @@ -4005,7 +4023,7 @@ funct_exit: trx->op_info = ""; - return((int) err); + DBUG_RETURN((int) err); } /************************************************************************* diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 957a7f822b9..72aa01fcb8b 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -44,6 +44,21 @@ Created 1/8/1996 Heikki Tuuri #include "ut0vec.h" #include "ha_prototypes.h" +/************************************************************************* +Checks if a table name contains the string TEMP_TABLE_PATH_PREFIX which +denotes temporary tables in MySQL. */ +static +ibool +row_is_mysql_tmp_table_name( +/*========================*/ + /* out: TRUE if temporary table */ + const char* name) /* in: table name in the form + 'database/tablename' */ +{ + return(strstr(name, TEMP_TABLE_PATH_PREFIX) != NULL); +} + + /*****************************************************************//** Based on a table object, this function builds the entry to be inserted in the SYS_TABLES system table. @@ -1426,26 +1441,47 @@ dict_create_add_foreign_to_dictionary( { ulint error; ulint i; - - pars_info_t* info = pars_info_create(); + pars_info_t* info; if (foreign->id == NULL) { - char* stripped_name; /* Generate a new constraint id */ ulint namelen = strlen(table->name); char* id = mem_heap_alloc(foreign->heap, namelen + 20); - /* no overflow if number < 1e13 */ - sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); + + if (row_is_mysql_tmp_table_name(table->name)) { + sprintf(id, "%s_ibfk_%lu", table->name, + (ulong) (*id_nr)++); + } else { + char table_name[MAX_TABLE_NAME_LEN + 20] = ""; + uint errors = 0; + + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN + 20); + + innobase_convert_to_system_charset( + strchr(table_name, '/') + 1, + strchr(table->name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN + 20); + } + + sprintf(id, "%s_ibfk_%lu", table_name, + (ulong) (*id_nr)++); + + if (innobase_check_identifier_length( + strchr(id,'/') + 1)) { + return(DB_IDENTIFIER_TOO_LONG); + } + } foreign->id = id; - stripped_name = strchr(foreign->id, '/') + 1; - if (innobase_check_identifier_length(stripped_name)) { - fprintf(stderr, "InnoDB: Generated foreign key " - "name (%s) is too long\n", foreign->id); - return(DB_IDENTIFIER_TOO_LONG); - } } + info = pars_info_create(); + pars_info_add_str_literal(info, "id", foreign->id); pars_info_add_str_literal(info, "for_name", table->name); diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index 4219f83df4a..ca53d7fc157 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -1092,22 +1092,78 @@ dict_table_rename_in_cache( strcpy(foreign->foreign_table_name, table->name); if (strchr(foreign->id, '/')) { + /* This is a >= 4.0.18 format id */ + ulint db_len; char* old_id; + char old_name_cs_filename[MAX_TABLE_NAME_LEN+20]; + uint errors = 0; - /* This is a >= 4.0.18 format id */ + /* All table names are internally stored in charset + my_charset_filename (except the temp tables and the + partition identifier suffix in partition tables). The + foreign key constraint names are internally stored + in UTF-8 charset. The variable fkid here is used + to store foreign key constraint name in charset + my_charset_filename for comparison further below. */ + char fkid[MAX_TABLE_NAME_LEN+20]; + ibool on_tmp = FALSE; + + /* The old table name in my_charset_filename is stored + in old_name_cs_filename */ + + strncpy(old_name_cs_filename, old_name, + MAX_TABLE_NAME_LEN); + if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) { + + innobase_convert_to_system_charset( + strchr(old_name_cs_filename, '/') + 1, + strchr(old_name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* There has been an error to convert + old table into UTF-8. This probably + means that the old table name is + actually in UTF-8. */ + innobase_convert_to_filename_charset( + strchr(old_name_cs_filename, + '/') + 1, + strchr(old_name, '/') + 1, + MAX_TABLE_NAME_LEN); + } else { + /* Old name already in + my_charset_filename */ + strncpy(old_name_cs_filename, old_name, + MAX_TABLE_NAME_LEN); + } + } + + strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN); + + if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) { + innobase_convert_to_filename_charset( + strchr(fkid, '/') + 1, + strchr(foreign->id, '/') + 1, + MAX_TABLE_NAME_LEN+20); + } else { + on_tmp = TRUE; + } old_id = mem_strdup(foreign->id); - if (ut_strlen(foreign->id) > ut_strlen(old_name) + if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename) + ((sizeof dict_ibfk) - 1) - && !memcmp(foreign->id, old_name, - ut_strlen(old_name)) - && !memcmp(foreign->id + ut_strlen(old_name), + && !memcmp(fkid, old_name_cs_filename, + ut_strlen(old_name_cs_filename)) + && !memcmp(fkid + ut_strlen(old_name_cs_filename), dict_ibfk, (sizeof dict_ibfk) - 1)) { /* This is a generated >= 4.0.18 format id */ + char table_name[MAX_TABLE_NAME_LEN] = ""; + uint errors = 0; + if (strlen(table->name) > strlen(old_name)) { foreign->id = mem_heap_alloc( foreign->heap, @@ -1115,11 +1171,36 @@ dict_table_rename_in_cache( + strlen(old_id) + 1); } + /* Convert the table name to UTF-8 */ + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN); + innobase_convert_to_system_charset( + strchr(table_name, '/') + 1, + strchr(table->name, '/') + 1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted + from charset my_charset_filename to + UTF-8. This means that the table name + is already in UTF-8 (#mysql#50). */ + strncpy(table_name, table->name, + MAX_TABLE_NAME_LEN); + } + /* Replace the prefix 'databasename/tablename' with the new names */ - strcpy(foreign->id, table->name); - strcat(foreign->id, - old_id + ut_strlen(old_name)); + strcpy(foreign->id, table_name); + if (on_tmp) { + strcat(foreign->id, + old_id + ut_strlen(old_name)); + } else { + sprintf(strchr(foreign->id, '/') + 1, + "%s%s", + strchr(table_name, '/') +1, + strstr(old_id, "_ibfk_") ); + } + } else { /* This is a >= 4.0.18 format id where the user gave the id name */ @@ -4602,7 +4683,6 @@ dict_print_info_on_foreign_key_in_create_format( dict_foreign_t* foreign, /*!< in: foreign key constraint */ ibool add_newline) /*!< in: whether to add a newline */ { - char constraint_name[MAX_TABLE_NAME_LEN]; const char* stripped_id; ulint i; @@ -4624,9 +4704,7 @@ dict_print_info_on_foreign_key_in_create_format( } fputs(" CONSTRAINT ", file); - innobase_convert_from_id(&my_charset_filename, constraint_name, - stripped_id, MAX_TABLE_NAME_LEN); - ut_print_name(file, trx, FALSE, constraint_name); + ut_print_name(file, trx, FALSE, stripped_id); fputs(" FOREIGN KEY (", file); for (i = 0;;) { diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 87769f6e593..9bfa3b51948 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -1013,33 +1013,27 @@ innobase_convert_from_table_id( /********************************************************************** Check if the length of the identifier exceeds the maximum allowed. -The input to this function is an identifier in charset my_charset_filename. return true when length of identifier is too long. */ -extern "C" UNIV_INTERN +extern "C" my_bool innobase_check_identifier_length( /*=============================*/ - const char* id) /* in: identifier to check. it must belong - to charset my_charset_filename */ + const char* id) /* in: FK identifier to check excluding the + database portion. */ { - char tmp[MAX_TABLE_NAME_LEN + 10]; - uint errors; - uint len; int well_formed_error = 0; - CHARSET_INFO* cs1 = &my_charset_filename; - CHARSET_INFO* cs2 = thd_charset(current_thd); + CHARSET_INFO *cs = system_charset_info; + DBUG_ENTER("innobase_check_identifier_length"); - len = strconvert(cs1, id, cs2, tmp, MAX_TABLE_NAME_LEN + 10, &errors); + uint res = cs->cset->well_formed_len(cs, id, id + strlen(id), + NAME_CHAR_LEN, + &well_formed_error); - uint res = cs2->cset->well_formed_len(cs2, tmp, tmp + len, - NAME_CHAR_LEN, - &well_formed_error); - - if (well_formed_error || res != len) { - my_error(ER_TOO_LONG_IDENT, MYF(0), tmp); - return(true); + if (well_formed_error || res == NAME_CHAR_LEN) { + my_error(ER_TOO_LONG_IDENT, MYF(0), id); + DBUG_RETURN(true); } - return(false); + DBUG_RETURN(false); } /******************************************************************//** @@ -11614,4 +11608,30 @@ test_innobase_convert_name() } } +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +extern "C" +uint +innobase_convert_to_filename_charset( +/*=================================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len) /* in: length of 'to', in bytes */ +{ + uint errors; + uint rlen; + CHARSET_INFO* cs_to = &my_charset_filename; + CHARSET_INFO* cs_from = system_charset_info; + + rlen = strconvert(cs_from, from, cs_to, to, len, &errors); + + if (errors) { + fprintf(stderr, "InnoDB: There was a problem in converting" + "'%s' in charset %s to charset %s", from, cs_from->name, + cs_to->name); + } + + return(rlen); +} + #endif /* UNIV_COMPILE_TEST_FUNCS */ diff --git a/storage/innodb_plugin/include/dict0types.h b/storage/innodb_plugin/include/dict0types.h index f14b59a19d4..93c9e8f977e 100644 --- a/storage/innodb_plugin/include/dict0types.h +++ b/storage/innodb_plugin/include/dict0types.h @@ -40,4 +40,7 @@ typedef struct tab_node_struct tab_node_t; #define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */ #define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO +#define TEMP_TABLE_PREFIX "#sql" +#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX + #endif diff --git a/storage/innodb_plugin/include/ha_prototypes.h b/storage/innodb_plugin/include/ha_prototypes.h index cc3e5f64634..e84c419be3a 100644 --- a/storage/innodb_plugin/include/ha_prototypes.h +++ b/storage/innodb_plugin/include/ha_prototypes.h @@ -279,4 +279,24 @@ innobase_check_identifier_length( const char* id); /* in: identifier to check. it must belong to charset my_charset_filename */ +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +uint +innobase_convert_to_system_charset( +/*===============================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len, /* in: length of 'to', in bytes */ + uint* errors); /* out: error return */ + +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +uint +innobase_convert_to_filename_charset( +/*=================================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len); /* in: length of 'to', in bytes */ + + #endif diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 9379912a218..05f5d7ab68c 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -51,6 +51,7 @@ Created 9/17/2000 Heikki Tuuri #include "btr0sea.h" #include "fil0fil.h" #include "ibuf0ibuf.h" +#include "ha_prototypes.h" #ifdef __WIN__ /* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */ @@ -3902,12 +3903,29 @@ row_rename_table_for_mysql( goto end; } else if (!new_is_tmp) { /* Rename all constraints. */ + char new_table_name[MAX_TABLE_NAME_LEN] = ""; + uint errors = 0; info = pars_info_create(); pars_info_add_str_literal(info, "new_table_name", new_name); pars_info_add_str_literal(info, "old_table_name", old_name); + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + innobase_convert_to_system_charset( + strchr(new_table_name, '/') + 1, + strchr(new_name, '/') +1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted from charset + my_charset_filename to UTF-8. This means that the + table name is already in UTF-8 (#mysql#50). */ + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + } + + pars_info_add_str_literal(info, "new_table_utf8", new_table_name); + err = que_eval_sql( info, "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" @@ -3919,6 +3937,7 @@ row_rename_table_for_mysql( "old_t_name_len INT;\n" "new_db_name_len INT;\n" "id_len INT;\n" + "offset INT;\n" "found INT;\n" "BEGIN\n" "found := 1;\n" @@ -3927,8 +3946,6 @@ row_rename_table_for_mysql( "new_db_name := SUBSTR(:new_table_name, 0,\n" " new_db_name_len);\n" "old_t_name_len := LENGTH(:old_table_name);\n" - "gen_constr_prefix := CONCAT(:old_table_name,\n" - " '_ibfk_');\n" "WHILE found = 1 LOOP\n" " SELECT ID INTO foreign_id\n" " FROM SYS_FOREIGN\n" @@ -3945,12 +3962,13 @@ row_rename_table_for_mysql( " id_len := LENGTH(foreign_id);\n" " IF (INSTR(foreign_id, '/') > 0) THEN\n" " IF (INSTR(foreign_id,\n" - " gen_constr_prefix) > 0)\n" + " '_ibfk_') > 0)\n" " THEN\n" + " offset := INSTR(foreign_id, '_ibfk_') - 1;\n" " new_foreign_id :=\n" - " CONCAT(:new_table_name,\n" - " SUBSTR(foreign_id, old_t_name_len,\n" - " id_len - old_t_name_len));\n" + " CONCAT(:new_table_utf8,\n" + " SUBSTR(foreign_id, offset,\n" + " id_len - offset));\n" " ELSE\n" " new_foreign_id :=\n" " CONCAT(new_db_name,\n" From ded5a79dab46569c89044226ce590f6c3f9b7d21 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Tue, 7 May 2013 09:14:51 +0200 Subject: [PATCH 2/5] Updated spec file to ignore upgrade error message --- support-files/mysql.spec.sh | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 115a1380e32..2d8aa78464b 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -753,13 +753,16 @@ if [ -d $mysql_datadir ] ; then echo "MySQL RPM upgrade to version $NEW_VERSION" > $STATUS_FILE echo "'pre' step running at `date`" >> $STATUS_FILE echo >> $STATUS_FILE - echo "ERR file(s):" >> $STATUS_FILE - ls -ltr $mysql_datadir/*.err >> $STATUS_FILE - echo >> $STATUS_FILE - echo "Latest 'Version' line in latest file:" >> $STATUS_FILE - grep '^Version' `ls -tr $mysql_datadir/*.err | tail -1` | \ - tail -1 >> $STATUS_FILE - echo >> $STATUS_FILE + fcount=`ls -ltr $mysql_datadir/*.err 2>/dev/null | wc -l` + if [ $fcount -gt 0 ] ; then + echo "ERR file(s):" >> $STATUS_FILE + ls -ltr $mysql_datadir/*.err >> $STATUS_FILE + echo >> $STATUS_FILE + echo "Latest 'Version' line in latest file:" >> $STATUS_FILE + grep '^Version' `ls -tr $mysql_datadir/*.err | tail -1` | \ + tail -1 >> $STATUS_FILE + echo >> $STATUS_FILE + fi if [ -n "$SERVER_TO_START" ] ; then # There is only one PID file, race possibility ignored From 500f76f4f384078e04b71e349c59634aca3ee20d Mon Sep 17 00:00:00 2001 From: Murthy Narkedimilli Date: Fri, 10 May 2013 15:27:03 +0200 Subject: [PATCH 3/5] Merging the changes which fixes the build issue for Windows Builds. Description: Fixing a build issue. The function innobase_convert_to_system_charset() is included only in the builtin InnoDB, and it is missed in InnoDB plugin. Adding this function in InnoDB plugin as well. --- storage/innodb_plugin/handler/ha_innodb.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 9bfa3b51948..38f1fd566b1 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -1052,6 +1052,23 @@ innobase_convert_from_id( strconvert(cs, from, system_charset_info, to, (uint) len, &errors); } +/********************************************************************** +Converts an identifier from my_charset_filename to UTF-8 charset. */ +extern "C" +uint +innobase_convert_to_system_charset( +/*===============================*/ + char* to, /* out: converted identifier */ + const char* from, /* in: identifier to convert */ + ulint len, /* in: length of 'to', in bytes */ + uint* errors) /* out: error return */ +{ + CHARSET_INFO* cs1 = &my_charset_filename; + CHARSET_INFO* cs2 = system_charset_info; + + return(strconvert(cs1, from, cs2, to, len, errors)); +} + /******************************************************************//** Compares NUL-terminated UTF-8 strings case insensitively. @return 0 if a=b, <0 if a1 if a>b */ From 2e60b30cfb5d9337025b6ccffb4640923b341cdc Mon Sep 17 00:00:00 2001 From: Murthy Narkedimilli Date: Mon, 13 May 2013 15:22:49 +0200 Subject: [PATCH 4/5] Merging the changes for build failures in windows. --- storage/innodb_plugin/handler/ha_innodb.cc | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 38f1fd566b1..792717d471d 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -11624,6 +11624,7 @@ test_innobase_convert_name() } } } +#endif /* UNIV_COMPILE_TEST_FUNCS */ /********************************************************************** Converts an identifier from my_charset_filename to UTF-8 charset. */ @@ -11636,19 +11637,8 @@ innobase_convert_to_filename_charset( ulint len) /* in: length of 'to', in bytes */ { uint errors; - uint rlen; CHARSET_INFO* cs_to = &my_charset_filename; CHARSET_INFO* cs_from = system_charset_info; - rlen = strconvert(cs_from, from, cs_to, to, len, &errors); - - if (errors) { - fprintf(stderr, "InnoDB: There was a problem in converting" - "'%s' in charset %s to charset %s", from, cs_from->name, - cs_to->name); - } - - return(rlen); + return(strconvert(cs_from, from, cs_to, to, len, &errors)); } - -#endif /* UNIV_COMPILE_TEST_FUNCS */