diff options
author | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2013-02-12 14:52:48 +0530 |
---|---|---|
committer | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2013-02-12 14:52:48 +0530 |
commit | 8aecb30cdd1eea3517684dfc8d9d598b59396316 (patch) | |
tree | e7fe35b57020e80c8783949c6aba4638aba6b369 /storage/innobase | |
parent | b0f78ea2780858ef8e4501b40611c20efb9e5f9f (diff) | |
download | mariadb-git-8aecb30cdd1eea3517684dfc8d9d598b59396316.tar.gz |
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.
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/dict/dict0crea.c | 9 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.c | 6 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 63 | ||||
-rw-r--r-- | storage/innobase/include/db0err.h | 1 | ||||
-rw-r--r-- | storage/innobase/include/ha_prototypes.h | 22 |
5 files changed, 100 insertions, 1 deletions
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 <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;;) { 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)); @@ -895,6 +900,37 @@ 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 */ +{ + 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. NOTE that the exact prototype of this function has to be in @@ -914,6 +950,33 @@ innobase_convert_from_id( } /********************************************************************** +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. NOTE that the exact prototype of this function has to be in 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 |