|
|
@ -27,6 +27,7 @@ Created 1/8/1996 Heikki Tuuri |
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "fts0fts.h"
|
|
|
|
#include "fil0fil.h"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#ifdef UNIV_NONINL
|
|
|
|
#include "dict0dict.ic"
|
|
|
@ -1246,8 +1247,8 @@ dict_table_can_be_evicted( |
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
|
|
|
|
ut_a(table->can_be_evicted); |
|
|
|
ut_a(UT_LIST_GET_LEN(table->foreign_list) == 0); |
|
|
|
ut_a(UT_LIST_GET_LEN(table->referenced_list) == 0); |
|
|
|
ut_a(table->foreign_set.empty()); |
|
|
|
ut_a(table->referenced_set.empty()); |
|
|
|
|
|
|
|
if (table->n_ref_count == 0) { |
|
|
|
dict_index_t* index; |
|
|
@ -1463,6 +1464,22 @@ dict_index_find_on_id_low( |
|
|
|
return(NULL); |
|
|
|
} |
|
|
|
|
|
|
|
/** Function object to remove a foreign key constraint from the
|
|
|
|
referenced_set of the referenced table. The foreign key object is |
|
|
|
also removed from the dictionary cache. The foreign key constraint |
|
|
|
is not removed from the foreign_set of the table containing the |
|
|
|
constraint. */ |
|
|
|
struct dict_foreign_remove_partial |
|
|
|
{ |
|
|
|
void operator()(dict_foreign_t* foreign) { |
|
|
|
dict_table_t* table = foreign->referenced_table; |
|
|
|
if (table != NULL) { |
|
|
|
table->referenced_set.erase(foreign); |
|
|
|
} |
|
|
|
dict_foreign_free(foreign); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Renames a table object. |
|
|
|
@return TRUE if success */ |
|
|
@ -1637,27 +1654,25 @@ dict_table_rename_in_cache( |
|
|
|
system tables through a call of dict_load_foreigns. */ |
|
|
|
|
|
|
|
/* Remove the foreign constraints from the cache */ |
|
|
|
foreign = UT_LIST_GET_LAST(table->foreign_list); |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
dict_foreign_remove_from_cache(foreign); |
|
|
|
foreign = UT_LIST_GET_LAST(table->foreign_list); |
|
|
|
} |
|
|
|
std::for_each(table->foreign_set.begin(), |
|
|
|
table->foreign_set.end(), |
|
|
|
dict_foreign_remove_partial()); |
|
|
|
table->foreign_set.clear(); |
|
|
|
|
|
|
|
/* Reset table field in referencing constraints */ |
|
|
|
for (dict_foreign_set::iterator it |
|
|
|
= table->referenced_set.begin(); |
|
|
|
it != table->referenced_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
foreign = *it; |
|
|
|
foreign->referenced_table = NULL; |
|
|
|
foreign->referenced_index = NULL; |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
/* Make the list of referencing constraints empty */ |
|
|
|
|
|
|
|
UT_LIST_INIT(table->referenced_list); |
|
|
|
/* Make the set of referencing constraints empty */ |
|
|
|
table->referenced_set.clear(); |
|
|
|
|
|
|
|
return(DB_SUCCESS); |
|
|
|
} |
|
|
@ -1666,9 +1681,19 @@ dict_table_rename_in_cache( |
|
|
|
the constraint id of new format >= 4.0.18 constraints. Note that at |
|
|
|
this point we have already changed table->name to the new name. */ |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
dict_foreign_set fk_set; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
|
|
|
dict_foreign_set::iterator it |
|
|
|
= table->foreign_set.begin(); |
|
|
|
|
|
|
|
if (it == table->foreign_set.end()) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
if (ut_strlen(foreign->foreign_table_name) |
|
|
|
< ut_strlen(table->name)) { |
|
|
|
/* Allocate a longer name buffer;
|
|
|
@ -1818,12 +1843,18 @@ dict_table_rename_in_cache( |
|
|
|
mem_free(old_id); |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
table->foreign_set.erase(it); |
|
|
|
fk_set.insert(foreign); |
|
|
|
} |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
foreign != NULL; |
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { |
|
|
|
ut_a(table->foreign_set.empty()); |
|
|
|
table->foreign_set.swap(fk_set); |
|
|
|
|
|
|
|
for (dict_foreign_set::iterator it = table->referenced_set.begin(); |
|
|
|
it != table->referenced_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
if (ut_strlen(foreign->referenced_table_name) |
|
|
|
< ut_strlen(table->name)) { |
|
|
@ -1893,27 +1924,17 @@ dict_table_remove_from_cache_low( |
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex))); |
|
|
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); |
|
|
|
|
|
|
|
#if 0
|
|
|
|
fputs("Removing table ", stderr); |
|
|
|
ut_print_name(stderr, table->name, ULINT_UNDEFINED); |
|
|
|
fputs(" from dictionary cache\n", stderr); |
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Remove the foreign constraints from the cache */ |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_LAST(table->foreign_list); |
|
|
|
foreign != NULL; |
|
|
|
foreign = UT_LIST_GET_LAST(table->foreign_list)) { |
|
|
|
|
|
|
|
dict_foreign_remove_from_cache(foreign); |
|
|
|
} |
|
|
|
std::for_each(table->foreign_set.begin(), table->foreign_set.end(), |
|
|
|
dict_foreign_remove_partial()); |
|
|
|
table->foreign_set.clear(); |
|
|
|
|
|
|
|
/* Reset table field in referencing constraints */ |
|
|
|
for (dict_foreign_set::iterator it = table->referenced_set.begin(); |
|
|
|
it != table->referenced_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
foreign != NULL; |
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
foreign->referenced_table = NULL; |
|
|
|
foreign->referenced_index = NULL; |
|
|
|
} |
|
|
@ -3133,7 +3154,7 @@ dict_table_is_referenced_by_foreign_key( |
|
|
|
/*====================================*/ |
|
|
|
const dict_table_t* table) /*!< in: InnoDB table */ |
|
|
|
{ |
|
|
|
return(UT_LIST_GET_LEN(table->referenced_list) > 0); |
|
|
|
return(!table->referenced_set.empty()); |
|
|
|
} |
|
|
|
|
|
|
|
/*********************************************************************//**
|
|
|
@ -3153,9 +3174,11 @@ dict_table_get_referenced_constraint( |
|
|
|
ut_ad(index != NULL); |
|
|
|
ut_ad(table != NULL); |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
foreign; |
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { |
|
|
|
for (dict_foreign_set::iterator it = table->referenced_set.begin(); |
|
|
|
it != table->referenced_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
if (foreign->referenced_index == index) { |
|
|
|
|
|
|
@ -3184,9 +3207,11 @@ dict_table_get_foreign_constraint( |
|
|
|
ut_ad(index != NULL); |
|
|
|
ut_ad(table != NULL); |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
foreign; |
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { |
|
|
|
for (dict_foreign_set::iterator it = table->foreign_set.begin(); |
|
|
|
it != table->foreign_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
if (foreign->foreign_index == index) { |
|
|
|
|
|
|
@ -3197,17 +3222,6 @@ dict_table_get_foreign_constraint( |
|
|
|
return(NULL); |
|
|
|
} |
|
|
|
|
|
|
|
/*********************************************************************//**
|
|
|
|
Frees a foreign key struct. */ |
|
|
|
UNIV_INTERN |
|
|
|
void |
|
|
|
dict_foreign_free( |
|
|
|
/*==============*/ |
|
|
|
dict_foreign_t* foreign) /*!< in, own: foreign key struct */ |
|
|
|
{ |
|
|
|
mem_heap_free(foreign->heap); |
|
|
|
} |
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
|
Removes a foreign constraint struct from the dictionary cache. */ |
|
|
|
UNIV_INTERN |
|
|
@ -3219,16 +3233,12 @@ dict_foreign_remove_from_cache( |
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex))); |
|
|
|
ut_a(foreign); |
|
|
|
|
|
|
|
if (foreign->referenced_table) { |
|
|
|
UT_LIST_REMOVE(referenced_list, |
|
|
|
foreign->referenced_table->referenced_list, |
|
|
|
foreign); |
|
|
|
if (foreign->referenced_table != NULL) { |
|
|
|
foreign->referenced_table->referenced_set.erase(foreign); |
|
|
|
} |
|
|
|
|
|
|
|
if (foreign->foreign_table) { |
|
|
|
UT_LIST_REMOVE(foreign_list, |
|
|
|
foreign->foreign_table->foreign_list, |
|
|
|
foreign); |
|
|
|
if (foreign->foreign_table != NULL) { |
|
|
|
foreign->foreign_table->foreign_set.erase(foreign); |
|
|
|
} |
|
|
|
|
|
|
|
dict_foreign_free(foreign); |
|
|
@ -3242,33 +3252,21 @@ static |
|
|
|
dict_foreign_t* |
|
|
|
dict_foreign_find( |
|
|
|
/*==============*/ |
|
|
|
dict_table_t* table, /*!< in: table object */ |
|
|
|
const char* id) /*!< in: foreign constraint id */ |
|
|
|
dict_table_t* table, /*!< in: table object */ |
|
|
|
dict_foreign_t* foreign) /*!< in: foreign constraint */ |
|
|
|
{ |
|
|
|
dict_foreign_t* foreign; |
|
|
|
|
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex))); |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
dict_foreign_set::iterator it = table->foreign_set.find(foreign); |
|
|
|
|
|
|
|
while (foreign) { |
|
|
|
if (ut_strcmp(id, foreign->id) == 0) { |
|
|
|
|
|
|
|
return(foreign); |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
if (it != table->foreign_set.end()) { |
|
|
|
return(*it); |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
|
|
|
|
while (foreign) { |
|
|
|
if (ut_strcmp(id, foreign->id) == 0) { |
|
|
|
|
|
|
|
return(foreign); |
|
|
|
} |
|
|
|
it = table->referenced_set.find(foreign); |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign); |
|
|
|
if (it != table->referenced_set.end()) { |
|
|
|
return(*it); |
|
|
|
} |
|
|
|
|
|
|
|
return(NULL); |
|
|
@ -3406,11 +3404,11 @@ dict_foreign_add_to_cache( |
|
|
|
ut_a(for_table || ref_table); |
|
|
|
|
|
|
|
if (for_table) { |
|
|
|
for_in_cache = dict_foreign_find(for_table, foreign->id); |
|
|
|
for_in_cache = dict_foreign_find(for_table, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
if (!for_in_cache && ref_table) { |
|
|
|
for_in_cache = dict_foreign_find(ref_table, foreign->id); |
|
|
|
for_in_cache = dict_foreign_find(ref_table, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
if (for_in_cache) { |
|
|
@ -3447,9 +3445,12 @@ dict_foreign_add_to_cache( |
|
|
|
|
|
|
|
for_in_cache->referenced_table = ref_table; |
|
|
|
for_in_cache->referenced_index = index; |
|
|
|
UT_LIST_ADD_LAST(referenced_list, |
|
|
|
ref_table->referenced_list, |
|
|
|
for_in_cache); |
|
|
|
|
|
|
|
std::pair<dict_foreign_set::iterator, bool> ret |
|
|
|
= ref_table->referenced_set.insert(for_in_cache); |
|
|
|
|
|
|
|
ut_a(ret.second); /* second is true if the insertion
|
|
|
|
took place */ |
|
|
|
added_to_referenced_list = TRUE; |
|
|
|
} |
|
|
|
|
|
|
@ -3478,10 +3479,13 @@ dict_foreign_add_to_cache( |
|
|
|
|
|
|
|
if (for_in_cache == foreign) { |
|
|
|
if (added_to_referenced_list) { |
|
|
|
UT_LIST_REMOVE( |
|
|
|
referenced_list, |
|
|
|
ref_table->referenced_list, |
|
|
|
for_in_cache); |
|
|
|
const dict_foreign_set::size_type n |
|
|
|
= ref_table->referenced_set |
|
|
|
.erase(for_in_cache); |
|
|
|
|
|
|
|
ut_a(n == 1); /* the number of
|
|
|
|
elements removed must |
|
|
|
be one */ |
|
|
|
} |
|
|
|
|
|
|
|
mem_heap_free(foreign->heap); |
|
|
@ -3492,9 +3496,11 @@ dict_foreign_add_to_cache( |
|
|
|
|
|
|
|
for_in_cache->foreign_table = for_table; |
|
|
|
for_in_cache->foreign_index = index; |
|
|
|
UT_LIST_ADD_LAST(foreign_list, |
|
|
|
for_table->foreign_list, |
|
|
|
for_in_cache); |
|
|
|
std::pair<dict_foreign_set::iterator, bool> ret |
|
|
|
= for_table->foreign_set.insert(for_in_cache); |
|
|
|
|
|
|
|
ut_a(ret.second); /* second is true if the insertion
|
|
|
|
took place */ |
|
|
|
} |
|
|
|
|
|
|
|
/* We need to move the table to the non-LRU end of the table LRU
|
|
|
@ -4072,9 +4078,12 @@ dict_table_get_highest_foreign_id( |
|
|
|
ut_a(table); |
|
|
|
|
|
|
|
len = ut_strlen(table->name); |
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
|
|
|
|
while (foreign) { |
|
|
|
for (dict_foreign_set::iterator it = table->foreign_set.begin(); |
|
|
|
it != table->foreign_set.end(); |
|
|
|
++it) { |
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len |
|
|
|
&& 0 == ut_memcmp(foreign->id, table->name, len) |
|
|
|
&& 0 == ut_memcmp(foreign->id + len, |
|
|
@ -4093,8 +4102,6 @@ dict_table_get_highest_foreign_id( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
return(biggest_id); |
|
|
@ -4155,6 +4162,7 @@ dict_create_foreign_constraints_low( |
|
|
|
dict_table_t* referenced_table; |
|
|
|
dict_table_t* table_to_alter; |
|
|
|
ulint highest_id_so_far = 0; |
|
|
|
ulint number = 1; |
|
|
|
dict_index_t* index; |
|
|
|
dict_foreign_t* foreign; |
|
|
|
const char* ptr = sql_string; |
|
|
@ -4173,6 +4181,8 @@ dict_create_foreign_constraints_low( |
|
|
|
const dict_col_t*columns[500]; |
|
|
|
const char* column_names[500]; |
|
|
|
const char* referenced_table_name; |
|
|
|
dict_foreign_set local_fk_set; |
|
|
|
dict_foreign_set_free local_fk_set_free(local_fk_set); |
|
|
|
|
|
|
|
ut_ad(!srv_read_only_mode); |
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex))); |
|
|
@ -4237,6 +4247,7 @@ dict_create_foreign_constraints_low( |
|
|
|
table_to_alter); |
|
|
|
} |
|
|
|
|
|
|
|
number = highest_id_so_far + 1; |
|
|
|
/* Scan for foreign key declarations in a loop */ |
|
|
|
loop: |
|
|
|
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */ |
|
|
@ -4281,7 +4292,7 @@ loop: |
|
|
|
command, determine if there are any foreign keys, and |
|
|
|
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)) { |
|
|
|
if (reject_fks && !local_fk_set.empty()) { |
|
|
|
|
|
|
|
return(DB_CANNOT_ADD_CONSTRAINT); |
|
|
|
} |
|
|
@ -4291,7 +4302,17 @@ loop: |
|
|
|
to the data dictionary system tables on disk */ |
|
|
|
|
|
|
|
error = dict_create_add_foreigns_to_dictionary( |
|
|
|
highest_id_so_far, table, trx); |
|
|
|
local_fk_set, table, trx); |
|
|
|
|
|
|
|
if (error == DB_SUCCESS) { |
|
|
|
|
|
|
|
table->foreign_set.insert(local_fk_set.begin(), |
|
|
|
local_fk_set.end()); |
|
|
|
std::for_each(local_fk_set.begin(), |
|
|
|
local_fk_set.end(), |
|
|
|
dict_foreign_add_to_referenced_table()); |
|
|
|
local_fk_set.clear(); |
|
|
|
} |
|
|
|
return(error); |
|
|
|
} |
|
|
|
|
|
|
@ -4423,6 +4444,24 @@ col_loop1: |
|
|
|
strcpy(foreign->id + db_len + 1, constraint_name); |
|
|
|
} |
|
|
|
|
|
|
|
if (foreign->id == NULL) { |
|
|
|
error = dict_create_add_foreign_id(&number, |
|
|
|
table->name, foreign); |
|
|
|
if (error != DB_SUCCESS) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
return(error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::pair<dict_foreign_set::iterator, bool> ret |
|
|
|
= local_fk_set.insert(foreign); |
|
|
|
|
|
|
|
if (!ret.second) { |
|
|
|
/* A duplicate foreign key name has been found */ |
|
|
|
dict_foreign_free(foreign); |
|
|
|
return(DB_CANNOT_ADD_CONSTRAINT); |
|
|
|
} |
|
|
|
|
|
|
|
foreign->foreign_table = table; |
|
|
|
foreign->foreign_table_name = mem_heap_strdup( |
|
|
|
foreign->heap, table->name); |
|
|
@ -4448,8 +4487,6 @@ col_loop1: |
|
|
|
checking of foreign key constraints! */ |
|
|
|
|
|
|
|
if (!success || (!referenced_table && trx->check_foreigns)) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
|
|
|
|
mutex_enter(&dict_foreign_err_mutex); |
|
|
|
dict_foreign_error_report_low(ef, name); |
|
|
|
fprintf(ef, "%s:\nCannot resolve table name close to:\n" |
|
|
@ -4463,7 +4500,6 @@ col_loop1: |
|
|
|
ptr = dict_accept(cs, ptr, "(", &success); |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign, |
|
|
|
ptr); |
|
|
|
return(DB_CANNOT_ADD_CONSTRAINT); |
|
|
@ -4478,7 +4514,6 @@ col_loop2: |
|
|
|
i++; |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
|
|
|
|
mutex_enter(&dict_foreign_err_mutex); |
|
|
|
dict_foreign_error_report_low(ef, name); |
|
|
@ -4499,7 +4534,6 @@ col_loop2: |
|
|
|
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); |
|
|
@ -4525,7 +4559,6 @@ scan_on_conditions: |
|
|
|
ptr = dict_accept(cs, ptr, "UPDATE", &success); |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
|
|
|
|
dict_foreign_report_syntax_err( |
|
|
|
name, start_of_latest_foreign, ptr); |
|
|
@ -4563,7 +4596,6 @@ scan_on_conditions: |
|
|
|
ptr = dict_accept(cs, ptr, "ACTION", &success); |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
dict_foreign_report_syntax_err( |
|
|
|
name, start_of_latest_foreign, ptr); |
|
|
|
|
|
|
@ -4582,7 +4614,6 @@ scan_on_conditions: |
|
|
|
ptr = dict_accept(cs, ptr, "SET", &success); |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign, |
|
|
|
ptr); |
|
|
|
return(DB_CANNOT_ADD_CONSTRAINT); |
|
|
@ -4591,7 +4622,6 @@ scan_on_conditions: |
|
|
|
ptr = dict_accept(cs, ptr, "NULL", &success); |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign, |
|
|
|
ptr); |
|
|
|
return(DB_CANNOT_ADD_CONSTRAINT); |
|
|
@ -4604,8 +4634,6 @@ scan_on_conditions: |
|
|
|
/* 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" |
|
|
@ -4631,8 +4659,6 @@ 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" |
|
|
@ -4654,7 +4680,6 @@ try_find_index: |
|
|
|
foreign->foreign_index, |
|
|
|
TRUE, FALSE); |
|
|
|
if (!index) { |
|
|
|
dict_foreign_free(foreign); |
|
|
|
mutex_enter(&dict_foreign_err_mutex); |
|
|
|
dict_foreign_error_report_low(ef, name); |
|
|
|
fprintf(ef, "%s:\n" |
|
|
@ -4698,16 +4723,6 @@ try_find_index: |
|
|
|
= mem_heap_strdup(foreign->heap, column_names[i]); |
|
|
|
} |
|
|
|
|
|
|
|
/* We found an ok constraint definition: add to the lists */ |
|
|
|
|
|
|
|
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign); |
|
|
|
|
|
|
|
if (referenced_table) { |
|
|
|
UT_LIST_ADD_LAST(referenced_list, |
|
|
|
referenced_table->referenced_list, |
|
|
|
foreign); |
|
|
|
} |
|
|
|
|
|
|
|
goto loop; |
|
|
|
} |
|
|
|
/**************************************************************************
|
|
|
@ -4793,7 +4808,6 @@ dict_foreign_parse_drop_constraints( |
|
|
|
const char*** constraints_to_drop) /*!< out: id's of the
|
|
|
|
constraints to drop */ |
|
|
|
{ |
|
|
|
dict_foreign_t* foreign; |
|
|
|
ibool success; |
|
|
|
char* str; |
|
|
|
size_t len; |
|
|
@ -4859,25 +4873,10 @@ loop: |
|
|
|
(*constraints_to_drop)[*n] = id; |
|
|
|
(*n)++; |
|
|
|
|
|
|
|
/* Look for the given constraint id */ |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
if (0 == innobase_strcasecmp(foreign->id, id) |
|
|
|
|| (strchr(foreign->id, '/') |
|
|
|
&& 0 == innobase_strcasecmp( |
|
|
|
id, |
|
|
|
dict_remove_db_name(foreign->id)))) { |
|
|
|
/* Found */ |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (foreign == NULL) { |
|
|
|
if (std::find_if(table->foreign_set.begin(), |
|
|
|
table->foreign_set.end(), |
|
|
|
dict_foreign_matches_id(id)) |
|
|
|
== table->foreign_set.end()) { |
|
|
|
|
|
|
|
if (!srv_read_only_mode) { |
|
|
|
FILE* ef = dict_foreign_err_file; |
|
|
@ -5204,7 +5203,6 @@ dict_table_print( |
|
|
|
dict_table_t* table) /*!< in: table */ |
|
|
|
{ |
|
|
|
dict_index_t* index; |
|
|
|
dict_foreign_t* foreign; |
|
|
|
ulint i; |
|
|
|
|
|
|
|
ut_ad(mutex_own(&(dict_sys->mutex))); |
|
|
@ -5243,19 +5241,13 @@ dict_table_print( |
|
|
|
|
|
|
|
dict_table_stats_unlock(table, RW_X_LATCH); |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
dict_foreign_print_low(foreign); |
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
std::for_each(table->foreign_set.begin(), |
|
|
|
table->foreign_set.end(), |
|
|
|
dict_foreign_print_low); |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
dict_foreign_print_low(foreign); |
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign); |
|
|
|
} |
|
|
|
std::for_each(table->referenced_set.begin(), |
|
|
|
table->referenced_set.end(), |
|
|
|
dict_foreign_print_low); |
|
|
|
} |
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
|
@ -5463,15 +5455,12 @@ dict_print_info_on_foreign_keys( |
|
|
|
|
|
|
|
mutex_enter(&(dict_sys->mutex)); |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
|
|
|
|
if (foreign == NULL) { |
|
|
|
mutex_exit(&(dict_sys->mutex)); |
|
|
|
for (dict_foreign_set::iterator it = table->foreign_set.begin(); |
|
|
|
it != table->foreign_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
foreign = *it; |
|
|
|
|
|
|
|
while (foreign != NULL) { |
|
|
|
if (create_table_format) { |
|
|
|
dict_print_info_on_foreign_key_in_create_format( |
|
|
|
file, trx, foreign, TRUE); |
|
|
@ -5528,8 +5517,6 @@ dict_print_info_on_foreign_keys( |
|
|
|
fputs(" ON UPDATE NO ACTION", file); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); |
|
|
|
} |
|
|
|
|
|
|
|
mutex_exit(&(dict_sys->mutex)); |
|
|
@ -5900,10 +5887,11 @@ dict_foreign_replace_index( |
|
|
|
ut_ad(index->to_be_dropped); |
|
|
|
ut_ad(index->table == table); |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->foreign_list); |
|
|
|
foreign; |
|
|
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { |
|
|
|
for (dict_foreign_set::iterator it = table->foreign_set.begin(); |
|
|
|
it != table->foreign_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
if (foreign->foreign_index == index) { |
|
|
|
ut_ad(foreign->foreign_table == index->table); |
|
|
|
|
|
|
@ -5923,10 +5911,11 @@ dict_foreign_replace_index( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (foreign = UT_LIST_GET_FIRST(table->referenced_list); |
|
|
|
foreign; |
|
|
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { |
|
|
|
for (dict_foreign_set::iterator it = table->referenced_set.begin(); |
|
|
|
it != table->referenced_set.end(); |
|
|
|
++it) { |
|
|
|
|
|
|
|
foreign = *it; |
|
|
|
if (foreign->referenced_index == index) { |
|
|
|
ut_ad(foreign->referenced_table == index->table); |
|
|
|
|
|
|
@ -6218,24 +6207,24 @@ dict_table_schema_check( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (req_schema->n_foreign != UT_LIST_GET_LEN(table->foreign_list)) { |
|
|
|
if (req_schema->n_foreign != table->foreign_set.size()) { |
|
|
|
ut_snprintf( |
|
|
|
errstr, errstr_sz, |
|
|
|
"Table %s has %lu foreign key(s) pointing to other " |
|
|
|
"tables, but it must have %lu.", |
|
|
|
"Table %s has " ULINTPF " foreign key(s) pointing" |
|
|
|
" to other tables, but it must have %lu.", |
|
|
|
ut_format_name(req_schema->table_name, |
|
|
|
TRUE, buf, sizeof(buf)), |
|
|
|
UT_LIST_GET_LEN(table->foreign_list), |
|
|
|
static_cast<ulint>(table->foreign_set.size()), |
|
|
|
req_schema->n_foreign); |
|
|
|
return(DB_ERROR); |
|
|
|
} |
|
|
|
|
|
|
|
if (req_schema->n_referenced != UT_LIST_GET_LEN(table->referenced_list)) { |
|
|
|
if (req_schema->n_referenced != table->referenced_set.size()) { |
|
|
|
ut_snprintf( |
|
|
|
errstr, errstr_sz, |
|
|
|
"There are %lu foreign key(s) pointing to %s, " |
|
|
|
"There are " ULINTPF " foreign key(s) pointing to %s, " |
|
|
|
"but there must be %lu.", |
|
|
|
UT_LIST_GET_LEN(table->referenced_list), |
|
|
|
static_cast<ulint>(table->referenced_set.size()), |
|
|
|
ut_format_name(req_schema->table_name, |
|
|
|
TRUE, buf, sizeof(buf)), |
|
|
|
req_schema->n_referenced); |
|
|
|