Skip to content

Commit cb16bc9

Browse files
committed
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.
1 parent 38bc4bc commit cb16bc9

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

storage/innobase/rem/rem0rec.cc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,7 @@ rec_copy_prefix_to_buf(
18381838
const byte* nulls;
18391839
const byte* lens;
18401840
ulint prefix_len = 0;
1841+
ulint instant_len = 0;
18411842

18421843
ut_ad(n_fields <= index->n_fields || dict_index_is_ibuf(index));
18431844
ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable));
@@ -1892,6 +1893,8 @@ rec_copy_prefix_to_buf(
18921893
nulls = &rec[-REC_N_NEW_EXTRA_BYTES];
18931894
const ulint n_rec = ulint(index->n_core_fields) + 1
18941895
+ rec_get_n_add_field(nulls);
1896+
instant_len = ulint(&rec[-REC_N_NEW_EXTRA_BYTES] - nulls);
1897+
ut_ad(instant_len == 1 || instant_len == 2);
18951898
const uint n_nullable = index->get_n_nullable(n_rec);
18961899
lens = --nulls - UT_BITS_IN_BYTES(n_nullable);
18971900
}
@@ -1947,17 +1950,29 @@ rec_copy_prefix_to_buf(
19471950

19481951
UNIV_PREFETCH_R(rec + prefix_len);
19491952

1950-
prefix_len += ulint(rec - (lens + 1));
1953+
prefix_len += ulint(rec - (lens + 1)) - instant_len;
19511954

19521955
if ((*buf == NULL) || (*buf_size < prefix_len)) {
19531956
ut_free(*buf);
19541957
*buf_size = prefix_len;
19551958
*buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
19561959
}
19571960

1958-
memcpy(*buf, lens + 1, prefix_len);
1959-
1960-
return(*buf + (rec - (lens + 1)));
1961+
if (instant_len) {
1962+
ulint hdr = ulint(&rec[-REC_N_NEW_EXTRA_BYTES] - (lens + 1))
1963+
- instant_len;
1964+
memcpy(*buf, lens + 1, hdr);
1965+
memcpy(*buf + hdr, &rec[-REC_N_NEW_EXTRA_BYTES],
1966+
prefix_len - hdr);
1967+
ut_ad(rec_get_status(*buf + hdr + REC_N_NEW_EXTRA_BYTES)
1968+
== REC_STATUS_COLUMNS_ADDED);
1969+
rec_set_status(*buf + hdr + REC_N_NEW_EXTRA_BYTES,
1970+
REC_STATUS_ORDINARY);
1971+
return *buf + hdr + REC_N_NEW_EXTRA_BYTES;
1972+
} else {
1973+
memcpy(*buf, lens + 1, prefix_len);
1974+
return *buf + (rec - (lens + 1));
1975+
}
19611976
}
19621977

19631978
/***************************************************************//**

0 commit comments

Comments
 (0)