Commit b39370bc authored by Annamalai Gurusami's avatar Annamalai Gurusami

Bug #11753153 INNODB GENERATES SYMBOLS THAT ARE TOO LONG, INVALID DDL

FROM SHOW CREATE

Problem: The length of the internally generated foreign key name 
is not checked. 

Solution: The length of the internally generated foreign key name is
checked.  If it is greater than the allowed limit, an error message
is reported. Also, the constraint name is printed in the same manner
as the table name, using the system charset information.

rb://1969 approved by Marko.
parent cf400bba
......@@ -25,6 +25,7 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0roll.h"
#include "usr0sess.h"
#include "ut0vec.h"
#include "ha_prototypes.h"
/*********************************************************************
Based on a table object, this function builds the entry to be inserted
......@@ -1350,12 +1351,20 @@ dict_create_add_foreign_to_dictionary(
pars_info_t* info = pars_info_create();
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);
}
}
pars_info_add_str_literal(info, "id", foreign->id);
......
......@@ -31,6 +31,7 @@ Created 1/8/1996 Heikki Tuuri
#ifndef UNIV_HOTBACKUP
# include "m_ctype.h" /* my_isspace() */
#endif /* !UNIV_HOTBACKUP */
#include "ha_prototypes.h"
#include <ctype.h>
......@@ -4107,6 +4108,7 @@ 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;
......@@ -4128,7 +4130,9 @@ dict_print_info_on_foreign_key_in_create_format(
}
fputs(" CONSTRAINT ", file);
ut_print_name(file, trx, FALSE, stripped_id);
innobase_convert_to_system_charset(constraint_name, stripped_id,
MAX_TABLE_NAME_LEN);
ut_print_name(file, trx, FALSE, constraint_name);
fputs(" FOREIGN KEY (", file);
for (i = 0;;) {
......
......@@ -791,6 +791,11 @@ convert_error_code_to_mysql(
} else if (error == DB_UNSUPPORTED) {
return(HA_ERR_UNSUPPORTED);
} else if (error == DB_IDENTIFIER_TOO_LONG) {
return(HA_ERR_INTERNAL_ERROR);
} else if (error == DB_INTERRUPTED) {
my_error(ER_QUERY_INTERRUPTED, MYF(0));
......@@ -894,6 +899,37 @@ innobase_convert_from_table_id(
&my_charset_filename, to, (uint) len, &errors);
}
/**********************************************************************
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 */
{
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);
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);
}
return(false);
}
/**********************************************************************
Converts an identifier to UTF-8.
......@@ -913,6 +949,33 @@ innobase_convert_from_id(
system_charset_info, to, (uint) len, &errors);
}
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset. */
extern "C"
uint
innobase_convert_to_system_charset(
/*===============================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
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);
}
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
......
......@@ -84,6 +84,7 @@ Created 5/24/1996 Heikki Tuuri
foreign keys as its prefix columns */
#define DB_TABLE_IN_FK_CHECK 53 /* table is being used in foreign
key check */
#define DB_IDENTIFIER_TOO_LONG 54 /* Identifier name too long */
/* The following are partial failure codes */
#define DB_FAIL 1000
......
......@@ -75,5 +75,27 @@ thd_is_select(
/* out: true if thd is executing SELECT */
const void* thd); /* in: thread handle (THD*) */
/**********************************************************************
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. */
my_bool
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 */
#endif
#endif
......@@ -42,6 +42,7 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0roll.h"
#include "usr0sess.h"
#include "ut0vec.h"
#include "ha_prototypes.h"
/*****************************************************************//**
Based on a table object, this function builds the entry to be inserted
......@@ -1429,12 +1430,20 @@ dict_create_add_foreign_to_dictionary(
pars_info_t* info = pars_info_create();
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);
}
}
pars_info_add_str_literal(info, "id", foreign->id);
......
......@@ -4602,6 +4602,7 @@ 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;
......@@ -4623,7 +4624,9 @@ dict_print_info_on_foreign_key_in_create_format(
}
fputs(" CONSTRAINT ", file);
ut_print_name(file, trx, FALSE, stripped_id);
innobase_convert_from_id(&my_charset_filename, constraint_name,
stripped_id, MAX_TABLE_NAME_LEN);
ut_print_name(file, trx, FALSE, constraint_name);
fputs(" FOREIGN KEY (", file);
for (i = 0;;) {
......
......@@ -931,6 +931,9 @@ convert_error_code_to_mysql(
return(HA_ERR_UNSUPPORTED);
case DB_OUT_OF_MEMORY:
return(HA_ERR_OUT_OF_MEM);
case DB_IDENTIFIER_TOO_LONG:
my_error(ER_TOO_LONG_IDENT, MYF(0));
return(HA_ERR_INTERNAL_ERROR);
}
}
......@@ -1009,6 +1012,37 @@ innobase_convert_from_table_id(
strconvert(cs, from, &my_charset_filename, to, (uint) len, &errors);
}
/**********************************************************************
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
my_bool
innobase_check_identifier_length(
/*=============================*/
const char* id) /* in: identifier to check. it must belong
to charset my_charset_filename */
{
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);
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);
}
return(false);
}
/******************************************************************//**
Converts an identifier to UTF-8. */
extern "C" UNIV_INTERN
......
......@@ -99,6 +99,7 @@ enum db_err {
maximum allowed depth */
DB_TABLE_IN_FK_CHECK, /* table is being used in foreign
key check */
DB_IDENTIFIER_TOO_LONG, /* Identifier name too long */
/* The following are partial failure codes */
DB_FAIL = 1000,
......
......@@ -268,4 +268,15 @@ thd_lock_wait_timeout(
void* thd); /*!< in: thread handle (THD*), or NULL to query
the global innodb_lock_wait_timeout */
/**********************************************************************
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. */
UNIV_INTERN
my_bool
innobase_check_identifier_length(
/*=============================*/
const char* id); /* in: identifier to check. it must belong
to charset my_charset_filename */
#endif
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