diff options
Diffstat (limited to 'innobase/row')
-rw-r--r-- | innobase/row/row0ins.c | 31 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 80 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 26 | ||||
-rw-r--r-- | innobase/row/row0upd.c | 2 |
4 files changed, 121 insertions, 18 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index c3f912d5f61..eb07291e709 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -391,7 +391,7 @@ row_ins_check_foreign_constraint( /* out: DB_SUCCESS, DB_LOCK_WAIT, DB_NO_REFERENCED_ROW, or DB_ROW_IS_REFERENCED */ - ibool check_ref,/* in: TRUE If we want to check that + ibool check_ref,/* in: TRUE if we want to check that the referenced table is ok, FALSE if we want to to check the foreign key table */ dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the @@ -411,10 +411,23 @@ row_ins_check_foreign_constraint( ibool moved; int cmp; ulint err; + ulint i; mtr_t mtr; ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED)); + /* If any of the foreign key fields in entry is SQL NULL, we + suppress the foreign key check: this is compatible with Oracle, + for example */ + + for (i = 0; i < foreign->n_fields; i++) { + if (UNIV_SQL_NULL == dfield_get_len( + dtuple_get_nth_field(entry, i))) { + + return(DB_SUCCESS); + } + } + if (check_ref) { check_table = foreign->referenced_table; check_index = foreign->referenced_index; @@ -591,6 +604,8 @@ row_ins_scan_sec_index_for_duplicate( dtuple_t* entry, /* in: index entry */ que_thr_t* thr) /* in: query thread */ { + ulint n_unique; + ulint i; int cmp; ulint n_fields_cmp; rec_t* rec; @@ -599,6 +614,20 @@ row_ins_scan_sec_index_for_duplicate( ibool moved; mtr_t mtr; + n_unique = dict_index_get_n_unique(index); + + /* If the secondary index is unique, but one of the fields in the + n_unique first fields is NULL, a unique key violation cannot occur, + since we define NULL != NULL in this case */ + + for (i = 0; i < n_unique; i++) { + if (UNIV_SQL_NULL == dfield_get_len( + dtuple_get_nth_field(entry, i))) { + + return(DB_SUCCESS); + } + } + mtr_start(&mtr); /* Store old value on n_fields_cmp */ diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index f5ed0ef65af..78b32a5642b 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1887,6 +1887,28 @@ loop: } /************************************************************************* +Checks if a table name contains the string "/#sql" which denotes temporary +tables in MySQL. */ +static +ibool +row_is_mysql_tmp_table_name( +/*========================*/ + /* out: TRUE if temporary table */ + char* name) /* in: table name in the form 'database/tablename' */ +{ + ulint i; + + for (i = 0; i <= ut_strlen(name) - 5; i++) { + if (ut_memcmp(name + i, "/#sql", 5) == 0) { + + return(TRUE); + } + } + + return(FALSE); +} + +/************************************************************************* Renames a table for MySQL. */ int @@ -1949,16 +1971,27 @@ row_rename_table_for_mysql( str2 = (char *) "';\nold_table_name := '"; - 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" - "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" - "WHERE REF_NAME = old_table_name;\n" - "COMMIT WORK;\n" - "END;\n"; + if (row_is_mysql_tmp_table_name(new_name)) { + + /* We want to preserve the original foreign key + constraint definitions despite the name change */ + + str3 = (char*) + "';\n" + "UPDATE SYS_TABLES SET NAME = new_table_name\n" + "WHERE NAME = old_table_name;\n" + "END;\n"; + } 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" + "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" + "WHERE REF_NAME = old_table_name;\n" + "END;\n"; + } len = ut_strlen(str1); @@ -2033,7 +2066,32 @@ row_rename_table_for_mysql( trx_general_rollback_for_mysql(trx, FALSE, NULL); trx->error_state = DB_SUCCESS; } else { - ut_a(dict_table_rename_in_cache(table, new_name)); + ut_a(dict_table_rename_in_cache(table, new_name, + !row_is_mysql_tmp_table_name(new_name))); + + if (row_is_mysql_tmp_table_name(old_name)) { + + err = dict_load_foreigns(new_name); + + if (err != DB_SUCCESS) { + + ut_print_timestamp(stderr); + + fprintf(stderr, + " InnoDB: Error: in ALTER TABLE table %s\n" + "InnoDB: has or is referenced in foreign key constraints\n" + "InnoDB: which are not compatible with the new table definition.\n", + new_name); + + ut_a(dict_table_rename_in_cache(table, + old_name, FALSE)); + + trx->error_state = DB_SUCCESS; + trx_general_rollback_for_mysql(trx, FALSE, + NULL); + trx->error_state = DB_SUCCESS; + } + } } funct_exit: mutex_exit(&(dict_sys->mutex)); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index abae7f373bf..a7462babb73 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2234,7 +2234,7 @@ row_sel_get_clust_rec_for_mysql( (or old_vers) is not rec; in that case we must ignore such row because in our snapshot rec would not have existed. Remember that from rec we cannot see directly which transaction - id corrsponds to it: we have to go to the clustered index + id corresponds to it: we have to go to the clustered index record. A query where we want to fetch all rows where the secondary index value is in some interval would return a wrong result if we would not drop rows which we come to @@ -2245,6 +2245,12 @@ row_sel_get_clust_rec_for_mysql( && !row_sel_sec_rec_is_for_clust_rec(rec, sec_index, clust_rec, clust_index)) { clust_rec = NULL; + } else { +#ifdef UNIV_SEARCH_DEBUG + ut_a(clust_rec == NULL || + row_sel_sec_rec_is_for_clust_rec(rec, sec_index, + clust_rec, clust_index)); +#endif } } @@ -2400,7 +2406,12 @@ row_sel_try_search_shortcut_for_mysql( btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, pcur, - RW_S_LATCH, mtr); +#ifndef UNIV_SEARCH_DEBUG + RW_S_LATCH, +#else + 0, +#endif + mtr); rec = btr_pcur_get_rec(pcur); if (!page_rec_is_user_rec(rec)) { @@ -2624,15 +2635,18 @@ row_search_for_mysql( goto no_shortcut; } - +#ifndef UNIV_SEARCH_DEBUG if (!trx->has_search_latch) { rw_lock_s_lock(&btr_search_latch); trx->has_search_latch = TRUE; } - +#endif shortcut = row_sel_try_search_shortcut_for_mysql(&rec, prebuilt, &mtr); if (shortcut == SEL_FOUND) { +#ifdef UNIV_SEARCH_DEBUG + ut_a(0 == cmp_dtuple_rec(search_tuple, rec)); +#endif row_sel_store_mysql_rec(buf, prebuilt, rec); mtr_commit(&mtr); @@ -2794,7 +2808,9 @@ rec_loop: /* The record matches enough */ ut_ad(mode == PAGE_CUR_GE); - +#ifdef UNIV_SEARCH_DEBUG + ut_a(0 == cmp_dtuple_rec(search_tuple, rec)); +#endif } else if (match_mode == ROW_SEL_EXACT) { /* Test if the index record matches completely to search_tuple in prebuilt: if not, then we return with DB_RECORD_NOT_FOUND */ diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 31d58dd04a2..710f650c0bd 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -142,7 +142,7 @@ try_again: /************************************************************************* Checks if possible foreign key constraints hold after a delete of the record -under pcur. NOTE that this function will temporarily commit mtr and lose +under pcur. NOTE that this function will temporarily commit mtr and lose the pcur position! */ static ulint |