mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 11:01:52 +01:00
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
This commit is contained in:
parent
ce38f6b441
commit
068e6673a0
12 changed files with 444 additions and 104 deletions
|
@ -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);
|
||||
|
|
|
@ -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;;) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;;) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue