summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorAnnamalai Gurusami <annamalai.gurusami@oracle.com>2013-02-12 14:52:48 +0530
committerAnnamalai Gurusami <annamalai.gurusami@oracle.com>2013-02-12 14:52:48 +0530
commit8aecb30cdd1eea3517684dfc8d9d598b59396316 (patch)
treee7fe35b57020e80c8783949c6aba4638aba6b369 /storage/innobase
parentb0f78ea2780858ef8e4501b40611c20efb9e5f9f (diff)
downloadmariadb-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.c9
-rw-r--r--storage/innobase/dict/dict0dict.c6
-rw-r--r--storage/innobase/handler/ha_innodb.cc63
-rw-r--r--storage/innobase/include/db0err.h1
-rw-r--r--storage/innobase/include/ha_prototypes.h22
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