diff --git a/include/rem0rec.h b/include/rem0rec.h index 7a6665881bd..a4bbe11294f 100644 --- a/include/rem0rec.h +++ b/include/rem0rec.h @@ -420,6 +420,15 @@ rec_offs_comp( /* out: nonzero if compact format */ const ulint* offsets);/* in: array returned by rec_get_offsets() */ /********************************************************** +Determine if the offsets are for a record containing +externally stored columns. */ +UNIV_INLINE +ulint +rec_offs_any_extern( +/*================*/ + /* out: nonzero if externally stored */ + const ulint* offsets);/* in: array returned by rec_get_offsets() */ +/********************************************************** Returns nonzero if the extern bit is set in nth field of rec. */ UNIV_INLINE ulint @@ -448,15 +457,6 @@ rec_offs_nth_size( ulint n); /* in: nth field */ /********************************************************** -Returns TRUE if the extern bit is set in any of the fields -of a record. */ -UNIV_INLINE -ibool -rec_offs_any_extern( -/*================*/ - /* out: TRUE if a field is stored externally */ - const ulint* offsets);/* in: array returned by rec_get_offsets() */ -/********************************************************** Returns the number of extern bits set in a record. */ UNIV_INLINE ulint diff --git a/include/rem0rec.ic b/include/rem0rec.ic index fce467b3fff..514182dbda4 100644 --- a/include/rem0rec.ic +++ b/include/rem0rec.ic @@ -1045,6 +1045,20 @@ rec_offs_comp( return(*rec_offs_base(offsets) & REC_OFFS_COMPACT); } +/********************************************************** +Determine if the offsets are for a record containing +externally stored columns. */ +UNIV_INLINE +ulint +rec_offs_any_extern( +/*================*/ + /* out: nonzero if externally stored */ + const ulint* offsets)/* in: array returned by rec_get_offsets() */ +{ + ut_ad(rec_offs_validate(NULL, NULL, offsets)); + return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL)); +} + /********************************************************** Returns nonzero if the extern bit is set in nth field of rec. */ UNIV_INLINE @@ -1093,25 +1107,6 @@ rec_offs_nth_size( & REC_OFFS_MASK); } -/********************************************************** -Returns TRUE if the extern bit is set in any of the fields -of a record. */ -UNIV_INLINE -ibool -rec_offs_any_extern( -/*================*/ - /* out: TRUE if a field is stored externally */ - const ulint* offsets)/* in: array returned by rec_get_offsets() */ -{ - ulint i; - for (i = rec_offs_n_fields(offsets); i--; ) { - if (rec_offs_nth_extern(offsets, i)) { - return(TRUE); - } - } - return(FALSE); -} - /********************************************************** Returns the number of extern bits set in a record. */ UNIV_INLINE @@ -1121,13 +1116,18 @@ rec_offs_n_extern( /* out: number of externally stored fields */ const ulint* offsets)/* in: array returned by rec_get_offsets() */ { - ulint i; ulint n = 0; - for (i = rec_offs_n_fields(offsets); i--; ) { - if (rec_offs_nth_extern(offsets, i)) { - n++; + + if (rec_offs_any_extern(offsets)) { + ulint i; + + for (i = rec_offs_n_fields(offsets); i--; ) { + if (rec_offs_nth_extern(offsets, i)) { + n++; + } } } + return(n); } @@ -1416,7 +1416,7 @@ rec_offs_extra_size( { ulint size; ut_ad(rec_offs_validate(NULL, NULL, offsets)); - size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT; + size = *rec_offs_base(offsets) & ~(REC_OFFS_COMPACT | REC_OFFS_EXTERNAL); ut_ad(size < UNIV_PAGE_SIZE); return(size); } diff --git a/page/page0zip.c b/page/page0zip.c index 9a4ea45ff9c..59cf206cde2 100644 --- a/page/page0zip.c +++ b/page/page0zip.c @@ -2200,6 +2200,9 @@ zlib_done: columns in this record. For each externally stored column, restore or clear the BTR_EXTERN_FIELD_REF. */ + if (!rec_offs_any_extern(offsets)) { + continue; + } for (i = 0; i < rec_offs_n_fields(offsets); i++) { if (!rec_offs_nth_extern(offsets, i)) { @@ -3159,16 +3162,20 @@ page_zip_clear_rec( /* Do not clear the record, because there is not enough space to log the operation. */ - ulint i; - for (i = rec_offs_n_fields(offsets); i--; ) { - /* Clear all BLOB pointers in order to make - page_zip_validate() pass. */ - if (rec_offs_nth_extern(offsets, i)) { - ulint len; - byte* field = rec_get_nth_field(rec, offsets, - i, &len); - memset(field + len - BTR_EXTERN_FIELD_REF_SIZE, - 0, BTR_EXTERN_FIELD_REF_SIZE); + if (rec_offs_any_extern(offsets)) { + ulint i; + + for (i = rec_offs_n_fields(offsets); i--; ) { + /* Clear all BLOB pointers in order to make + page_zip_validate() pass. */ + if (rec_offs_nth_extern(offsets, i)) { + ulint len; + byte* field = rec_get_nth_field( + rec, offsets, i, &len); + memset(field + len + - BTR_EXTERN_FIELD_REF_SIZE, + 0, BTR_EXTERN_FIELD_REF_SIZE); + } } } } diff --git a/rem/rem0rec.c b/rem/rem0rec.c index 6279488bb77..394613b33f9 100644 --- a/rem/rem0rec.c +++ b/rem/rem0rec.c @@ -218,7 +218,8 @@ ulint, where rec_offs_n_fields(offsets) has been initialized to the number of fields in the record. The rest of the array will be initialized by this function. rec_offs_base(offsets)[0] will be set to the extra size (if REC_OFFS_COMPACT is set, the record is in the -new format), and rec_offs_base(offsets)[1..n_fields] will be set to +new format; if REC_OFFS_EXTERNAL is set, the record contains externally +stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to offsets past the end of fields 0..n_fields, or to the beginning of fields 1..n_fields+1. When the high-order bit of the offset at [i+1] is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second @@ -240,6 +241,7 @@ rec_init_offsets( rec_offs_make_valid(rec, index, offsets); if (dict_table_is_comp(index->table)) { + ulint any_ext; const byte* nulls; const byte* lens; dict_field_t* field; @@ -266,6 +268,7 @@ rec_init_offsets( nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1); lens = nulls - (index->n_nullable + 7) / 8; offs = 0; + any_ext = 0; null_mask = 1; /* read the lengths of fields 0..n */ @@ -316,6 +319,7 @@ rec_init_offsets( & 0x4000)) { ut_ad(dict_index_is_clust (index)); + any_ext = REC_OFFS_EXTERNAL; len = offs | REC_OFFS_EXTERNAL; } else { @@ -335,7 +339,7 @@ resolved: } while (++i < rec_offs_n_fields(offsets)); *rec_offs_base(offsets) - = (rec - (lens + 1)) | REC_OFFS_COMPACT; + = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext; } else { /* Old-style record: determine extra size and end offsets */ offs = REC_N_OLD_EXTRA_BYTES; @@ -364,6 +368,7 @@ resolved: if (offs & REC_2BYTE_EXTERN_MASK) { offs &= ~REC_2BYTE_EXTERN_MASK; offs |= REC_OFFS_EXTERNAL; + *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL; } rec_offs_base(offsets)[1 + i] = offs; } while (++i < rec_offs_n_fields(offsets)); @@ -459,6 +464,7 @@ rec_get_offsets_reverse( ulint n; ulint i; ulint offs; + ulint any_ext; const byte* nulls; const byte* lens; dict_field_t* field; @@ -485,6 +491,7 @@ rec_get_offsets_reverse( lens = nulls + (index->n_nullable + 7) / 8; i = offs = 0; null_mask = 1; + any_ext = 0; /* read the lengths of fields 0..n */ do { @@ -529,6 +536,7 @@ rec_get_offsets_reverse( offs += len & 0x3fff; if (UNIV_UNLIKELY(len & 0x4000)) { + any_ext = REC_OFFS_EXTERNAL; len = offs | REC_OFFS_EXTERNAL; } else { len = offs; @@ -548,7 +556,7 @@ resolved: ut_ad(lens >= extra); *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES) - | REC_OFFS_COMPACT; + | REC_OFFS_COMPACT | any_ext; } /****************************************************************