summaryrefslogtreecommitdiff
path: root/innobase/row
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/row')
-rw-r--r--innobase/row/row0ins.c31
-rw-r--r--innobase/row/row0mysql.c80
-rw-r--r--innobase/row/row0sel.c26
-rw-r--r--innobase/row/row0upd.c2
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