Commit c2e7c4d5 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

Merging the fix from mysql-5.5 to mysql-5.5.32-release.
parent ed37f5a7
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -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.
...@@ -1424,25 +1439,45 @@ dict_create_add_foreign_to_dictionary( ...@@ -1424,25 +1439,45 @@ 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 {
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); 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);
......
...@@ -1116,22 +1116,78 @@ dict_table_rename_in_cache( ...@@ -1116,22 +1116,78 @@ dict_table_rename_in_cache(
dict_mem_foreign_table_name_lookup_set(foreign, FALSE); dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
} }
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,
...@@ -1139,11 +1195,36 @@ dict_table_rename_in_cache( ...@@ -1139,11 +1195,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);
if (on_tmp) {
strcat(foreign->id, strcat(foreign->id,
old_id + ut_strlen(old_name)); 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 */
...@@ -4691,7 +4772,6 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4691,7 +4772,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;
...@@ -4713,9 +4793,7 @@ dict_print_info_on_foreign_key_in_create_format( ...@@ -4713,9 +4793,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;;) {
......
...@@ -1159,33 +1159,27 @@ innobase_convert_from_table_id( ...@@ -1159,33 +1159,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 = cs->cset->well_formed_len(cs, id, id + strlen(id),
uint res = cs2->cset->well_formed_len(cs2, tmp, tmp + len,
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);
} }
/******************************************************************//** /******************************************************************//**
...@@ -11966,3 +11960,55 @@ test_innobase_convert_name() ...@@ -11966,3 +11960,55 @@ test_innobase_convert_name()
} }
#endif /* UNIV_COMPILE_TEST_FUNCS */ #endif /* UNIV_COMPILE_TEST_FUNCS */
/**********************************************************************
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);
}
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset. */
extern "C"
uint
innobase_convert_to_system_charset(
/*===============================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len, /* in: length of 'to', in bytes */
uint* errors) /* out: error return */
{
uint rlen;
CHARSET_INFO* cs1 = &my_charset_filename;
CHARSET_INFO* cs2 = system_charset_info;
rlen = strconvert(cs1, from, cs2, to, len, errors);
if (*errors) {
fprintf(stderr, "InnoDB: There was a problem in converting"
"'%s' in charset %s to charset %s", from, cs1->name,
cs2->name);
}
return(rlen);
}
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -58,4 +58,7 @@ enum dict_err_ignore { ...@@ -58,4 +58,7 @@ enum dict_err_ignore {
typedef enum dict_err_ignore dict_err_ignore_t; typedef enum dict_err_ignore dict_err_ignore_t;
#define TEMP_TABLE_PREFIX "#sql"
#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX
#endif #endif
/***************************************************************************** /*****************************************************************************
Copyright (c) 2006, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -307,4 +307,24 @@ innobase_check_identifier_length( ...@@ -307,4 +307,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
...@@ -53,7 +53,7 @@ Created 9/17/2000 Heikki Tuuri ...@@ -53,7 +53,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"
/** Provide optional 4.x backwards compatibility for 5.0 and above */ /** Provide optional 4.x backwards compatibility for 5.0 and above */
UNIV_INTERN ibool row_rollback_on_timeout = FALSE; UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
...@@ -3956,12 +3956,29 @@ row_rename_table_for_mysql( ...@@ -3956,12 +3956,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"
...@@ -3973,6 +3990,7 @@ row_rename_table_for_mysql( ...@@ -3973,6 +3990,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"
...@@ -3981,8 +3999,6 @@ row_rename_table_for_mysql( ...@@ -3981,8 +3999,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"
...@@ -3999,12 +4015,13 @@ row_rename_table_for_mysql( ...@@ -3999,12 +4015,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