@ -2614,6 +2614,11 @@ dict_foreign_find(
DBUG_RETURN ( NULL ) ;
}
# define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
# define DB_FOREIGN_KEY_COL_NOT_NULL 201
# define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
# define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
/*********************************************************************/ /**
Tries to find an index whose first fields are the columns in the array ,
in the same order and is not marked for deletion and is not the same
@ -2631,12 +2636,21 @@ dict_foreign_find_index(
ibool check_charsets ,
/*!< in: whether to check charsets.
only has an effect if types_idx ! = NULL */
ulint check_null )
ulint check_null ,
/*!< in: nonzero if none of the columns must
be declared NOT NULL */
ulint * error , /*!< out: error code */
ulint * err_col_no ,
/*!< out: column number where error happened */
dict_index_t * * err_index )
/*!< out: index where error happened */
{
dict_index_t * index ;
if ( error ) {
* error = DB_FOREIGN_KEY_INDEX_NOT_FOUND ;
}
index = dict_table_get_first_index ( table ) ;
while ( index ! = NULL ) {
@ -2662,6 +2676,12 @@ dict_foreign_find_index(
/* We do not accept column prefix
indexes here */
if ( error & & err_col_no & & err_index ) {
* error = DB_FOREIGN_KEY_IS_PREFIX_INDEX ;
* err_col_no = i ;
* err_index = index ;
}
break ;
}
@ -2673,6 +2693,11 @@ dict_foreign_find_index(
if ( check_null
& & ( field - > col - > prtype & DATA_NOT_NULL ) ) {
if ( error & & err_col_no & & err_index ) {
* error = DB_FOREIGN_KEY_COL_NOT_NULL ;
* err_col_no = i ;
* err_index = index ;
}
return ( NULL ) ;
}
@ -2682,6 +2707,12 @@ dict_foreign_find_index(
i ) ,
check_charsets ) ) {
if ( error & & err_col_no & & err_index ) {
* error = DB_FOREIGN_KEY_COLS_NOT_EQUAL ;
* err_col_no = i ;
* err_index = index ;
}
break ;
}
}
@ -2689,6 +2720,10 @@ dict_foreign_find_index(
if ( i = = n_cols ) {
/* We found a matching index */
if ( error ) {
* error = DB_SUCCESS ;
}
return ( index ) ;
}
}
@ -2720,7 +2755,7 @@ dict_foreign_find_equiv_index(
foreign - > foreign_table ,
foreign - > foreign_col_names , foreign - > n_fields ,
foreign - > foreign_index , TRUE , /* check types */
FALSE /* allow columns to be NULL */ ) ) ;
FALSE /* allow columns to be NULL */ , NULL , NULL , NULL ) ) ;
}
# endif /* !UNIV_HOTBACKUP */
@ -2883,11 +2918,15 @@ dict_foreign_add_to_cache(
}
if ( for_in_cache - > referenced_table = = NULL & & ref_table ) {
ulint index_error ;
ulint err_col ;
dict_index_t * err_index = NULL ;
index = dict_foreign_find_index (
ref_table ,
for_in_cache - > referenced_col_names ,
for_in_cache - > n_fields , for_in_cache - > foreign_index ,
check_charsets , FALSE ) ;
check_charsets , FALSE , & index_error , & err_col , & err_index ) ;
if ( index = = NULL
& & ! ( ignore_err & DICT_ERR_IGNORE_FK_NOKEY ) ) {
@ -2919,6 +2958,9 @@ dict_foreign_add_to_cache(
}
if ( for_in_cache - > foreign_table = = NULL & & for_table ) {
ulint index_error ;
ulint err_col ;
dict_index_t * err_index = NULL ;
index = dict_foreign_find_index (
for_table ,
@ -2927,7 +2969,8 @@ dict_foreign_add_to_cache(
for_in_cache - > referenced_index , check_charsets ,
for_in_cache - > type
& ( DICT_FOREIGN_ON_DELETE_SET_NULL
| DICT_FOREIGN_ON_UPDATE_SET_NULL ) ) ;
| DICT_FOREIGN_ON_UPDATE_SET_NULL ) ,
& index_error , & err_col , & err_index ) ;
if ( index = = NULL
& & ! ( ignore_err & DICT_ERR_IGNORE_FK_NOKEY ) ) {
@ -3538,6 +3581,8 @@ static
void
dict_foreign_report_syntax_err (
/*===========================*/
const char * fmt , /*!< in: syntax err msg */
const char * oper , /*!< in: operation */
const char * name , /*!< in: table name */
const char * start_of_latest_foreign ,
/*!< in: start of the foreign key clause
@ -3548,11 +3593,101 @@ dict_foreign_report_syntax_err(
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n Syntax error close to: \n %s \n " ,
start_of_latest_foreign , ptr ) ;
fprintf ( ef , fmt , oper , name , start_of_latest_foreign , ptr ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
}
/*********************************************************************/ /**
Push warning message to SQL - layer based on foreign key constraint
index match error . */
static
void
dict_foreign_push_index_error (
/*==========================*/
trx_t * trx , /*!< in: trx */
const char * operation , /*!< in: operation create or alter
*/
const char * create_name , /*!< in: table name in create or
alter table */
const char * latest_foreign , /*!< in: start of latest foreign key
constraint name */
const char * * columns , /*!< in: foreign key columns */
ulint index_error , /*!< in: error code */
ulint err_col , /*!< in: column where error happened
*/
dict_index_t * err_index , /*!< in: index where error happened
*/
dict_table_t * table , /*!< in: table */
FILE * ef ) /*!< in: output stream */
{
switch ( index_error ) {
case DB_FOREIGN_KEY_INDEX_NOT_FOUND : {
fprintf ( ef ,
" %s table '%s' with foreign key constraint "
" failed. There is no index in the referenced "
" table where the referenced columns appear "
" as the first columns. Error close to %s. \n " ,
operation , create_name , latest_foreign ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table '%s' with foreign key constraint "
" failed. There is no index in the referenced "
" table where the referenced columns appear "
" as the first columns. Error close to %s. " ,
operation , create_name , latest_foreign ) ;
break ;
}
case DB_FOREIGN_KEY_IS_PREFIX_INDEX : {
fprintf ( ef ,
" %s table '%s' with foreign key constraint "
" failed. There is only prefix index in the referenced "
" table where the referenced columns appear "
" as the first columns. Error close to %s. \n " ,
operation , create_name , latest_foreign ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table '%s' with foreign key constraint "
" failed. There is only prefix index in the referenced "
" table where the referenced columns appear "
" as the first columns. Error close to %s. " ,
operation , create_name , latest_foreign ) ;
break ;
}
case DB_FOREIGN_KEY_COL_NOT_NULL : {
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. You have defined a SET NULL condition but "
" field %s on index is defined as NOT NULL close to %s \n " ,
operation , create_name , columns [ err_col ] , latest_foreign ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. You have defined a SET NULL condition but "
" field %s on index is defined as NOT NULL close to %s " ,
operation , create_name , columns [ err_col ] , latest_foreign ) ;
break ;
}
case DB_FOREIGN_KEY_COLS_NOT_EQUAL : {
dict_field_t * field ;
const char * col_name ;
field = dict_index_get_nth_field ( err_index , err_col ) ;
col_name = dict_table_get_col_name (
table , dict_col_get_no ( field - > col ) ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. Field type or character set for column %s "
" does not mach referenced column %s close to %s \n " ,
operation , create_name , columns [ err_col ] , col_name , latest_foreign ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Field type or character set for column %s "
" does not mach referenced column %s close to %s " ,
operation , create_name , columns [ err_col ] , col_name , latest_foreign ) ;
break ;
}
default :
ut_error ;
}
}
/*********************************************************************/ /**
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string . This function should be called after
@ -3581,15 +3716,20 @@ dict_create_foreign_constraints_low(
DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found . */
{
dict_table_t * table ;
dict_table_t * referenced_table ;
dict_table_t * table_to_alter ;
dict_table_t * table = NULL ;
dict_table_t * referenced_table = NULL ;
dict_table_t * table_to_alter = NULL ;
dict_table_t * table_to_create = NULL ;
ulint highest_id_so_far = 0 ;
dict_index_t * index ;
dict_foreign_t * foreign ;
dict_index_t * index = NULL ;
dict_foreign_t * foreign = NULL ;
const char * ptr = sql_string ;
const char * start_of_latest_foreign = sql_string ;
const char * start_of_latest_set = NULL ;
FILE * ef = dict_foreign_err_file ;
ulint index_error = DB_SUCCESS ;
dict_index_t * err_index = NULL ;
ulint err_col ;
const char * constraint_name ;
ibool success ;
ulint error ;
@ -3602,29 +3742,64 @@ dict_create_foreign_constraints_low(
ulint n_on_updates ;
const dict_col_t * columns [ 500 ] ;
const char * column_names [ 500 ] ;
const char * ref_column_names [ 500 ] ;
const char * referenced_table_name ;
const char * create_table_name ;
const char * orig ;
const char create_name [ MAX_TABLE_NAME_LEN + 1 ] ;
const char operation [ 8 ] ;
ut_ad ( mutex_own ( & ( dict_sys - > mutex ) ) ) ;
table = dict_table_get_low ( name , DICT_ERR_IGNORE_NONE ) ;
/* First check if we are actually doing an ALTER TABLE, and in that
case look for the table being altered */
ptr = dict_accept ( cs , ptr , " ALTER " , & success ) ;
strcpy ( ( char * ) operation , success ? " Alter " : " Create " ) ;
if ( ! success ) {
orig = ptr ;
ptr = dict_scan_to ( ptr , " CREATE " ) ;
ptr = dict_scan_to ( ptr , " TABLE " ) ;
ptr = dict_accept ( cs , ptr , " TABLE " , & success ) ;
if ( success ) {
ptr = dict_scan_table_name ( cs , ptr , & table_to_create , name ,
& success , heap , & create_table_name ) ;
}
if ( success ) {
innobase_convert_name ( ( char * ) create_name , MAX_TABLE_NAME_LEN ,
create_table_name , strlen ( create_table_name ) ,
trx - > mysql_thd , TRUE ) ;
ptr = orig ;
} else {
ptr = orig ;
innobase_convert_name ( ( char * ) create_name , MAX_TABLE_NAME_LEN ,
name , strlen ( name ) , trx - > mysql_thd , TRUE ) ;
}
goto loop ;
}
if ( table = = NULL ) {
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef ,
" Cannot find the table in the internal "
" data dictionary of InnoDB. \n "
" Create table statement: \n %s \n " , sql_string ) ;
dict_foreign_error_report_low ( ef , create_ name) ;
fprintf ( ef , " %s table %s with foreign key constraint "
" failed. Table %s not found from data dictionary. "
" Error close to %s . \n " ,
operation , create_name , create_name , start_of_latest_foreign ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_ERROR ,
" %s table %s with foreign key constraint "
" failed. Table %s not found from data dictionary. "
" Error close to %s. " ,
operation , create_name , create_name , start_of_latest_foreign ) ;
return ( DB_ERROR ) ;
}
/* First check if we are actually doing an ALTER TABLE, and in that
case look for the table being altered */
ptr = dict_accept ( cs , ptr , " ALTER " , & success ) ;
/* If not alter table jump to loop */
if ( ! success ) {
goto loop ;
@ -3639,13 +3814,35 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */
orig = ptr ;
ptr = dict_scan_table_name ( cs , ptr , & table_to_alter , name ,
& success , heap , & referenced_table_name ) ;
if ( table_to_alter ) {
innobase_convert_name ( ( char * ) create_name , MAX_TABLE_NAME_LEN ,
table_to_alter - > name , strlen ( table_to_alter - > name ) ,
trx - > mysql_thd , TRUE ) ;
} else {
innobase_convert_name ( ( char * ) create_name , MAX_TABLE_NAME_LEN ,
referenced_table_name , strlen ( referenced_table_name ) ,
trx - > mysql_thd , TRUE ) ;
}
if ( ! success ) {
fprintf ( stderr ,
" InnoDB: Error: could not find "
" the table being ALTERED in: \n %s \n " ,
sql_string ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. Table %s not found from data dictionary. "
" Error close to %s. \n " ,
operation , create_name , create_name , orig ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_ERROR ,
" %s table %s with foreign key constraint "
" failed. Table %s not found from data dictionary. "
" Error close to %s. " ,
operation , create_name , create_name , orig ) ;
return ( DB_ERROR ) ;
}
@ -3711,7 +3908,19 @@ loop:
if so , immediately reject the command if the table is a
temporary one . For now , this kludge will work . */
if ( reject_fks & & ( UT_LIST_GET_LEN ( table - > foreign_list ) > 0 ) ) {
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef , " %s table %s with foreign key constraint "
" failed. Temporary tables can't have foreign key constraints. "
" Error close to %s. \n " ,
operation , create_name , start_of_latest_foreign ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Temporary tables can't have foreign key constraints. "
" Error close to %s. " ,
operation , create_name , start_of_latest_foreign ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3747,11 +3956,21 @@ loop:
if ( ! success ) {
/* MySQL allows also an index id before the '('; we
skip it */
orig = ptr ;
ptr = dict_skip_word ( cs , ptr , & success ) ;
if ( ! success ) {
dict_foreign_report_syntax_err (
name , start_of_latest_foreign , ptr ) ;
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3771,15 +3990,26 @@ loop:
/* Scan the columns in the first list */
col_loop1 :
ut_a ( i < ( sizeof column_names ) / sizeof * column_names ) ;
orig = ptr ;
ptr = dict_scan_col ( cs , ptr , & success , table , columns + i ,
heap , column_names + i ) ;
if ( ! success ) {
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n Cannot resolve column name close to: \n %s \n " ,
start_of_latest_foreign , ptr ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3791,11 +4021,22 @@ col_loop1:
goto col_loop1 ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " ) " , & success ) ;
if ( ! success ) {
dict_foreign_report_syntax_err (
name , start_of_latest_foreign , ptr ) ;
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3803,27 +4044,41 @@ col_loop1:
as the first fields and in the right order */
index = dict_foreign_find_index ( table , column_names , i ,
NULL , TRUE , FALSE ) ;
NULL , TRUE , FALSE , & index_error , & err_col , & err_index ) ;
if ( ! index ) {
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
dict_foreign_error_report_low ( ef , create_ name) ;
fputs ( " There is no index in table " , ef ) ;
ut_print_name ( ef , NULL , TRUE , name ) ;
ut_print_name ( ef , NULL , TRUE , create_ name) ;
fprintf ( ef , " where the columns appear \n "
" as the first columns. Constraint: \n %s \n "
" See " REFMAN " innodb-foreign-key-constraints.html \n "
" for correct foreign key definition. \n " ,
start_of_latest_foreign ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
return ( DB_CHILD_NO_INDEX ) ;
dict_foreign_push_index_error ( trx , operation , create_name , start_of_latest_foreign ,
column_names , index_error , err_col , err_index , table , ef ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " REFERENCES " , & success ) ;
if ( ! success | | ! my_isspace ( cs , * ptr ) ) {
dict_foreign_report_syntax_err (
name , start_of_latest_foreign , ptr ) ;
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3872,24 +4127,48 @@ col_loop1:
checking of foreign key constraints ! */
if ( ! success | | ( ! referenced_table & & trx - > check_foreigns ) ) {
char buf [ MAX_TABLE_NAME_LEN + 1 ] = " " ;
innobase_convert_name ( buf , MAX_TABLE_NAME_LEN ,
referenced_table_name , strlen ( referenced_table_name ) ,
trx - > mysql_thd , TRUE ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
" close to %s. " ,
operation , create_name , buf , start_of_latest_foreign ) ;
dict_foreign_free ( foreign ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n Cannot resolve table name close to: \n "
" %s \n " ,
start_of_latest_foreign , ptr ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
" close to %s. \n " ,
operation , create_name , buf , start_of_latest_foreign ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " ( " , & success ) ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err ( name , start_of_latest_foreign ,
ptr ) ;
dict_foreign_report_syntax_err (
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3897,20 +4176,29 @@ col_loop1:
i = 0 ;
col_loop2 :
orig = ptr ;
ptr = dict_scan_col ( cs , ptr , & success , referenced_table , columns + i ,
heap , column_names + i ) ;
heap , ref_ column_names + i ) ;
i + + ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n Cannot resolve column name close to: \n "
" %s \n " ,
start_of_latest_foreign , ptr ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , orig ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3920,13 +4208,23 @@ col_loop2:
goto col_loop2 ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " ) " , & success ) ;
if ( ! success | | foreign - > n_fields ! = i ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err ( name , start_of_latest_foreign ,
ptr ) ;
dict_foreign_report_syntax_err (
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. Too few referenced columns. \n " ,
operation , create_name , start_of_latest_foreign , orig ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. Too few referenced columns, you have %d when you should have %d. " ,
operation , create_name , start_of_latest_foreign , orig , i , foreign - > n_fields ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3936,6 +4234,7 @@ col_loop2:
scan_on_conditions :
/* Loop here as long as we can find ON ... conditions */
start_of_latest_set = ptr ;
ptr = dict_accept ( cs , ptr , " ON " , & success ) ;
if ( ! success ) {
@ -3946,13 +4245,24 @@ scan_on_conditions:
ptr = dict_accept ( cs , ptr , " DELETE " , & success ) ;
if ( ! success ) {
orig = ptr ;
ptr = dict_accept ( cs , ptr , " UPDATE " , & success ) ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err (
name , start_of_latest_foreign , ptr ) ;
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -3984,12 +4294,22 @@ scan_on_conditions:
ptr = dict_accept ( cs , ptr , " NO " , & success ) ;
if ( success ) {
orig = ptr ;
ptr = dict_accept ( cs , ptr , " ACTION " , & success ) ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err (
name , start_of_latest_foreign , ptr ) ;
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -4003,42 +4323,73 @@ scan_on_conditions:
goto scan_on_conditions ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " SET " , & success ) ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err ( name , start_of_latest_foreign ,
ptr ) ;
dict_foreign_report_syntax_err (
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
orig = ptr ;
ptr = dict_accept ( cs , ptr , " NULL " , & success ) ;
if ( ! success ) {
dict_foreign_free ( foreign ) ;
dict_foreign_report_syntax_err ( name , start_of_latest_foreign ,
ptr ) ;
dict_foreign_report_syntax_err (
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. \n " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. Foreign key constraint parse error in %s "
" close to %s. " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
for ( j = 0 ; j < foreign - > n_fields ; j + + ) {
if ( ( dict_index_get_nth_col ( foreign - > foreign_index , j ) - > prtype )
& DATA_NOT_NULL ) {
const dict_col_t * col
= dict_index_get_nth_col ( foreign - > foreign_index , j ) ;
const char * col_name = dict_table_get_col_name ( foreign - > foreign_index - > table ,
dict_col_get_no ( col ) ) ;
/* It is not sensible to define SET NULL
if the column is not allowed to be NULL ! */
dict_foreign_free ( foreign ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n "
" You have defined a SET NULL condition "
" though some of the \n "
" columns are defined as NOT NULL .\n " ,
start_of_latest_foreign ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL "
" in %s close to %s .\n " ,
operation , create_name , col_name , start_of_latest_foreign , start_of_latest_set ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL "
" in %s close to %s. " ,
operation , create_name , col_name , start_of_latest_foreign , start_of_latest_set ) ;
dict_foreign_free ( foreign ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
}
@ -4055,16 +4406,22 @@ try_find_index:
if ( n_on_deletes > 1 | | n_on_updates > 1 ) {
/* It is an error to define more than 1 action */
dict_foreign_free ( foreign ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
fprintf ( ef , " %s: \n "
" You have twice an ON DELETE clause "
" or twice an ON UPDATE clause. \n " ,
start_of_latest_foreign ) ;
dict_foreign_error_report_low ( ef , create_name ) ;
fprintf ( ef ,
" %s table %s with foreign key constraint "
" failed. You have more than one on delete or on update clause "
" in %s close to %s. \n " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
ib_push_warning ( trx , DB_CANNOT_ADD_CONSTRAINT ,
" %s table %s with foreign key constraint "
" failed. You have more than one on delete or on update clause "
" in %s close to %s. " ,
operation , create_name , start_of_latest_foreign , start_of_latest_set ) ;
dict_foreign_free ( foreign ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
@ -4074,13 +4431,13 @@ try_find_index:
if ( referenced_table ) {
index = dict_foreign_find_index ( referenced_table ,
column_names , i ,
foreign - > foreign_index ,
TRUE , FALSE ) ;
ref_ column_names, i ,
foreign - > foreign_index ,
TRUE , FALSE , & index_error , & err_col , & err_index ) ;
if ( ! index ) {
dict_foreign_free ( foreign ) ;
mutex_enter ( & dict_foreign_err_mutex ) ;
dict_foreign_error_report_low ( ef , name ) ;
dict_foreign_error_report_low ( ef , create_ name) ;
fprintf ( ef , " %s: \n "
" Cannot find an index in the "
" referenced table where the \n "
@ -4098,9 +4455,13 @@ try_find_index:
" innodb-foreign-key-constraints.html \n "
" for correct foreign key definition. \n " ,
start_of_latest_foreign ) ;
dict_foreign_push_index_error ( trx , operation , create_name , start_of_latest_foreign ,
column_names , index_error , err_col , err_index , referenced_table , ef ) ;
mutex_exit ( & dict_foreign_err_mutex ) ;
return ( DB_PARENT_NO_INDEX ) ;
return ( DB_CANNOT_ADD_CONSTRAINT ) ;
}
} else {
ut_a ( trx - > check_foreigns = = FALSE ) ;
@ -4118,7 +4479,7 @@ try_find_index:
i * sizeof ( void * ) ) ;
for ( i = 0 ; i < foreign - > n_fields ; i + + ) {
foreign - > referenced_col_names [ i ]
= mem_heap_strdup ( foreign - > heap , column_names [ i ] ) ;
= mem_heap_strdup ( foreign - > heap , ref_ column_names[ i ] ) ;
}
/* We found an ok constraint definition: add to the lists */
@ -5251,7 +5612,8 @@ dict_table_replace_index_in_foreign_list(
foreign - > referenced_table ,
foreign - > referenced_col_names ,
foreign - > n_fields , index ,
/*check_charsets=*/ TRUE , /*check_null=*/ FALSE ) ;
/*check_charsets=*/ TRUE , /*check_null=*/ FALSE ,
NULL , NULL , NULL ) ;
ut_ad ( new_index | | ! trx - > check_foreigns ) ;
ut_ad ( ! new_index | | new_index - > table = = index - > table ) ;