Commit 068e6673 authored by Annamalai Gurusami's avatar Annamalai Gurusami

Bug #16722314 FOREIGN KEY ID MODIFIED DURING EXPORT

Bug #16754901 PARS_INFO_FREE NOT CALLED IN DICT_CREATE_ADD_FOREIGN_TO_DICTIONARY

Problem:

There are two situations here.  The constraint name is explicitly
given by the user and the constraint name is automatically generated
by InnoDB.  In the case of generated constraint name, it is formed by
adding table name as prefix.  The table names are stored internally in
my_charset_filename.  In the case of constraint name explicitly given
by the user, it is stored in UTF8 format itself.  So, in some
situations the constraint name is in utf8 and in some situations it is
in my_charset_filename format.  Hence this problem.

Solution:

Always store the foreign key constraint name in UTF-8 even when
automatically generated.

Bug #16754901 PARS_INFO_FREE NOT CALLED IN DICT_CREATE_ADD_FOREIGN_TO_DICTIONARY

Problem:

There was a memory leak in the function dict_create_add_foreign_to_dictionary().
The allocated pars_info_t object is not freed in the error code path.

Solution:

Allocate the pars_info_t object after the error checking.

rb#2368 in review
parent ce38f6b4
...@@ -27,6 +27,21 @@ Created 1/8/1996 Heikki Tuuri ...@@ -27,6 +27,21 @@ Created 1/8/1996 Heikki Tuuri
#include "ut0vec.h" #include "ut0vec.h"
#include "ha_prototypes.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 Based on a table object, this function builds the entry to be inserted
in the SYS_TABLES system table. */ in the SYS_TABLES system table. */
...@@ -1347,26 +1362,47 @@ dict_create_add_foreign_to_dictionary( ...@@ -1347,26 +1362,47 @@ dict_create_add_foreign_to_dictionary(
{ {
ulint error; ulint error;
ulint i; ulint i;
pars_info_t* info;
pars_info_t* info = pars_info_create();
if (foreign->id == NULL) { if (foreign->id == NULL) {
char* stripped_name;
/* Generate a new constraint id */ /* Generate a new constraint id */
ulint namelen = strlen(table->name); ulint namelen = strlen(table->name);
char* id = mem_heap_alloc(foreign->heap, namelen + 20); char* id = mem_heap_alloc(foreign->heap, namelen + 20);
/* no overflow if number < 1e13 */ /* 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 (row_is_mysql_tmp_table_name(table->name)) {
if (innobase_check_identifier_length(stripped_name)) { sprintf(id, "%s_ibfk_%lu", table->name,
fprintf(stderr, "InnoDB: Generated foreign key " (ulong) (*id_nr)++);
"name (%s) is too long\n", foreign->id); } else {
return(DB_IDENTIFIER_TOO_LONG); 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, "id", foreign->id);
pars_info_add_str_literal(info, "for_name", table->name); pars_info_add_str_literal(info, "for_name", table->name);
......
...@@ -1052,6 +1052,7 @@ dict_table_rename_in_cache( ...@@ -1052,6 +1052,7 @@ dict_table_rename_in_cache(
foreign = UT_LIST_GET_FIRST(table->foreign_list); foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) { while (foreign != NULL) {
if (ut_strlen(foreign->foreign_table_name) if (ut_strlen(foreign->foreign_table_name)
< ut_strlen(table->name)) { < ut_strlen(table->name)) {
/* Allocate a longer name buffer; /* Allocate a longer name buffer;
...@@ -1065,34 +1066,115 @@ dict_table_rename_in_cache( ...@@ -1065,34 +1066,115 @@ dict_table_rename_in_cache(
strcpy(foreign->foreign_table_name, table->name); strcpy(foreign->foreign_table_name, table->name);
if (strchr(foreign->id, '/')) { if (strchr(foreign->id, '/')) {
/* This is a >= 4.0.18 format id */
ulint db_len; ulint db_len;
char* old_id; 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); 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) + ((sizeof dict_ibfk) - 1)
&& !memcmp(foreign->id, old_name, && !memcmp(fkid, old_name_cs_filename,
ut_strlen(old_name)) ut_strlen(old_name_cs_filename))
&& !memcmp(foreign->id + ut_strlen(old_name), && !memcmp(fkid + ut_strlen(old_name_cs_filename),
dict_ibfk, (sizeof dict_ibfk) - 1)) { 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 */ /* This is a generated >= 4.0.18 format id */
if (strlen(table->name) > strlen(old_name)) { if (strlen(table->name) > strlen(old_name)) {
foreign->id = mem_heap_alloc( foreign->id = mem_heap_zalloc(
foreign->heap, foreign->heap,
strlen(table->name) strlen(table->name)
+ strlen(old_id) + 1); + 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' /* Replace the prefix 'databasename/tablename'
with the new names */ with the new names */
strcpy(foreign->id, table->name); strcpy(foreign->id, table_name);
strcat(foreign->id, if (on_tmp) {
old_id + ut_strlen(old_name)); 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 { } else {
/* This is a >= 4.0.18 format id where the user /* This is a >= 4.0.18 format id where the user
gave the id name */ gave the id name */
...@@ -4108,7 +4190,6 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4108,7 +4190,6 @@ dict_print_info_on_foreign_key_in_create_format(
dict_foreign_t* foreign, /* in: foreign key constraint */ dict_foreign_t* foreign, /* in: foreign key constraint */
ibool add_newline) /* in: whether to add a newline */ ibool add_newline) /* in: whether to add a newline */
{ {
char constraint_name[MAX_TABLE_NAME_LEN];
const char* stripped_id; const char* stripped_id;
ulint i; ulint i;
...@@ -4130,9 +4211,7 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4130,9 +4211,7 @@ dict_print_info_on_foreign_key_in_create_format(
} }
fputs(" CONSTRAINT ", file); fputs(" CONSTRAINT ", file);
innobase_convert_to_system_charset(constraint_name, stripped_id, ut_print_name(file, trx, FALSE, stripped_id);
MAX_TABLE_NAME_LEN);
ut_print_name(file, trx, FALSE, constraint_name);
fputs(" FOREIGN KEY (", file); fputs(" FOREIGN KEY (", file);
for (i = 0;;) { for (i = 0;;) {
......
...@@ -901,33 +901,27 @@ innobase_convert_from_table_id( ...@@ -901,33 +901,27 @@ innobase_convert_from_table_id(
/********************************************************************** /**********************************************************************
Check if the length of the identifier exceeds the maximum allowed. 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. */ return true when length of identifier is too long. */
extern "C" extern "C"
my_bool my_bool
innobase_check_identifier_length( innobase_check_identifier_length(
/*=============================*/ /*=============================*/
const char* id) /* in: identifier to check. it must belong const char* id) /* in: FK identifier to check excluding the
to charset my_charset_filename */ database portion. */
{ {
char tmp[MAX_TABLE_NAME_LEN + 10];
uint errors;
uint len;
int well_formed_error = 0; int well_formed_error = 0;
CHARSET_INFO *cs1 = &my_charset_filename; CHARSET_INFO *cs = system_charset_info;
CHARSET_INFO *cs2 = thd_charset(current_thd); 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, if (well_formed_error || res == NAME_CHAR_LEN) {
NAME_CHAR_LEN, my_error(ER_TOO_LONG_IDENT, MYF(0), id);
&well_formed_error); DBUG_RETURN(true);
if (well_formed_error || res != len) {
my_error(ER_TOO_LONG_IDENT, MYF(0), tmp);
return(true);
} }
return(false); DBUG_RETURN(false);
} }
/********************************************************************** /**********************************************************************
...@@ -957,17 +951,17 @@ innobase_convert_to_system_charset( ...@@ -957,17 +951,17 @@ innobase_convert_to_system_charset(
/*===============================*/ /*===============================*/
char* to, /* out: converted identifier */ char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */ 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; uint rlen;
CHARSET_INFO* cs1 = &my_charset_filename; CHARSET_INFO* cs1 = &my_charset_filename;
CHARSET_INFO* cs2 = system_charset_info; CHARSET_INFO* cs2 = system_charset_info;
rlen = strconvert(cs1, from, cs2, to, len, &errors); rlen = strconvert(cs1, from, cs2, to, len, errors);
if (errors) { if (*errors) {
fprintf(stderr, " InnoDB: There was a problem in converting" fprintf(stderr, "InnoDB: There was a problem in converting"
"'%s' in charset %s to charset %s", from, cs1->name, "'%s' in charset %s to charset %s", from, cs1->name,
cs2->name); cs2->name);
} }
...@@ -975,6 +969,32 @@ innobase_convert_to_system_charset( ...@@ -975,6 +969,32 @@ innobase_convert_to_system_charset(
return(rlen); 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. Compares NUL-terminated UTF-8 strings case insensitively.
......
...@@ -19,4 +19,7 @@ typedef struct dict_foreign_struct dict_foreign_t; ...@@ -19,4 +19,7 @@ typedef struct dict_foreign_struct dict_foreign_t;
typedef struct ind_node_struct ind_node_t; typedef struct ind_node_struct ind_node_t;
typedef struct tab_node_struct tab_node_t; typedef struct tab_node_struct tab_node_t;
#define TEMP_TABLE_PREFIX "#sql"
#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX
#endif #endif
...@@ -92,10 +92,19 @@ Converts an identifier from my_charset_filename to UTF-8 charset. */ ...@@ -92,10 +92,19 @@ Converts an identifier from my_charset_filename to UTF-8 charset. */
uint uint
innobase_convert_to_system_charset( innobase_convert_to_system_charset(
/*===============================*/ /*===============================*/
char* to, /* out: converted identifier */ char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */ 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 */
/**********************************************************************
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
#endif #endif
...@@ -33,6 +33,7 @@ Created 9/17/2000 Heikki Tuuri ...@@ -33,6 +33,7 @@ Created 9/17/2000 Heikki Tuuri
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "m_string.h" #include "m_string.h"
#include "my_sys.h" #include "my_sys.h"
#include "ha_prototypes.h"
/* A dummy variable used to fool the compiler */ /* A dummy variable used to fool the compiler */
ibool row_mysql_identically_false = FALSE; ibool row_mysql_identically_false = FALSE;
...@@ -3657,6 +3658,7 @@ row_rename_table_for_mysql( ...@@ -3657,6 +3658,7 @@ row_rename_table_for_mysql(
ibool old_is_tmp, new_is_tmp; ibool old_is_tmp, new_is_tmp;
pars_info_t* info = NULL; pars_info_t* info = NULL;
ulint retry = 0; ulint retry = 0;
DBUG_ENTER("row_rename_table_for_mysql");
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(old_name != NULL); ut_a(old_name != NULL);
...@@ -3672,7 +3674,7 @@ row_rename_table_for_mysql( ...@@ -3672,7 +3674,7 @@ row_rename_table_for_mysql(
stderr); stderr);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
return(DB_ERROR); DBUG_RETURN(DB_ERROR);
} }
if (row_mysql_is_system_table(new_name)) { if (row_mysql_is_system_table(new_name)) {
...@@ -3685,7 +3687,7 @@ row_rename_table_for_mysql( ...@@ -3685,7 +3687,7 @@ row_rename_table_for_mysql(
new_name); new_name);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
return(DB_ERROR); DBUG_RETURN(DB_ERROR);
} }
trx->op_info = "renaming table"; trx->op_info = "renaming table";
...@@ -3799,12 +3801,29 @@ row_rename_table_for_mysql( ...@@ -3799,12 +3801,29 @@ row_rename_table_for_mysql(
if (!new_is_tmp) { if (!new_is_tmp) {
/* Rename all constraints. */ /* Rename all constraints. */
char new_table_name[MAX_TABLE_NAME_LEN] = "";
uint errors = 0;
info = pars_info_create(); info = pars_info_create();
pars_info_add_str_literal(info, "new_table_name", new_name); pars_info_add_str_literal(info, "new_table_name", new_name);
pars_info_add_str_literal(info, "old_table_name", old_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( err = que_eval_sql(
info, info,
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
...@@ -3816,6 +3835,7 @@ row_rename_table_for_mysql( ...@@ -3816,6 +3835,7 @@ row_rename_table_for_mysql(
"old_t_name_len INT;\n" "old_t_name_len INT;\n"
"new_db_name_len INT;\n" "new_db_name_len INT;\n"
"id_len INT;\n" "id_len INT;\n"
"offset INT;\n"
"found INT;\n" "found INT;\n"
"BEGIN\n" "BEGIN\n"
"found := 1;\n" "found := 1;\n"
...@@ -3824,8 +3844,6 @@ row_rename_table_for_mysql( ...@@ -3824,8 +3844,6 @@ row_rename_table_for_mysql(
"new_db_name := SUBSTR(:new_table_name, 0,\n" "new_db_name := SUBSTR(:new_table_name, 0,\n"
" new_db_name_len);\n" " new_db_name_len);\n"
"old_t_name_len := LENGTH(:old_table_name);\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" "WHILE found = 1 LOOP\n"
" SELECT ID INTO foreign_id\n" " SELECT ID INTO foreign_id\n"
" FROM SYS_FOREIGN\n" " FROM SYS_FOREIGN\n"
...@@ -3842,12 +3860,12 @@ row_rename_table_for_mysql( ...@@ -3842,12 +3860,12 @@ row_rename_table_for_mysql(
" id_len := LENGTH(foreign_id);\n" " id_len := LENGTH(foreign_id);\n"
" IF (INSTR(foreign_id, '/') > 0) THEN\n" " IF (INSTR(foreign_id, '/') > 0) THEN\n"
" IF (INSTR(foreign_id,\n" " IF (INSTR(foreign_id,\n"
" gen_constr_prefix) > 0)\n" " '_ibfk_') > 0)\n"
" THEN\n" " THEN\n"
" offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
" new_foreign_id :=\n" " new_foreign_id :=\n"
" CONCAT(:new_table_name,\n" " CONCAT(:new_table_utf8,\n"
" SUBSTR(foreign_id, old_t_name_len,\n" " SUBSTR(foreign_id, offset, id_len - offset));\n"
" id_len - old_t_name_len));\n"
" ELSE\n" " ELSE\n"
" new_foreign_id :=\n" " new_foreign_id :=\n"
" CONCAT(new_db_name,\n" " CONCAT(new_db_name,\n"
...@@ -4005,7 +4023,7 @@ funct_exit: ...@@ -4005,7 +4023,7 @@ funct_exit:
trx->op_info = ""; trx->op_info = "";
return((int) err); DBUG_RETURN((int) err);
} }
/************************************************************************* /*************************************************************************
......
...@@ -44,6 +44,21 @@ Created 1/8/1996 Heikki Tuuri ...@@ -44,6 +44,21 @@ Created 1/8/1996 Heikki Tuuri
#include "ut0vec.h" #include "ut0vec.h"
#include "ha_prototypes.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 Based on a table object, this function builds the entry to be inserted
in the SYS_TABLES system table. in the SYS_TABLES system table.
...@@ -1426,26 +1441,47 @@ dict_create_add_foreign_to_dictionary( ...@@ -1426,26 +1441,47 @@ dict_create_add_foreign_to_dictionary(
{ {
ulint error; ulint error;
ulint i; ulint i;
pars_info_t* info;
pars_info_t* info = pars_info_create();
if (foreign->id == NULL) { if (foreign->id == NULL) {
char* stripped_name;
/* Generate a new constraint id */ /* Generate a new constraint id */
ulint namelen = strlen(table->name); ulint namelen = strlen(table->name);
char* id = mem_heap_alloc(foreign->heap, namelen + 20); 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 (row_is_mysql_tmp_table_name(table->name)) {
if (innobase_check_identifier_length(stripped_name)) { sprintf(id, "%s_ibfk_%lu", table->name,
fprintf(stderr, "InnoDB: Generated foreign key " (ulong) (*id_nr)++);
"name (%s) is too long\n", foreign->id); } else {
return(DB_IDENTIFIER_TOO_LONG); 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, "id", foreign->id);
pars_info_add_str_literal(info, "for_name", table->name); pars_info_add_str_literal(info, "for_name", table->name);
......
...@@ -1092,22 +1092,78 @@ dict_table_rename_in_cache( ...@@ -1092,22 +1092,78 @@ dict_table_rename_in_cache(
strcpy(foreign->foreign_table_name, table->name); strcpy(foreign->foreign_table_name, table->name);
if (strchr(foreign->id, '/')) { if (strchr(foreign->id, '/')) {
/* This is a >= 4.0.18 format id */
ulint db_len; ulint db_len;
char* old_id; 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); 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) + ((sizeof dict_ibfk) - 1)
&& !memcmp(foreign->id, old_name, && !memcmp(fkid, old_name_cs_filename,
ut_strlen(old_name)) ut_strlen(old_name_cs_filename))
&& !memcmp(foreign->id + ut_strlen(old_name), && !memcmp(fkid + ut_strlen(old_name_cs_filename),
dict_ibfk, (sizeof dict_ibfk) - 1)) { dict_ibfk, (sizeof dict_ibfk) - 1)) {
/* This is a generated >= 4.0.18 format id */ /* 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)) { if (strlen(table->name) > strlen(old_name)) {
foreign->id = mem_heap_alloc( foreign->id = mem_heap_alloc(
foreign->heap, foreign->heap,
...@@ -1115,11 +1171,36 @@ dict_table_rename_in_cache( ...@@ -1115,11 +1171,36 @@ dict_table_rename_in_cache(
+ strlen(old_id) + 1); + 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' /* Replace the prefix 'databasename/tablename'
with the new names */ with the new names */
strcpy(foreign->id, table->name); strcpy(foreign->id, table_name);
strcat(foreign->id, if (on_tmp) {
old_id + ut_strlen(old_name)); 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 { } else {
/* This is a >= 4.0.18 format id where the user /* This is a >= 4.0.18 format id where the user
gave the id name */ gave the id name */
...@@ -4602,7 +4683,6 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4602,7 +4683,6 @@ dict_print_info_on_foreign_key_in_create_format(
dict_foreign_t* foreign, /*!< in: foreign key constraint */ dict_foreign_t* foreign, /*!< in: foreign key constraint */
ibool add_newline) /*!< in: whether to add a newline */ ibool add_newline) /*!< in: whether to add a newline */
{ {
char constraint_name[MAX_TABLE_NAME_LEN];
const char* stripped_id; const char* stripped_id;
ulint i; ulint i;
...@@ -4624,9 +4704,7 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4624,9 +4704,7 @@ dict_print_info_on_foreign_key_in_create_format(
} }
fputs(" CONSTRAINT ", file); fputs(" CONSTRAINT ", file);
innobase_convert_from_id(&my_charset_filename, constraint_name, ut_print_name(file, trx, FALSE, stripped_id);
stripped_id, MAX_TABLE_NAME_LEN);
ut_print_name(file, trx, FALSE, constraint_name);
fputs(" FOREIGN KEY (", file); fputs(" FOREIGN KEY (", file);
for (i = 0;;) { for (i = 0;;) {
......
...@@ -1013,33 +1013,27 @@ innobase_convert_from_table_id( ...@@ -1013,33 +1013,27 @@ innobase_convert_from_table_id(
/********************************************************************** /**********************************************************************
Check if the length of the identifier exceeds the maximum allowed. 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. */ return true when length of identifier is too long. */
extern "C" UNIV_INTERN extern "C"
my_bool my_bool
innobase_check_identifier_length( innobase_check_identifier_length(
/*=============================*/ /*=============================*/
const char* id) /* in: identifier to check. it must belong const char* id) /* in: FK identifier to check excluding the
to charset my_charset_filename */ database portion. */
{ {
char tmp[MAX_TABLE_NAME_LEN + 10];
uint errors;
uint len;
int well_formed_error = 0; int well_formed_error = 0;
CHARSET_INFO* cs1 = &my_charset_filename; CHARSET_INFO *cs = system_charset_info;
CHARSET_INFO* cs2 = thd_charset(current_thd); DBUG_ENTER("innobase_check_identifier_length");
len = strconvert(cs1, id, cs2, tmp, MAX_TABLE_NAME_LEN + 10, &errors);
uint res = cs2->cset->well_formed_len(cs2, tmp, tmp + len, uint res = cs->cset->well_formed_len(cs, id, id + strlen(id),
NAME_CHAR_LEN, NAME_CHAR_LEN,
&well_formed_error); &well_formed_error);
if (well_formed_error || res != len) { if (well_formed_error || res == NAME_CHAR_LEN) {
my_error(ER_TOO_LONG_IDENT, MYF(0), tmp); my_error(ER_TOO_LONG_IDENT, MYF(0), id);
return(true); DBUG_RETURN(true);
} }
return(false); DBUG_RETURN(false);
} }
/******************************************************************//** /******************************************************************//**
...@@ -11614,4 +11608,30 @@ test_innobase_convert_name() ...@@ -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 */ #endif /* UNIV_COMPILE_TEST_FUNCS */
...@@ -40,4 +40,7 @@ typedef struct tab_node_struct tab_node_t; ...@@ -40,4 +40,7 @@ typedef struct tab_node_struct tab_node_t;
#define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */ #define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */
#define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO #define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO
#define TEMP_TABLE_PREFIX "#sql"
#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX
#endif #endif
...@@ -279,4 +279,24 @@ innobase_check_identifier_length( ...@@ -279,4 +279,24 @@ innobase_check_identifier_length(
const char* id); /* in: identifier to check. it must belong const char* id); /* in: identifier to check. it must belong
to charset my_charset_filename */ 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 #endif
...@@ -51,6 +51,7 @@ Created 9/17/2000 Heikki Tuuri ...@@ -51,6 +51,7 @@ Created 9/17/2000 Heikki Tuuri
#include "btr0sea.h" #include "btr0sea.h"
#include "fil0fil.h" #include "fil0fil.h"
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "ha_prototypes.h"
#ifdef __WIN__ #ifdef __WIN__
/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */ /* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */
...@@ -3902,12 +3903,29 @@ row_rename_table_for_mysql( ...@@ -3902,12 +3903,29 @@ row_rename_table_for_mysql(
goto end; goto end;
} else if (!new_is_tmp) { } else if (!new_is_tmp) {
/* Rename all constraints. */ /* Rename all constraints. */
char new_table_name[MAX_TABLE_NAME_LEN] = "";
uint errors = 0;
info = pars_info_create(); info = pars_info_create();
pars_info_add_str_literal(info, "new_table_name", new_name); pars_info_add_str_literal(info, "new_table_name", new_name);
pars_info_add_str_literal(info, "old_table_name", old_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( err = que_eval_sql(
info, info,
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
...@@ -3919,6 +3937,7 @@ row_rename_table_for_mysql( ...@@ -3919,6 +3937,7 @@ row_rename_table_for_mysql(
"old_t_name_len INT;\n" "old_t_name_len INT;\n"
"new_db_name_len INT;\n" "new_db_name_len INT;\n"
"id_len INT;\n" "id_len INT;\n"
"offset INT;\n"
"found INT;\n" "found INT;\n"
"BEGIN\n" "BEGIN\n"
"found := 1;\n" "found := 1;\n"
...@@ -3927,8 +3946,6 @@ row_rename_table_for_mysql( ...@@ -3927,8 +3946,6 @@ row_rename_table_for_mysql(
"new_db_name := SUBSTR(:new_table_name, 0,\n" "new_db_name := SUBSTR(:new_table_name, 0,\n"
" new_db_name_len);\n" " new_db_name_len);\n"
"old_t_name_len := LENGTH(:old_table_name);\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" "WHILE found = 1 LOOP\n"
" SELECT ID INTO foreign_id\n" " SELECT ID INTO foreign_id\n"
" FROM SYS_FOREIGN\n" " FROM SYS_FOREIGN\n"
...@@ -3945,12 +3962,13 @@ row_rename_table_for_mysql( ...@@ -3945,12 +3962,13 @@ row_rename_table_for_mysql(
" id_len := LENGTH(foreign_id);\n" " id_len := LENGTH(foreign_id);\n"
" IF (INSTR(foreign_id, '/') > 0) THEN\n" " IF (INSTR(foreign_id, '/') > 0) THEN\n"
" IF (INSTR(foreign_id,\n" " IF (INSTR(foreign_id,\n"
" gen_constr_prefix) > 0)\n" " '_ibfk_') > 0)\n"
" THEN\n" " THEN\n"
" offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
" new_foreign_id :=\n" " new_foreign_id :=\n"
" CONCAT(:new_table_name,\n" " CONCAT(:new_table_utf8,\n"
" SUBSTR(foreign_id, old_t_name_len,\n" " SUBSTR(foreign_id, offset,\n"
" id_len - old_t_name_len));\n" " id_len - offset));\n"
" ELSE\n" " ELSE\n"
" new_foreign_id :=\n" " new_foreign_id :=\n"
" CONCAT(new_db_name,\n" " CONCAT(new_db_name,\n"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment