mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
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.
This commit is contained in:
parent
38bc4bcc96
commit
cb16bc95ff
1 changed files with 19 additions and 4 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************//**
|
||||
|
|
Loading…
Reference in a new issue