1
0
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:
Jan Lindström 2015-07-29 05:58:45 +03:00
parent 392df76bc3
commit e05cd97b8a
8 changed files with 350 additions and 2 deletions

View 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;

View 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;

View File

@ -1419,6 +1419,91 @@ dict_create_add_foreign_field_to_dictionary(
table, foreign, trx)); 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 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 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_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); return(error);
} }
@ -1509,6 +1610,20 @@ dict_create_add_foreign_to_dictionary(
i, table, foreign, trx); i, table, foreign, trx);
if (error != DB_SUCCESS) { 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); return(error);
} }
@ -1593,7 +1708,7 @@ dict_create_add_foreigns_to_dictionary(
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
error = dict_create_add_foreign_to_dictionary(&number, table, error = dict_create_add_foreign_to_dictionary(&number, table,
foreign, trx); foreign, trx);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {

View File

@ -12304,3 +12304,29 @@ ib_warn_row_too_big(const dict_table_t* table)
" ROW_FORMAT=COMPRESSED ": "" " ROW_FORMAT=COMPRESSED ": ""
, prefix ? DICT_MAX_FIXED_COL_LEN : 0); , 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);
}

View File

@ -326,5 +326,14 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */ const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */ 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 #endif

View File

@ -1626,6 +1626,91 @@ dict_create_add_foreign_field_to_dictionary(
table, foreign, trx)); 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 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 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_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); return(error);
} }
@ -1716,6 +1817,20 @@ dict_create_add_foreign_to_dictionary(
i, table, foreign, trx); i, table, foreign, trx);
if (error != DB_SUCCESS) { 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); return(error);
} }
@ -1800,7 +1915,7 @@ dict_create_add_foreigns_to_dictionary(
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
error = dict_create_add_foreign_to_dictionary(&number, table, error = dict_create_add_foreign_to_dictionary(&number, table,
foreign, trx); foreign, trx);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {

View File

@ -14107,3 +14107,28 @@ ha_innobase::idx_cond_push(
DBUG_RETURN(NULL); 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);
}

View File

@ -353,5 +353,14 @@ innobase_convert_to_filename_charset(
const char* from, /* in: identifier to convert */ const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */ 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 #endif