diff options
Diffstat (limited to 'innobase/row')
-rw-r--r-- | innobase/row/row0ins.c | 16 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 119 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 11 |
3 files changed, 122 insertions, 24 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index c89f41f69ad..5e84f43bcf0 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -682,14 +682,6 @@ row_ins_foreign_check_on_constraint( (DICT_FOREIGN_ON_DELETE_CASCADE | DICT_FOREIGN_ON_DELETE_SET_NULL))) { - /* No action is defined: return a foreign key error if - NO ACTION is not specified */ - - if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - - return(DB_SUCCESS); - } - row_ins_foreign_report_err((char*)"Trying to delete", thr, foreign, btr_pcur_get_rec(pcur), entry); @@ -703,14 +695,6 @@ row_ins_foreign_check_on_constraint( /* This is an UPDATE */ - /* No action is defined: return a foreign key error if - NO ACTION is not specified */ - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - - return(DB_SUCCESS); - } - row_ins_foreign_report_err((char*)"Trying to update", thr, foreign, btr_pcur_get_rec(pcur), entry); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index cf7a3efcdfc..476ab85f62e 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2085,6 +2085,7 @@ row_drop_table_for_mysql( char* name, /* in: table name */ trx_t* trx) /* in: transaction handle */ { + dict_foreign_t* foreign; dict_table_t* table; ulint space_id; que_thr_t* thr; @@ -2282,6 +2283,38 @@ row_drop_table_for_mysql( goto funct_exit; } + /* Check if the table is referenced by foreign key constraints from + some other table (not the table itself) */ + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign && foreign->foreign_table == table) { + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } + + if (foreign && trx->check_foreigns) { + char* buf = dict_foreign_err_buf; + + /* We only allow dropping a referenced table if + FOREIGN_KEY_CHECKS is set to 0 */ + + err = DB_CANNOT_DROP_CONSTRAINT; + + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + + sprintf(buf + strlen(buf), + " Cannot drop table %.500s\n", name); + sprintf(buf + strlen(buf), +"because it is referenced by %.500s\n", foreign->foreign_table_name); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + + mutex_exit(&dict_foreign_err_mutex); + + goto funct_exit; + } + if (table->n_mysql_handles_opened > 0) { ut_print_timestamp(stderr); @@ -2469,7 +2502,7 @@ row_is_mysql_tmp_table_name( { ulint i; - for (i = 0; i <= ut_strlen(name) - 5; i++) { + for (i = 0; i + 5 <= ut_strlen(name); i++) { if (ut_memcmp(name + i, (char*)"/#sql", 5) == 0) { return(TRUE); @@ -2505,6 +2538,7 @@ row_rename_table_for_mysql( ulint keywordlen; ulint len; ulint i; + char* db_name; ibool success; char buf[2 * OS_FILE_MAX_PATH]; @@ -2593,6 +2627,15 @@ row_rename_table_for_mysql( "PROCEDURE RENAME_TABLE_PROC () IS\n" "new_table_name CHAR;\n" "old_table_name CHAR;\n" + "gen_constr_prefix CHAR;\n" + "new_db_name CHAR;\n" + "foreign_id CHAR;\n" + "new_foreign_id CHAR;\n" + "old_db_name_len INT;\n" + "old_t_name_len INT;\n" + "new_db_name_len INT;\n" + "id_len INT;\n" + "found INT;\n" "BEGIN\n" "new_table_name :='"; @@ -2619,32 +2662,94 @@ row_rename_table_for_mysql( } str3 = mem_heap_alloc(heap, - 1000 + 500 * n_constraints_to_drop); + 1000 + 1000 * n_constraints_to_drop); *str3 = '\0'; sprintf(str3, "';\n" "UPDATE SYS_TABLES SET NAME = new_table_name\n" "WHERE NAME = old_table_name;\n"); + db_name = mem_heap_alloc(heap, 1 + dict_get_db_name_len( + old_name)); + ut_memcpy(db_name, old_name, dict_get_db_name_len(old_name)); + db_name[dict_get_db_name_len(old_name)] = '\0'; + + /* Internally, old format < 4.0.18 constraints have as the + constraint id <number>_<number>, while new format constraints + have <databasename>/<constraintname>. */ + for (i = 0; i < n_constraints_to_drop; i++) { + sprintf(str3 + strlen(str3), - "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n" - "DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n", + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s/%s';\n" + "DELETE FROM SYS_FOREIGN WHERE ID = '%s/%s';\n", + db_name, constraints_to_drop[i], + db_name, constraints_to_drop[i]); + + if (!ut_str_contains(constraints_to_drop[i], '/')) { + /* If this happens to be an old format + constraint, let us delete it. Since all new + format constraints contain '/', it does no + harm to run these DELETEs anyway. */ + + sprintf(str3 + strlen(str3), + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n" + "DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n", constraints_to_drop[i], constraints_to_drop[i]); + } } sprintf(str3 + strlen(str3), "END;\n"); - ut_a(strlen(str3) < 1000 + 500 * n_constraints_to_drop); + ut_a(strlen(str3) < 1000 + 1000 * n_constraints_to_drop); } else { str3 = (char*) "';\n" "UPDATE SYS_TABLES SET NAME = new_table_name\n" "WHERE NAME = old_table_name;\n" - "UPDATE SYS_FOREIGN SET FOR_NAME = new_table_name\n" - "WHERE FOR_NAME = old_table_name;\n" + "found := 1;\n" + "old_db_name_len := INSTR(old_table_name, '/') - 1;\n" + "new_db_name_len := INSTR(new_table_name, '/') - 1;\n" + "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n" + "old_t_name_len := LENGTH(old_table_name);\n" + "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = old_table_name;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE\n" + " UPDATE SYS_FOREIGN\n" + " SET FOR_NAME = new_table_name\n" + " WHERE ID = foreign_id;\n" + " id_len := LENGTH(foreign_id);\n" + " IF (INSTR(foreign_id, '/') > 0) THEN\n" + " IF (INSTR(foreign_id,\n" + " gen_constr_prefix) > 0)\n" + " THEN\n" + " new_foreign_id :=\n" + " CONCAT(new_table_name,\n" + " SUBSTR(foreign_id, old_t_name_len,\n" + " id_len - old_t_name_len));\n" + " ELSE\n" + " new_foreign_id :=\n" + " CONCAT(new_db_name,\n" + " SUBSTR(foreign_id,\n" + " old_db_name_len,\n" + " id_len - old_db_name_len));\n" + " END IF;\n" + " UPDATE SYS_FOREIGN\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " UPDATE SYS_FOREIGN_COLS\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + " END IF;\n" + "END LOOP;\n" "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" "WHERE REF_NAME = old_table_name;\n" "END;\n"; diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 57de309c090..b32f0b204b3 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2886,7 +2886,16 @@ row_search_for_mysql( if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE && dtuple_get_n_fields(search_tuple) - == dict_index_get_n_unique(index)) { + == dict_index_get_n_unique(index) + && (index->type & DICT_CLUSTERED + || !dtuple_contains_null(search_tuple))) { + + /* Note above that a UNIQUE secondary index can contain many + rows with the same key value if one of the columns is the SQL + null. A clustered index under MySQL can never contain null + columns because we demand that all the columns in primary key + are non-null. */ + unique_search = TRUE; /* Even if the condition is unique, MySQL seems to try to |