mirror of
https://github.com/MariaDB/server.git
synced 2026-05-14 19:07:15 +02:00
row0mysql.c, pars0pars.c, eval0eval.c, dict0load.c, dict0dict.c, dict0crea.c:
Fix bug #3478: InnoDB's FOREIGN KEY tables treated table and database names as case-insensitive; RENAME TABLE t to T would hang in an endless loop if t had a foreign key constraint defined on it dict0dict.c: Fix bug #3478: InnoDB's FOREIGN KEY tables treated table and database names as case-insensitive; RENAME TABLE t to T would hang in an endless loop if t had a foreign key constraint defined on it; fix also a hang that would occur if one tried in ALTER TABLE or RENAME TABLE to create a foreign key constraint name that collided with another existing name
This commit is contained in:
parent
35e8670301
commit
d22a24d871
6 changed files with 69 additions and 13 deletions
|
|
@ -1011,6 +1011,12 @@ dict_create_or_check_foreign_constraint_tables(void)
|
|||
there are 2 secondary indexes on SYS_FOREIGN, and they
|
||||
are defined just like below */
|
||||
|
||||
/* NOTE: when designing InnoDB's foreign key support in 2001, we made
|
||||
an error and made the table names and the foreign key id of type
|
||||
'CHAR' (internally, really a VARCHAR). We should have made the type
|
||||
VARBINARY, like in other InnoDB system tables, to get a clean
|
||||
design. */
|
||||
|
||||
str = (char *)
|
||||
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
|
|
@ -1227,9 +1233,17 @@ loop:
|
|||
fputs(".\nA foreign key constraint of name ", ef);
|
||||
ut_print_name(ef, foreign->id);
|
||||
fputs("\nalready exists."
|
||||
" (Note that internally InnoDB adds 'databasename/'\n"
|
||||
" (Note that internally InnoDB adds 'databasename/'\n"
|
||||
"in front of the user-defined constraint name).\n",
|
||||
ef);
|
||||
fputs("Note that InnoDB's FOREIGN KEY system tables store\n"
|
||||
"constraint names as case-insensitive, with the\n"
|
||||
"MySQL standard latin1_swedish_ci collation. If you\n"
|
||||
"create tables or databases whose names differ only in\n"
|
||||
"the character case, then collisions in constraint\n"
|
||||
"names can occur. Workaround: name your constraints\n"
|
||||
"explicitly with unique names.\n",
|
||||
ef);
|
||||
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ dict_index_build_internal_non_clust(
|
|||
dict_index_t* index); /* in: user representation of a non-clustered
|
||||
index */
|
||||
/**************************************************************************
|
||||
Removes a foreign constraint struct from the dictionet cache. */
|
||||
Removes a foreign constraint struct from the dictionary cache. */
|
||||
static
|
||||
void
|
||||
dict_foreign_remove_from_cache(
|
||||
|
|
@ -581,7 +581,7 @@ dict_table_get_on_id(
|
|||
dict_table_t* table;
|
||||
|
||||
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
|
||||
|| trx->dict_operation) {
|
||||
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
|
||||
/* It is a system table which will always exist in the table
|
||||
cache: we avoid acquiring the dictionary mutex, because
|
||||
if we are doing a rollback to handle an error in TABLE
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Created 4/24/1996 Heikki Tuuri
|
|||
#include "mach0data.h"
|
||||
#include "dict0dict.h"
|
||||
#include "dict0boot.h"
|
||||
#include "rem0cmp.h"
|
||||
|
||||
/************************************************************************
|
||||
Finds the first table name in the given database. */
|
||||
|
|
@ -1121,12 +1122,26 @@ loop:
|
|||
rec = btr_pcur_get_rec(&pcur);
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
|
||||
/* Check if the table name in record is the one searched for */
|
||||
if (len != ut_strlen(table_name)
|
||||
|| 0 != ut_memcmp(field, table_name, len)) {
|
||||
/* Check if the table name in the record is the one searched for; the
|
||||
following call does the comparison in the latin1_swedish_ci
|
||||
charset-collation, in a case-insensitive way. */
|
||||
|
||||
if (0 != cmp_data_data(dfield_get_type(dfield),
|
||||
dfield_get_data(dfield), dfield_get_len(dfield),
|
||||
field, len)) {
|
||||
|
||||
goto load_next_index;
|
||||
}
|
||||
|
||||
/* Since table names in SYS_FOREIGN are stored in a case-insensitive
|
||||
order, we have to check that the table name matches also in a binary
|
||||
string comparison. On Unix, MySQL allows table names that only differ
|
||||
in character case. */
|
||||
|
||||
if (0 != ut_memcmp(field, table_name, len)) {
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec)) {
|
||||
|
||||
|
|
|
|||
|
|
@ -627,7 +627,11 @@ eval_concat(
|
|||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node. */
|
||||
Evaluates a predefined function node. If the first argument is an integer,
|
||||
this function looks at the second argument which is the integer length in
|
||||
bytes, and converts the integer to a VARCHAR.
|
||||
If the first argument is of some other type, this function converts it to
|
||||
BINARY. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_to_binary(
|
||||
|
|
@ -638,12 +642,24 @@ eval_to_binary(
|
|||
que_node_t* arg2;
|
||||
dfield_t* dfield;
|
||||
byte* str1;
|
||||
ulint len;
|
||||
ulint len1;
|
||||
|
||||
arg1 = func_node->args;
|
||||
|
||||
str1 = dfield_get_data(que_node_get_val(arg1));
|
||||
|
||||
if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
|
||||
|
||||
len = dfield_get_len(que_node_get_val(arg1));
|
||||
|
||||
dfield = que_node_get_val(func_node);
|
||||
|
||||
dfield_set_data(dfield, str1, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg2);
|
||||
|
|
|
|||
|
|
@ -259,9 +259,13 @@ pars_resolve_func_data_type(
|
|||
dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
|
||||
DATA_ENGLISH, 0, 0);
|
||||
} else if (func == PARS_TO_BINARY_TOKEN) {
|
||||
ut_a(dtype_get_mtype(que_node_get_data_type(arg)) == DATA_INT);
|
||||
dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
|
||||
if (dtype_get_mtype(que_node_get_data_type(arg)) == DATA_INT) {
|
||||
dtype_set(que_node_get_data_type(node), DATA_VARCHAR,
|
||||
DATA_ENGLISH, 0, 0);
|
||||
} else {
|
||||
dtype_set(que_node_get_data_type(node), DATA_BINARY,
|
||||
0, 0, 0);
|
||||
}
|
||||
} else if (func == PARS_TO_NUMBER_TOKEN) {
|
||||
ut_a(dtype_get_mtype(que_node_get_data_type(arg))
|
||||
== DATA_VARCHAR);
|
||||
|
|
|
|||
|
|
@ -1981,7 +1981,8 @@ row_drop_table_for_mysql(
|
|||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = table_name;\n"
|
||||
" WHERE FOR_NAME = table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
|
|
@ -2381,7 +2382,8 @@ row_rename_table_for_mysql(
|
|||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = old_table_name;\n"
|
||||
" WHERE FOR_NAME = old_table_name\n"
|
||||
" AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE\n"
|
||||
|
|
@ -2414,7 +2416,8 @@ row_rename_table_for_mysql(
|
|||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n"
|
||||
"WHERE REF_NAME = old_table_name;\n";
|
||||
"WHERE REF_NAME = old_table_name\n"
|
||||
" AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n";
|
||||
static const char str5[] =
|
||||
"END;\n";
|
||||
|
||||
|
|
@ -2602,7 +2605,11 @@ row_rename_table_for_mysql(
|
|||
if (err == DB_DUPLICATE_KEY) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fputs(" InnoDB: Error: table ", stderr);
|
||||
fputs(
|
||||
" InnoDB: Error; possible reasons:\n"
|
||||
"InnoDB: 1) Table rename would cause two FOREIGN KEY constraints\n"
|
||||
"InnoDB: to have the same internal name in case-insensitive comparison.\n"
|
||||
"InnoDB: 2) table ", stderr);
|
||||
ut_print_name(stderr, new_name);
|
||||
fputs(" exists in the InnoDB internal data\n"
|
||||
"InnoDB: dictionary though MySQL is trying rename table ", stderr);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue