diff options
Diffstat (limited to 'storage/xtradb/row/row0mysql.c')
-rw-r--r-- | storage/xtradb/row/row0mysql.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index 62221fa456d..56754404b65 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -577,6 +577,13 @@ handle_new_error: "InnoDB: " REFMAN "forcing-recovery.html" " for help.\n", stderr); break; + case DB_FOREIGN_EXCEED_MAX_CASCADE: + fprintf(stderr, "InnoDB: Cannot delete/update rows with" + " cascading foreign key constraints that exceed max" + " depth of %lu\n" + "Please drop excessive foreign constraints" + " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD); + break; default: fprintf(stderr, "InnoDB: unknown error code %lu\n", (ulong) err); @@ -1392,11 +1399,15 @@ row_update_for_mysql( run_again: thr->run_node = node; thr->prev_node = node; + thr->fk_cascade_depth = 0; row_upd_step(thr); err = trx->error_state; + /* Reset fk_cascade_depth back to 0 */ + thr->fk_cascade_depth = 0; + if (err != DB_SUCCESS) { que_thr_stop_for_mysql(thr); @@ -1587,6 +1598,12 @@ row_update_cascade_for_mysql( trx_t* trx; trx = thr_get_trx(thr); + + thr->fk_cascade_depth++; + + if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) { + return (DB_FOREIGN_EXCEED_MAX_CASCADE); + } run_again: thr->run_node = node; thr->prev_node = node; @@ -2106,7 +2123,7 @@ row_table_add_foreign_constraints( name, reject_fks); if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ - err = dict_load_foreigns(name, TRUE); + err = dict_load_foreigns(name, FALSE, TRUE); } if (err != DB_SUCCESS) { @@ -2799,6 +2816,15 @@ row_truncate_table_for_mysql( trx->table_id = table->id; + /* Lock all index trees for this table, as we will + truncate the table/index and possibly change their metadata. + All DML/DDL are blocked by table level lock, with + a few exceptions such as queries into information schema + about the table, MySQL could try to access index stats + for this kind of query, we need to use index locks to + sync up */ + dict_table_x_lock_indexes(table); + if (table->space && !table->dir_path_of_temp_table) { /* Discard and create the single-table tablespace. */ ulint space = table->space; @@ -2815,6 +2841,7 @@ row_truncate_table_for_mysql( || fil_create_new_single_table_tablespace( space, table->name, FALSE, flags, FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { + dict_table_x_unlock_indexes(table); ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: TRUNCATE TABLE %s failed to" @@ -2918,6 +2945,10 @@ next_rec: mem_heap_free(heap); + /* Done with index truncation, release index tree locks, + subsequent work relates to table level metadata change */ + dict_table_x_unlock_indexes(table); + dict_hdr_get_new_id(&new_id, NULL, NULL); info = pars_info_create(); @@ -3967,7 +3998,7 @@ end: an ALTER, not in a RENAME. */ err = dict_load_foreigns( - new_name, !old_is_tmp || trx->check_foreigns); + new_name, FALSE, !old_is_tmp || trx->check_foreigns); if (err != DB_SUCCESS) { ut_print_timestamp(stderr); |