http://database.51cto.com/art/201303/383042.htm
/******************************************************//** The following function determines the offsets to each field in the record. The offsets are written to a previously allocated array of 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; 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 high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the field i is being stored externally. */ static void rec_init_offsets( /*=============*/ const rec_t* rec, /*!< in: physical record */ const dict_index_t* index, /*!< in: record descriptor */ ulint* offsets)/*!< in/out: array of offsets; in: n=rec_offs_n_fields(offsets) */ { ulint i = ; ulint offs; rec_offs_make_valid(rec, index, offsets); if (dict_table_is_comp(index->table)) { const byte* nulls; const byte* lens; dict_field_t* field; ulint null_mask; ulint status = rec_get_status(rec); ulint n_node_ptr_field = ULINT_UNDEFINED; switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) { case REC_STATUS_INFIMUM: case REC_STATUS_SUPREMUM: /* the field is 8 bytes long */ rec_offs_base(offsets)[] = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT; rec_offs_base(offsets)[] = ; return; case REC_STATUS_NODE_PTR: n_node_ptr_field = dict_index_get_n_unique_in_tree(index); break; case REC_STATUS_ORDINARY: rec_init_offsets_comp_ordinary( rec, FALSE, index, offsets); return; } nulls = rec - (REC_N_NEW_EXTRA_BYTES + ); lens = nulls - UT_BITS_IN_BYTES(index->n_nullable); offs = ; null_mask = ; /* read the lengths of fields 0..n */ do { ulint len; if (UNIV_UNLIKELY(i == n_node_ptr_field)) { len = offs += REC_NODE_PTR_SIZE; goto resolved; } field = dict_index_get_nth_field(index, i); if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) { /* nullable field => read the null flag */ if (UNIV_UNLIKELY(!(byte) null_mask)) { nulls--; null_mask = ; } if (*nulls & null_mask) { null_mask <<= ; /* No length is stored for NULL fields. We do not advance offs, and we set the length to zero and enable the SQL NULL flag in offsets[]. */ len = offs | REC_OFFS_SQL_NULL; goto resolved; } null_mask <<= ; } if (UNIV_UNLIKELY(!field->fixed_len)) { /* Variable-length field: read the length */ const dict_col_t* col = dict_field_get_col(field); len = *lens--; /* If the maximum length of the field is up to 255 bytes, the actual length is always stored in one byte. If the maximum length is more than 255 bytes, the actual length is stored in one byte for 0..127. The length will be encoded in two bytes when it is 128 or more, or when the field is stored externally. */ ) || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) { if (len & 0x80) { /* 1exxxxxxx xxxxxxxx */ len <<= ; len |= *lens--; /* B-tree node pointers must not contain externally stored columns. Thus the "e" flag must be 0. */ ut_a(!(len & 0x4000)); offs += len & 0x3fff; len = offs; goto resolved; } } len = offs += len; } else { len = offs += field->fixed_len; } resolved: rec_offs_base(offsets)[i + ] = len; } while (++i < rec_offs_n_fields(offsets)); *rec_offs_base(offsets) = (rec - (lens + )) | REC_OFFS_COMPACT; } else { /* Old-style record: determine extra size and end offsets */ offs = REC_N_OLD_EXTRA_BYTES; if (rec_get_1byte_offs_flag(rec)) { offs += rec_offs_n_fields(offsets); *rec_offs_base(offsets) = offs; /* Determine offsets to fields */ do { offs = rec_1_get_field_end_info(rec, i); if (offs & REC_1BYTE_SQL_NULL_MASK) { offs &= ~REC_1BYTE_SQL_NULL_MASK; offs |= REC_OFFS_SQL_NULL; } rec_offs_base(offsets)[ + i] = offs; } while (++i < rec_offs_n_fields(offsets)); } else { offs += * rec_offs_n_fields(offsets); *rec_offs_base(offsets) = offs; /* Determine offsets to fields */ do { offs = rec_2_get_field_end_info(rec, i); if (offs & REC_2BYTE_SQL_NULL_MASK) { offs &= ~REC_2BYTE_SQL_NULL_MASK; offs |= REC_OFFS_SQL_NULL; } 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)[ + i] = offs; } while (++i < rec_offs_n_fields(offsets)); } } }