summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2018-04-30 11:25:36 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-04-30 12:00:30 +0300
commitcb16bc95ff9a7b4ce0835acf8fa6d6a06ad10c3c (patch)
tree661f3c2974a8168c55acc7049fa83bfb07c7c17a
parent38bc4bcc964794f3cfc3d117079679c33f72f11a (diff)
downloadmariadb-git-cb16bc95ff9a7b4ce0835acf8fa6d6a06ad10c3c.tar.gz
MDEV-14906 Assertion index->is_instant() failed on DELETE
The assertion would fail with the following trace: rec_init_offsets_comp_ordinary(..., format=REC_LEAF_COLUMNS_ADDED) rec_init_offsets() rec_get_offsets_func() rec_copy_prefix_to_dtuple() dict_index_build_data_tuple() btr_pcur_restore_position_func() When btr_cur_store_position() had stored pcur->old_rec, the table contained instantly added columns. The table was emptied (dict_index_t::remove_instant() invoked) between the 'store' and 'restore' operations, causing the assertion to fail. Here is a non-deterministic test case to repeat the scenario: --source include/have_innodb.inc --connect (con1,localhost,root,,test) CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE = InnoDB; INSERT INTO t1 VALUES (0); ALTER TABLE t1 ADD COLUMN a INT; ALTER TABLE t1 ADD UNIQUE KEY (a); DELETE FROM t1; send INSERT INTO t1 VALUES (1,0),(2,0); --connection default DELETE FROM t1; # the assertion could fail here DROP TABLE t1; --disconnect con1 The fix is to normalize the pcur->old_rec so that when the record prefix is stored, it will always be in the plain format. This can be done, because the record prefix never includes any instantly added columns. (It can only include key columns, which can never be instantly added.) rec_copy_prefix_to_buf(): Convert REC_STATUS_COLUMNS_ADDED to REC_STATUS_ORDINARY format.
-rw-r--r--storage/innobase/rem/rem0rec.cc23
1 files changed, 19 insertions, 4 deletions
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
index 77b3fcb7906..0180d10ed44 100644
--- a/storage/innobase/rem/rem0rec.cc
+++ b/storage/innobase/rem/rem0rec.cc
@@ -1838,6 +1838,7 @@ rec_copy_prefix_to_buf(
const byte* nulls;
const byte* lens;
ulint prefix_len = 0;
+ ulint instant_len = 0;
ut_ad(n_fields <= index->n_fields || dict_index_is_ibuf(index));
ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable));
@@ -1892,6 +1893,8 @@ rec_copy_prefix_to_buf(
nulls = &rec[-REC_N_NEW_EXTRA_BYTES];
const ulint n_rec = ulint(index->n_core_fields) + 1
+ rec_get_n_add_field(nulls);
+ instant_len = ulint(&rec[-REC_N_NEW_EXTRA_BYTES] - nulls);
+ ut_ad(instant_len == 1 || instant_len == 2);
const uint n_nullable = index->get_n_nullable(n_rec);
lens = --nulls - UT_BITS_IN_BYTES(n_nullable);
}
@@ -1947,7 +1950,7 @@ rec_copy_prefix_to_buf(
UNIV_PREFETCH_R(rec + prefix_len);
- prefix_len += ulint(rec - (lens + 1));
+ prefix_len += ulint(rec - (lens + 1)) - instant_len;
if ((*buf == NULL) || (*buf_size < prefix_len)) {
ut_free(*buf);
@@ -1955,9 +1958,21 @@ rec_copy_prefix_to_buf(
*buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
}
- memcpy(*buf, lens + 1, prefix_len);
-
- return(*buf + (rec - (lens + 1)));
+ if (instant_len) {
+ ulint hdr = ulint(&rec[-REC_N_NEW_EXTRA_BYTES] - (lens + 1))
+ - instant_len;
+ memcpy(*buf, lens + 1, hdr);
+ memcpy(*buf + hdr, &rec[-REC_N_NEW_EXTRA_BYTES],
+ prefix_len - hdr);
+ ut_ad(rec_get_status(*buf + hdr + REC_N_NEW_EXTRA_BYTES)
+ == REC_STATUS_COLUMNS_ADDED);
+ rec_set_status(*buf + hdr + REC_N_NEW_EXTRA_BYTES,
+ REC_STATUS_ORDINARY);
+ return *buf + hdr + REC_N_NEW_EXTRA_BYTES;
+ } else {
+ memcpy(*buf, lens + 1, prefix_len);
+ return *buf + (rec - (lens + 1));
+ }
}
/***************************************************************//**