summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
authorunknown <heikki@donna.mysql.fi>2001-04-27 21:12:15 +0300
committerunknown <heikki@donna.mysql.fi>2001-04-27 21:12:15 +0300
commitd067af6a168860548f31175966bfc830028dd5f6 (patch)
tree3939255428e4a2bb73bc080f3f3c953286857644 /innobase
parent26f9b9af380f411f4d5f6a23a228e0ab32e1bd92 (diff)
downloadmariadb-git-d067af6a168860548f31175966bfc830028dd5f6.tar.gz
row0sel.c Fix a bug in multiversioned reads through a secondary index
row0uins.c Partial fix to the DROP TABLE + another user rolls back in that table problem row0umod.c Partial fix to the DROP TABLE + another user rolls back in that table problem os0file.c Reduce probability of deadlock bugs in connection with ibuf: do not let the ibuf i/o handler sleep innobase/os/os0file.c: Reduce probability of deadlock bugs in connection with ibuf: do not let the ibuf i/o handler sleep innobase/row/row0uins.c: Partial fix to the DROP TABLE + another user rolls back in that table problem innobase/row/row0umod.c: Partial fix to the DROP TABLE + another user rolls back in that table problem innobase/row/row0sel.c: Fix a bug in multiversioned reads through a secondary index
Diffstat (limited to 'innobase')
-rw-r--r--innobase/os/os0file.c4
-rw-r--r--innobase/row/row0sel.c91
-rw-r--r--innobase/row/row0uins.c11
-rw-r--r--innobase/row/row0umod.c18
4 files changed, 119 insertions, 5 deletions
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index c2cedba5137..3b610990cb9 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -1348,6 +1348,10 @@ try_again:
}
} else if (mode == OS_AIO_IBUF) {
ut_ad(type == OS_FILE_READ);
+ /* Reduce probability of deadlock bugs in connection with ibuf:
+ do not let the ibuf i/o handler sleep */
+
+ wake_later = FALSE;
array = os_aio_ibuf_array;
} else if (mode == OS_AIO_LOG) {
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index e6182257581..8845f9192da 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -48,6 +48,52 @@ to que_run_threads: this is to allow canceling runaway queries */
#define SEL_EXHAUSTED 1
#define SEL_RETRY 2
+/************************************************************************
+Returns TRUE if the user-defined column values in a secondary index record
+are the same as the corresponding columns in the clustered index record. */
+static
+ibool
+row_sel_sec_rec_is_for_clust_rec(
+/*=============================*/
+ rec_t* sec_rec,
+ dict_index_t* sec_index,
+ rec_t* clust_rec,
+ dict_index_t* clust_index)
+{
+ dict_col_t* col;
+ byte* sec_field;
+ ulint sec_len;
+ byte* clust_field;
+ ulint clust_len;
+ ulint n;
+ ulint i;
+
+ n = dict_index_get_n_ordering_defined_by_user(sec_index);
+
+ for (i = 0; i++; i < n) {
+ col = dict_field_get_col(
+ dict_index_get_nth_field(sec_index, i));
+
+ clust_field = rec_get_nth_field(clust_rec,
+ dict_col_get_clust_pos(col),
+ &clust_len);
+ sec_field = rec_get_nth_field(sec_rec, i, &sec_len);
+
+ if (sec_len != clust_len) {
+
+ return(FALSE);
+ }
+
+ if (sec_len != UNIV_SQL_NULL
+ && ut_memcmp(sec_field, clust_field, sec_len) != 0) {
+
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
/*************************************************************************
Creates a select node struct. */
@@ -561,6 +607,8 @@ row_sel_get_clust_rec(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
+ old_vers = NULL;
+
if (!lock_clust_rec_cons_read_sees(clust_rec, index,
node->read_view)) {
@@ -579,6 +627,28 @@ row_sel_get_clust_rec(
return(DB_SUCCESS);
}
}
+
+ /* If we had to go to an earlier version of row or the
+ secondary index record is delete marked, then it may be that
+ the secondary index record corresponding to clust_rec
+ (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 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
+ visit through secondary index records that would not really
+ exist in our snapshot. */
+
+ if ((old_vers || rec_get_deleted_flag(rec))
+ && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
+ clust_rec, index)) {
+ clust_rec = NULL;
+ *out_rec = clust_rec;
+
+ return(DB_SUCCESS);
+ }
}
/* Fetch the columns needed in test conditions */
@@ -2105,6 +2175,8 @@ row_sel_get_clust_rec_for_mysql(
a previous version of the record */
trx = thr_get_trx(thr);
+
+ old_vers = NULL;
if (!lock_clust_rec_cons_read_sees(clust_rec, clust_index,
trx->read_view)) {
@@ -2121,6 +2193,25 @@ row_sel_get_clust_rec_for_mysql(
clust_rec = old_vers;
}
+
+ /* If we had to go to an earlier version of row or the
+ secondary index record is delete marked, then it may be that
+ the secondary index record corresponding to clust_rec
+ (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
+ 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
+ visit through secondary index records that would not really
+ exist in our snapshot. */
+
+ if ((old_vers || rec_get_deleted_flag(rec))
+ && !row_sel_sec_rec_is_for_clust_rec(rec, sec_index,
+ clust_rec, clust_index)) {
+ clust_rec = NULL;
+ }
}
*out_rec = clust_rec;
diff --git a/innobase/row/row0uins.c b/innobase/row/row0uins.c
index 68115895dbb..426eec0cd50 100644
--- a/innobase/row/row0uins.c
+++ b/innobase/row/row0uins.c
@@ -250,9 +250,12 @@ row_undo_ins_parse_undo_rec(
ut_ad(type == TRX_UNDO_INSERT_REC);
node->rec_type = type;
- /* NOTE that the table has to be explicitly released later */
node->table = dict_table_get_on_id(table_id, node->trx);
+ if (node->table == NULL) {
+ return;
+ }
+
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
@@ -280,7 +283,11 @@ row_undo_ins(
row_undo_ins_parse_undo_rec(node, thr);
- found = row_undo_search_clust_to_pcur(node, thr);
+ if (node->table == NULL) {
+ found = FALSE;
+ } else {
+ found = row_undo_search_clust_to_pcur(node, thr);
+ }
if (!found) {
return(DB_SUCCESS);
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index 2aa223a6186..84e8d9ee5f5 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -534,9 +534,16 @@ row_undo_mod_parse_undo_rec(
&undo_no, &table_id);
node->rec_type = type;
- /* NOTE that the table has to be explicitly released later */
node->table = dict_table_get_on_id(table_id, thr_get_trx(thr));
+ /* TODO: other fixes associated with DROP TABLE + rollback in the
+ same table by another user */
+
+ if (node->table == NULL) {
+ /* Table was dropped */
+ return;
+ }
+
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
@@ -571,11 +578,16 @@ row_undo_mod(
row_undo_mod_parse_undo_rec(node, thr);
- found = row_undo_search_clust_to_pcur(node, thr);
+ if (node->table == NULL) {
+ found = FALSE;
+ } else {
+
+ found = row_undo_search_clust_to_pcur(node, thr);
+ }
if (!found) {
/* It is already undone, or will be undone by another query
- thread */
+ thread, or table was dropped */
node->state = UNDO_NODE_FETCH_NEXT;