MDEV-21899 INSERT into a secondary index with zero-data-length key is not crash-safe

page_cur_insert_rec_low(): Remove a bogus condition that wrongly
omitted redo logging when the record contains no data payload bytes.
We can have such records in secondary indexes, when the values of
the PRIMARY KEY column(s) are the empty string, and the values of
secondary key column(s) are are NULL or the empty string.

page_apply_delete_dynamic(): Improve the consistency check, and
do not allow adjacent records to be less than 5 bytes apart from
each other. The fixed-size part of the record header is 5 bytes.
Usually there must also be some header or payload bytes, but in
an extreme case where all columns are CHAR(0) NOT NULL, the
minimum secondary index record size is 5 bytes, and the table can
contain at most 1 row. The minimum clustered index record size is
5+6+7 bytes (header, DB_TRX_ID, DB_ROLL_PTR) or x+5+4 bytes
(fixed-size header, child page number, and some additional header
or payload bytes).
This commit is contained in:
Marko Mäkelä 2020-03-27 08:59:20 +02:00
parent eb483c5181
commit f614b6ea61

View File

@ -1551,7 +1551,6 @@ inc_dir:
/* Insert the record, possibly copying from the preceding record. */
ut_ad(mtr->get_log_mode() == MTR_LOG_ALL);
if (data_size)
{
const byte *r= rec;
const byte *c= cur->rec;
@ -2883,7 +2882,11 @@ corrupted:
ulint slot_owned;
for (ulint i= n_recs; !(slot_owned= rec_get_n_owned_new(s)); )
{
n= static_cast<uint16_t>(n + mach_read_from_2(s - REC_NEXT));
const uint16_t next= mach_read_from_2(s - REC_NEXT);
if (UNIV_UNLIKELY(next < REC_N_NEW_EXTRA_BYTES ||
next > static_cast<uint16_t>(-REC_N_NEW_EXTRA_BYTES)))
goto corrupted;
n= static_cast<uint16_t>(n + next);
s= block.frame + n;
if (n == PAGE_NEW_SUPREMUM);
else if (UNIV_UNLIKELY(n < PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES ||