diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-04-30 11:25:36 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-04-30 12:00:30 +0300 |
commit | cb16bc95ff9a7b4ce0835acf8fa6d6a06ad10c3c (patch) | |
tree | 661f3c2974a8168c55acc7049fa83bfb07c7c17a /storage | |
parent | 38bc4bcc964794f3cfc3d117079679c33f72f11a (diff) | |
download | mariadb-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.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/rem/rem0rec.cc | 23 |
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)); + } } /***************************************************************//** |