summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurthy Narkedimilli <murthy.narkedimilli@oracle.com>2013-05-07 08:10:09 +0200
committerMurthy Narkedimilli <murthy.narkedimilli@oracle.com>2013-05-07 08:10:09 +0200
commit9e1474fe34bb42d8cb1c27b5366cf57958bcb5c5 (patch)
tree49dcc792a883316f1221481a337b764d2055f72f
parent0fdc37cad035d07ae4016346646cfa42444513bb (diff)
downloadmariadb-git-9e1474fe34bb42d8cb1c27b5366cf57958bcb5c5.tar.gz
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
-rw-r--r--storage/innobase/dict/dict0crea.c56
-rw-r--r--storage/innobase/dict/dict0dict.c105
-rw-r--r--storage/innobase/handler/ha_innodb.cc64
-rw-r--r--storage/innobase/include/dict0types.h3
-rw-r--r--storage/innobase/include/ha_prototypes.h15
-rw-r--r--storage/innobase/row/row0mysql.c36
-rw-r--r--storage/innodb_plugin/dict/dict0crea.c58
-rw-r--r--storage/innodb_plugin/dict/dict0dict.c102
-rw-r--r--storage/innodb_plugin/handler/ha_innodb.cc56
-rw-r--r--storage/innodb_plugin/include/dict0types.h3
-rw-r--r--storage/innodb_plugin/include/ha_prototypes.h20
-rw-r--r--storage/innodb_plugin/row/row0mysql.c30
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;
+
+ /* 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);
+ }
+ }
- /* This is a >= 4.0.18 format id */
+ 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)++);
- 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/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;
+
+ /* 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);
+ }
+ }
- /* This is a >= 4.0.18 format id */
+ 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);
-
- len = strconvert(cs1, id, cs2, tmp, MAX_TABLE_NAME_LEN + 10, &errors);
+ CHARSET_INFO *cs = system_charset_info;
+ DBUG_ENTER("innobase_check_identifier_length");
- uint res = cs2->cset->well_formed_len(cs2, tmp, tmp + len,
- NAME_CHAR_LEN,
- &well_formed_error);
+ uint res = cs->cset->well_formed_len(cs, id, id + strlen(id),
+ 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"