mirror of
https://github.com/MariaDB/server.git
synced 2025-05-28 13:01:41 +03:00
MDEV-8524: Improve error messaging when there is duplicate key or foreign key names
Added better error message that will be printed when foreign key constraint name in create table is not unique in database.
This commit is contained in:
parent
392df76bc3
commit
e05cd97b8a
20
mysql-test/suite/innodb/r/innodb-fk-warnings.result
Normal file
20
mysql-test/suite/innodb/r/innodb-fk-warnings.result
Normal file
@ -0,0 +1,20 @@
|
||||
CREATE TABLE t1 (
|
||||
id int(11) NOT NULL PRIMARY KEY,
|
||||
a int(11) NOT NULL,
|
||||
b int(11) NOT NULL,
|
||||
c int not null,
|
||||
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
CREATE TABLE t2 (
|
||||
id int(11) NOT NULL PRIMARY KEY,
|
||||
a int(11) NOT NULL,
|
||||
b int(11) NOT NULL,
|
||||
c int not null,
|
||||
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 121)
|
||||
show warnings;
|
||||
Level Code Message
|
||||
Warning 121 InnoDB: foreign key constraint name `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`).
|
||||
Error 1005 Can't create table 'test.t2' (errno: 121)
|
||||
drop table t1;
|
29
mysql-test/suite/innodb/t/innodb-fk-warnings.test
Normal file
29
mysql-test/suite/innodb/t/innodb-fk-warnings.test
Normal file
@ -0,0 +1,29 @@
|
||||
--source include/have_innodb.inc
|
||||
|
||||
#
|
||||
# MDEV-8524: Improve error messaging when there is duplicate key or foreign key names
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
id int(11) NOT NULL PRIMARY KEY,
|
||||
a int(11) NOT NULL,
|
||||
b int(11) NOT NULL,
|
||||
c int not null,
|
||||
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
#
|
||||
# Below create table fails because constraint name test
|
||||
# is reserved for above table.
|
||||
#
|
||||
--error 1005
|
||||
CREATE TABLE t2 (
|
||||
id int(11) NOT NULL PRIMARY KEY,
|
||||
a int(11) NOT NULL,
|
||||
b int(11) NOT NULL,
|
||||
c int not null,
|
||||
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
show warnings;
|
||||
|
||||
drop table t1;
|
@ -1419,6 +1419,91 @@ dict_create_add_foreign_field_to_dictionary(
|
||||
table, foreign, trx));
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Construct foreign key constraint defintion from data dictionary information.
|
||||
*/
|
||||
static
|
||||
char*
|
||||
dict_foreign_def_get(
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
trx_t* trx) /*!< in: trx */
|
||||
{
|
||||
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
|
||||
const char* tbname;
|
||||
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
int i;
|
||||
|
||||
tbname = dict_remove_db_name(foreign->id);
|
||||
innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||
tbname, strlen(tbname), trx->mysql_thd, FALSE);
|
||||
|
||||
sprintf(fk_def,
|
||||
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
|
||||
|
||||
for(i = 0; i < foreign->n_fields; i++) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->foreign_col_names[i],
|
||||
strlen(foreign->foreign_col_names[i]),
|
||||
trx->mysql_thd, FALSE);
|
||||
strcat(fk_def, buf);
|
||||
if (i < foreign->n_fields-1) {
|
||||
strcat(fk_def, (char *)",");
|
||||
}
|
||||
}
|
||||
|
||||
strcat(fk_def,(char *)") REFERENCES ");
|
||||
|
||||
innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_table_name,
|
||||
strlen(foreign->referenced_table_name),
|
||||
trx->mysql_thd, TRUE);
|
||||
|
||||
strcat(fk_def, tablebuf);
|
||||
strcat(fk_def, " (");
|
||||
|
||||
for(i = 0; i < foreign->n_fields; i++) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_col_names[i],
|
||||
strlen(foreign->referenced_col_names[i]),
|
||||
trx->mysql_thd, FALSE);
|
||||
strcat(fk_def, buf);
|
||||
if (i < foreign->n_fields-1) {
|
||||
strcat(fk_def, (char *)",");
|
||||
}
|
||||
}
|
||||
strcat(fk_def, (char *)")");
|
||||
|
||||
return fk_def;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Convert foreign key column names from data dictionary to SQL-layer.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dict_foreign_def_get_fields(
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
trx_t* trx, /*!< in: trx */
|
||||
char** field, /*!< out: foreign column */
|
||||
char** field2, /*!< out: referenced column */
|
||||
int col_no) /*!< in: column number */
|
||||
{
|
||||
*field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||
*field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||
|
||||
innobase_convert_name(*field, MAX_TABLE_NAME_LEN,
|
||||
foreign->foreign_col_names[col_no],
|
||||
strlen(foreign->foreign_col_names[col_no]),
|
||||
trx->mysql_thd, FALSE);
|
||||
|
||||
innobase_convert_name(*field, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_col_names[col_no],
|
||||
strlen(foreign->referenced_col_names[col_no]),
|
||||
trx->mysql_thd, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Add a single foreign key definition to the data dictionary tables in the
|
||||
database. We also generate names to constraints that were not named by the
|
||||
@ -1501,6 +1586,22 @@ dict_create_add_foreign_to_dictionary(
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
if (error == DB_DUPLICATE_KEY) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
char* fk_def;
|
||||
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||
|
||||
fk_def = dict_foreign_def_get(foreign, trx);
|
||||
|
||||
ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s "
|
||||
"already exists on data dictionary."
|
||||
" Foreign key constraint names need to be unique in database."
|
||||
" Error in foreign key definition: %s.",
|
||||
buf, fk_def);
|
||||
}
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -1509,6 +1610,20 @@ dict_create_add_foreign_to_dictionary(
|
||||
i, table, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
char* field=NULL;
|
||||
char* field2=NULL;
|
||||
char* fk_def;
|
||||
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||
fk_def = dict_foreign_def_get(foreign, trx);
|
||||
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
|
||||
|
||||
ib_push_warning(trx, error,
|
||||
(const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary."
|
||||
" Error in foreign key definition: %s.",
|
||||
buf, i+1, fk_def);
|
||||
|
||||
return(error);
|
||||
}
|
||||
@ -1593,7 +1708,7 @@ dict_create_add_foreigns_to_dictionary(
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
|
||||
|
||||
error = dict_create_add_foreign_to_dictionary(&number, table,
|
||||
foreign, trx);
|
||||
foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
|
@ -12304,3 +12304,29 @@ ib_warn_row_too_big(const dict_table_t* table)
|
||||
" ROW_FORMAT=COMPRESSED ": ""
|
||||
, prefix ? DICT_MAX_FIXED_COL_LEN : 0);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||
extern "C" UNIV_INTERN
|
||||
void
|
||||
ib_push_warning(
|
||||
trx_t* trx, /*!< in: trx */
|
||||
ulint error, /*!< in: error code to push as warning */
|
||||
const char *format,/*!< in: warning message */
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
THD *thd = (THD *)trx->mysql_thd;
|
||||
char *buf;
|
||||
#define MAX_BUF_SIZE 4*1024
|
||||
|
||||
va_start(args, format);
|
||||
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
|
||||
vsprintf(buf,format, args);
|
||||
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
convert_error_code_to_mysql(error, 0, thd),
|
||||
buf);
|
||||
my_free(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -326,5 +326,14 @@ innobase_convert_to_filename_charset(
|
||||
const char* from, /* in: identifier to convert */
|
||||
ulint len); /* in: length of 'to', in bytes */
|
||||
|
||||
/********************************************************************//**
|
||||
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ib_push_warning(
|
||||
trx_t* trx, /*!< in: trx */
|
||||
ulint error, /*!< in: error code to push as warning */
|
||||
const char *format,/*!< in: warning message */
|
||||
...);
|
||||
|
||||
#endif
|
||||
|
@ -1626,6 +1626,91 @@ dict_create_add_foreign_field_to_dictionary(
|
||||
table, foreign, trx));
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Construct foreign key constraint defintion from data dictionary information.
|
||||
*/
|
||||
static
|
||||
char*
|
||||
dict_foreign_def_get(
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
trx_t* trx) /*!< in: trx */
|
||||
{
|
||||
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
|
||||
const char* tbname;
|
||||
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
int i;
|
||||
|
||||
tbname = dict_remove_db_name(foreign->id);
|
||||
innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||
tbname, strlen(tbname), trx->mysql_thd, FALSE);
|
||||
|
||||
sprintf(fk_def,
|
||||
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
|
||||
|
||||
for(i = 0; i < foreign->n_fields; i++) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->foreign_col_names[i],
|
||||
strlen(foreign->foreign_col_names[i]),
|
||||
trx->mysql_thd, FALSE);
|
||||
strcat(fk_def, buf);
|
||||
if (i < foreign->n_fields-1) {
|
||||
strcat(fk_def, (char *)",");
|
||||
}
|
||||
}
|
||||
|
||||
strcat(fk_def,(char *)") REFERENCES ");
|
||||
|
||||
innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_table_name,
|
||||
strlen(foreign->referenced_table_name),
|
||||
trx->mysql_thd, TRUE);
|
||||
|
||||
strcat(fk_def, tablebuf);
|
||||
strcat(fk_def, " (");
|
||||
|
||||
for(i = 0; i < foreign->n_fields; i++) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_col_names[i],
|
||||
strlen(foreign->referenced_col_names[i]),
|
||||
trx->mysql_thd, FALSE);
|
||||
strcat(fk_def, buf);
|
||||
if (i < foreign->n_fields-1) {
|
||||
strcat(fk_def, (char *)",");
|
||||
}
|
||||
}
|
||||
strcat(fk_def, (char *)")");
|
||||
|
||||
return fk_def;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Convert foreign key column names from data dictionary to SQL-layer.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dict_foreign_def_get_fields(
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
trx_t* trx, /*!< in: trx */
|
||||
char** field, /*!< out: foreign column */
|
||||
char** field2, /*!< out: referenced column */
|
||||
int col_no) /*!< in: column number */
|
||||
{
|
||||
*field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||
*field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||
|
||||
innobase_convert_name(*field, MAX_TABLE_NAME_LEN,
|
||||
foreign->foreign_col_names[col_no],
|
||||
strlen(foreign->foreign_col_names[col_no]),
|
||||
trx->mysql_thd, FALSE);
|
||||
|
||||
innobase_convert_name(*field, MAX_TABLE_NAME_LEN,
|
||||
foreign->referenced_col_names[col_no],
|
||||
strlen(foreign->referenced_col_names[col_no]),
|
||||
trx->mysql_thd, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Add a single foreign key definition to the data dictionary tables in the
|
||||
database. We also generate names to constraints that were not named by the
|
||||
@ -1708,6 +1793,22 @@ dict_create_add_foreign_to_dictionary(
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
if (error == DB_DUPLICATE_KEY) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
char* fk_def;
|
||||
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||
|
||||
fk_def = dict_foreign_def_get(foreign, trx);
|
||||
|
||||
ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s "
|
||||
"already exists on data dictionary."
|
||||
" Foreign key constraint names need to be unique in database."
|
||||
" Error in foreign key definition: %s.",
|
||||
buf, fk_def);
|
||||
}
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -1716,6 +1817,20 @@ dict_create_add_foreign_to_dictionary(
|
||||
i, table, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||
char* field=NULL;
|
||||
char* field2=NULL;
|
||||
char* fk_def;
|
||||
|
||||
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||
fk_def = dict_foreign_def_get(foreign, trx);
|
||||
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
|
||||
|
||||
ib_push_warning(trx, error,
|
||||
(const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary."
|
||||
" Error in foreign key definition: %s.",
|
||||
buf, i+1, fk_def);
|
||||
|
||||
return(error);
|
||||
}
|
||||
@ -1800,7 +1915,7 @@ dict_create_add_foreigns_to_dictionary(
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
|
||||
|
||||
error = dict_create_add_foreign_to_dictionary(&number, table,
|
||||
foreign, trx);
|
||||
foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
|
@ -14107,3 +14107,28 @@ ha_innobase::idx_cond_push(
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||
extern "C" UNIV_INTERN
|
||||
void
|
||||
ib_push_warning(
|
||||
trx_t* trx, /*!< in: trx */
|
||||
ulint error, /*!< in: error code to push as warning */
|
||||
const char *format,/*!< in: warning message */
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
THD *thd = (THD *)trx->mysql_thd;
|
||||
char *buf;
|
||||
#define MAX_BUF_SIZE 4*1024
|
||||
|
||||
va_start(args, format);
|
||||
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
|
||||
vsprintf(buf,format, args);
|
||||
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
convert_error_code_to_mysql(error, 0, thd),
|
||||
buf);
|
||||
my_free(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -353,5 +353,14 @@ innobase_convert_to_filename_charset(
|
||||
const char* from, /* in: identifier to convert */
|
||||
ulint len); /* in: length of 'to', in bytes */
|
||||
|
||||
/********************************************************************//**
|
||||
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ib_push_warning(
|
||||
trx_t* trx, /*!< in: trx */
|
||||
ulint error, /*!< in: error code to push as warning */
|
||||
const char *format,/*!< in: warning message */
|
||||
...);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user