summaryrefslogtreecommitdiff
path: root/innobase/dict/dict0dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/dict/dict0dict.c')
-rw-r--r--innobase/dict/dict0dict.c135
1 files changed, 119 insertions, 16 deletions
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 18f27602cf0..c70e848c5c8 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -1113,6 +1113,7 @@ dict_index_add_to_cache(
ulint n_ord;
ibool success;
ulint i;
+ ulint j;
ut_ad(index);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1143,6 +1144,28 @@ dict_index_add_to_cache(
return(FALSE);
}
+ /* Check that the same column does not appear twice in the index.
+ InnoDB assumes this in its algorithms, e.g., update of an index
+ entry */
+
+ for (i = 0; i < dict_index_get_n_fields(index); i++) {
+
+ for (j = 0; j < i; j++) {
+ if (dict_index_get_nth_field(index, j)->col
+ == dict_index_get_nth_field(index, i)->col) {
+
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+" InnoDB: Error: column %s appears twice in index %s of table %s\n"
+"InnoDB: This is not allowed in InnoDB.\n"
+"InnoDB: UPDATE can cause such an index to become corrupt in InnoDB.\n",
+ dict_index_get_nth_field(index, i)->col->name,
+ index->name, table->name);
+ }
+ }
+ }
+
/* Build the cache internal representation of the index,
containing also the added system fields */
@@ -2212,6 +2235,9 @@ dict_create_foreign_constraints(
ulint error;
ulint i;
ulint j;
+ ibool is_on_delete;
+ ulint n_on_deletes;
+ ulint n_on_updates;
dict_col_t* columns[500];
char* column_names[500];
ulint column_name_lens[500];
@@ -2371,6 +2397,12 @@ col_loop2:
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ n_on_deletes = 0;
+ n_on_updates = 0;
+
+scan_on_conditions:
+ /* Loop here as long as we can find ON ... conditions */
+
ptr = dict_accept(ptr, "ON", &success);
if (!success) {
@@ -2381,23 +2413,58 @@ col_loop2:
ptr = dict_accept(ptr, "DELETE", &success);
if (!success) {
- dict_foreign_free(foreign);
+ ptr = dict_accept(ptr, "UPDATE", &success);
+
+ if (!success) {
+
+ dict_foreign_free(foreign);
- return(DB_CANNOT_ADD_CONSTRAINT);
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ is_on_delete = FALSE;
+ n_on_updates++;
+ } else {
+ is_on_delete = TRUE;
+ n_on_deletes++;
}
ptr = dict_accept(ptr, "RESTRICT", &success);
if (success) {
- goto try_find_index;
+ goto scan_on_conditions;
}
ptr = dict_accept(ptr, "CASCADE", &success);
if (success) {
- foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE;
+ if (is_on_delete) {
+ foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
+ } else {
+ foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
+ }
- goto try_find_index;
+ goto scan_on_conditions;
+ }
+
+ ptr = dict_accept(ptr, "NO", &success);
+
+ if (success) {
+ ptr = dict_accept(ptr, "ACTION", &success);
+
+ if (!success) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ if (is_on_delete) {
+ foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
+ } else {
+ foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
+ }
+
+ goto scan_on_conditions;
}
ptr = dict_accept(ptr, "SET", &success);
@@ -2430,20 +2497,23 @@ col_loop2:
}
}
- foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
+ if (is_on_delete) {
+ foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
+ } else {
+ foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
+ }
-try_find_index:
- /* We check that there are no superfluous words like 'ON UPDATE ...'
- which we do not support yet. */
+ goto scan_on_conditions;
- ptr = dict_accept(ptr, (char *) "ON", &success);
-
- if (success) {
+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);
return(DB_CANNOT_ADD_CONSTRAINT);
}
-
+
/* Try to find an index which contains the columns as the first fields
and in the right order, and the types are the same as in
foreign->foreign_index */
@@ -3265,7 +3335,8 @@ dict_print_info_on_foreign_keys_in_create_format(
/*=============================================*/
char* buf, /* in: auxiliary buffer */
char* str, /* in/out: pointer to a string */
- ulint len, /* in: space in str available for info */
+ ulint len, /* in: str has to be a buffer at least
+ len + 5000 bytes */
dict_table_t* table) /* in: table */
{
@@ -3335,14 +3406,30 @@ dict_print_info_on_foreign_keys_in_create_format(
buf2 += sprintf(buf2, ")");
- if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
+ if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
buf2 += sprintf(buf2, " ON DELETE CASCADE");
}
- if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
+ if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
buf2 += sprintf(buf2, " ON DELETE SET NULL");
}
+ if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
+ buf2 += sprintf(buf2, " ON DELETE NO ACTION");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
+ buf2 += sprintf(buf2, " ON UPDATE CASCADE");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
+ buf2 += sprintf(buf2, " ON UPDATE SET NULL");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
+ buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
+ }
+
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
no_space:
@@ -3434,6 +3521,22 @@ dict_print_info_on_foreign_keys(
buf2 += sprintf(buf2, " ON DELETE SET NULL");
}
+ if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
+ buf2 += sprintf(buf2, " ON DELETE NO ACTION");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
+ buf2 += sprintf(buf2, " ON UPDATE CASCADE");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
+ buf2 += sprintf(buf2, " ON UPDATE SET NULL");
+ }
+
+ if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
+ buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
+ }
+
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
no_space: