From 8aecb30cdd1eea3517684dfc8d9d598b59396316 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Tue, 12 Feb 2013 14:52:48 +0530 Subject: 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. --- storage/innobase/dict/dict0crea.c | 9 +++++ storage/innobase/dict/dict0dict.c | 6 ++- storage/innobase/handler/ha_innodb.cc | 63 ++++++++++++++++++++++++++++++++ storage/innobase/include/db0err.h | 1 + storage/innobase/include/ha_prototypes.h | 22 +++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) (limited to 'storage/innobase') diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 4116230347d..5e0fac8b411 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -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); diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 7139eb5db95..a38b7224551 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -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 @@ -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;;) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 194a7eea795..0f373476efb 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -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. diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 1514b19639c..73bb1876b3a 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -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 diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index ce790814818..0ad3c82fffd 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -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 -- cgit v1.2.1