1/*****************************************************************************
2
3Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 2018, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/********************************************************************//**
21@file include/rem0rec.ic
22Record manager
23
24Created 5/30/1994 Heikki Tuuri
25*************************************************************************/
26
27#include "mach0data.h"
28#include "ut0byte.h"
29#include "dict0boot.h"
30#include "btr0types.h"
31
32/* Offsets of the bit-fields in an old-style record. NOTE! In the table the
33most significant bytes and bits are written below less significant.
34
35 (1) byte offset (2) bit usage within byte
36 downward from
37 origin -> 1 8 bits pointer to next record
38 2 8 bits pointer to next record
39 3 1 bit short flag
40 7 bits number of fields
41 4 3 bits number of fields
42 5 bits heap number
43 5 8 bits heap number
44 6 4 bits n_owned
45 4 bits info bits
46*/
47
48/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
49most significant bytes and bits are written below less significant.
50
51 (1) byte offset (2) bit usage within byte
52 downward from
53 origin -> 1 8 bits relative offset of next record
54 2 8 bits relative offset of next record
55 the relative offset is an unsigned 16-bit
56 integer:
57 (offset_of_next_record
58 - offset_of_this_record) mod 64Ki,
59 where mod is the modulo as a non-negative
60 number;
61 we can calculate the offset of the next
62 record with the formula:
63 relative_offset + offset_of_this_record
64 mod srv_page_size
65 3 3 bits status:
66 000=REC_STATUS_ORDINARY
67 001=REC_STATUS_NODE_PTR
68 010=REC_STATUS_INFIMUM
69 011=REC_STATUS_SUPREMUM
70 100=REC_STATUS_COLUMNS_ADDED
71 1xx=reserved
72 5 bits heap number
73 4 8 bits heap number
74 5 4 bits n_owned
75 4 bits info bits
76*/
77
78/* We list the byte offsets from the origin of the record, the mask,
79and the shift needed to obtain each bit-field of the record. */
80
81#define REC_NEXT 2
82#define REC_NEXT_MASK 0xFFFFUL
83#define REC_NEXT_SHIFT 0
84
85#define REC_OLD_SHORT 3 /* This is single byte bit-field */
86#define REC_OLD_SHORT_MASK 0x1UL
87#define REC_OLD_SHORT_SHIFT 0
88
89#define REC_OLD_N_FIELDS 4
90#define REC_OLD_N_FIELDS_MASK 0x7FEUL
91#define REC_OLD_N_FIELDS_SHIFT 1
92
93#define REC_OLD_HEAP_NO 5
94#define REC_HEAP_NO_MASK 0xFFF8UL
95#if 0 /* defined in rem0rec.h for use of page0zip.cc */
96#define REC_NEW_HEAP_NO 4
97#define REC_HEAP_NO_SHIFT 3
98#endif
99
100#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */
101#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */
102#define REC_N_OWNED_MASK 0xFUL
103#define REC_N_OWNED_SHIFT 0
104
105#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */
106#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */
107#define REC_INFO_BITS_MASK 0xF0UL
108#define REC_INFO_BITS_SHIFT 0
109
110#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
111 ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
112 ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
113 ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
114 ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
115 ^ 0xFFFFFFFFUL
116# error "sum of old-style masks != 0xFFFFFFFFUL"
117#endif
118#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
119 ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
120 ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
121 ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
122 ^ 0xFFFFFFUL
123# error "sum of new-style masks != 0xFFFFFFUL"
124#endif
125
126/***********************************************************//**
127Sets the value of the ith field SQL null bit of an old-style record. */
128void
129rec_set_nth_field_null_bit(
130/*=======================*/
131 rec_t* rec, /*!< in: record */
132 ulint i, /*!< in: ith field */
133 ibool val); /*!< in: value to set */
134/***********************************************************//**
135Sets an old-style record field to SQL null.
136The physical size of the field is not changed. */
137void
138rec_set_nth_field_sql_null(
139/*=======================*/
140 rec_t* rec, /*!< in: record */
141 ulint n); /*!< in: index of the field */
142
143/******************************************************//**
144Gets a bit field from within 1 byte. */
145UNIV_INLINE
146ulint
147rec_get_bit_field_1(
148/*================*/
149 const rec_t* rec, /*!< in: pointer to record origin */
150 ulint offs, /*!< in: offset from the origin down */
151 ulint mask, /*!< in: mask used to filter bits */
152 ulint shift) /*!< in: shift right applied after masking */
153{
154 ut_ad(rec);
155
156 return((mach_read_from_1(rec - offs) & mask) >> shift);
157}
158
159/******************************************************//**
160Sets a bit field within 1 byte. */
161UNIV_INLINE
162void
163rec_set_bit_field_1(
164/*================*/
165 rec_t* rec, /*!< in: pointer to record origin */
166 ulint val, /*!< in: value to set */
167 ulint offs, /*!< in: offset from the origin down */
168 ulint mask, /*!< in: mask used to filter bits */
169 ulint shift) /*!< in: shift right applied after masking */
170{
171 ut_ad(rec);
172 ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
173 ut_ad(mask);
174 ut_ad(mask <= 0xFFUL);
175 ut_ad(((mask >> shift) << shift) == mask);
176 ut_ad(((val << shift) & mask) == (val << shift));
177
178 mach_write_to_1(rec - offs,
179 (mach_read_from_1(rec - offs) & ~mask)
180 | (val << shift));
181}
182
183/******************************************************//**
184Gets a bit field from within 2 bytes. */
185UNIV_INLINE
186ulint
187rec_get_bit_field_2(
188/*================*/
189 const rec_t* rec, /*!< in: pointer to record origin */
190 ulint offs, /*!< in: offset from the origin down */
191 ulint mask, /*!< in: mask used to filter bits */
192 ulint shift) /*!< in: shift right applied after masking */
193{
194 ut_ad(rec);
195
196 return((mach_read_from_2(rec - offs) & mask) >> shift);
197}
198
199/******************************************************//**
200Sets a bit field within 2 bytes. */
201UNIV_INLINE
202void
203rec_set_bit_field_2(
204/*================*/
205 rec_t* rec, /*!< in: pointer to record origin */
206 ulint val, /*!< in: value to set */
207 ulint offs, /*!< in: offset from the origin down */
208 ulint mask, /*!< in: mask used to filter bits */
209 ulint shift) /*!< in: shift right applied after masking */
210{
211 ut_ad(rec);
212 ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
213 ut_ad(mask > 0xFFUL);
214 ut_ad(mask <= 0xFFFFUL);
215 ut_ad((mask >> shift) & 1);
216 ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
217 ut_ad(((mask >> shift) << shift) == mask);
218 ut_ad(((val << shift) & mask) == (val << shift));
219
220 mach_write_to_2(rec - offs,
221 (mach_read_from_2(rec - offs) & ~mask)
222 | (val << shift));
223}
224
225/******************************************************//**
226The following function is used to get the pointer of the next chained record
227on the same page.
228@return pointer to the next chained record, or NULL if none */
229UNIV_INLINE
230const rec_t*
231rec_get_next_ptr_const(
232/*===================*/
233 const rec_t* rec, /*!< in: physical record */
234 ulint comp) /*!< in: nonzero=compact page format */
235{
236 ulint field_value;
237
238 compile_time_assert(REC_NEXT_MASK == 0xFFFFUL);
239 compile_time_assert(REC_NEXT_SHIFT == 0);
240
241 field_value = mach_read_from_2(rec - REC_NEXT);
242
243 if (field_value == 0) {
244
245 return(NULL);
246 }
247
248 if (comp) {
249#if UNIV_PAGE_SIZE_MAX <= 32768
250 /* Note that for 64 KiB pages, field_value can 'wrap around'
251 and the debug assertion is not valid */
252
253 /* In the following assertion, field_value is interpreted
254 as signed 16-bit integer in 2's complement arithmetics.
255 If all platforms defined int16_t in the standard headers,
256 the expression could be written simpler as
257 (int16_t) field_value + ut_align_offset(...) < srv_page_size
258 */
259 ut_ad((field_value >= 32768
260 ? field_value - 65536
261 : field_value)
262 + ut_align_offset(rec, srv_page_size)
263 < srv_page_size);
264#endif
265 /* There must be at least REC_N_NEW_EXTRA_BYTES + 1
266 between each record. */
267 ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
268 && field_value < 32768)
269 || field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
270
271 return((byte*) ut_align_down(rec, srv_page_size)
272 + ut_align_offset(rec + field_value, srv_page_size));
273 } else {
274 ut_ad(field_value < srv_page_size);
275
276 return((byte*) ut_align_down(rec, srv_page_size)
277 + field_value);
278 }
279}
280
281/******************************************************//**
282The following function is used to get the pointer of the next chained record
283on the same page.
284@return pointer to the next chained record, or NULL if none */
285UNIV_INLINE
286rec_t*
287rec_get_next_ptr(
288/*=============*/
289 rec_t* rec, /*!< in: physical record */
290 ulint comp) /*!< in: nonzero=compact page format */
291{
292 return(const_cast<rec_t*>(rec_get_next_ptr_const(rec, comp)));
293}
294
295/******************************************************//**
296The following function is used to get the offset of the next chained record
297on the same page.
298@return the page offset of the next chained record, or 0 if none */
299UNIV_INLINE
300ulint
301rec_get_next_offs(
302/*==============*/
303 const rec_t* rec, /*!< in: physical record */
304 ulint comp) /*!< in: nonzero=compact page format */
305{
306 ulint field_value;
307 compile_time_assert(REC_NEXT_MASK == 0xFFFFUL);
308 compile_time_assert(REC_NEXT_SHIFT == 0);
309
310 field_value = mach_read_from_2(rec - REC_NEXT);
311
312 if (comp) {
313#if UNIV_PAGE_SIZE_MAX <= 32768
314 /* Note that for 64 KiB pages, field_value can 'wrap around'
315 and the debug assertion is not valid */
316
317 /* In the following assertion, field_value is interpreted
318 as signed 16-bit integer in 2's complement arithmetics.
319 If all platforms defined int16_t in the standard headers,
320 the expression could be written simpler as
321 (int16_t) field_value + ut_align_offset(...) < srv_page_size
322 */
323 ut_ad((field_value >= 32768
324 ? field_value - 65536
325 : field_value)
326 + ut_align_offset(rec, srv_page_size)
327 < srv_page_size);
328#endif
329 if (field_value == 0) {
330
331 return(0);
332 }
333
334 /* There must be at least REC_N_NEW_EXTRA_BYTES + 1
335 between each record. */
336 ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
337 && field_value < 32768)
338 || field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
339
340 return(ut_align_offset(rec + field_value, srv_page_size));
341 } else {
342 ut_ad(field_value < srv_page_size);
343
344 return(field_value);
345 }
346}
347
348/******************************************************//**
349The following function is used to set the next record offset field
350of an old-style record. */
351UNIV_INLINE
352void
353rec_set_next_offs_old(
354/*==================*/
355 rec_t* rec, /*!< in: old-style physical record */
356 ulint next) /*!< in: offset of the next record */
357{
358 ut_ad(rec);
359 ut_ad(srv_page_size > next);
360 compile_time_assert(REC_NEXT_MASK == 0xFFFFUL);
361 compile_time_assert(REC_NEXT_SHIFT == 0);
362 mach_write_to_2(rec - REC_NEXT, next);
363}
364
365/******************************************************//**
366The following function is used to set the next record offset field
367of a new-style record. */
368UNIV_INLINE
369void
370rec_set_next_offs_new(
371/*==================*/
372 rec_t* rec, /*!< in/out: new-style physical record */
373 ulint next) /*!< in: offset of the next record */
374{
375 ulint field_value;
376
377 ut_ad(rec);
378 ut_ad(srv_page_size > next);
379
380 if (!next) {
381 field_value = 0;
382 } else {
383 /* The following two statements calculate
384 next - offset_of_rec mod 64Ki, where mod is the modulo
385 as a non-negative number */
386
387 field_value = (ulint)
388 ((lint) next
389 - (lint) ut_align_offset(rec, srv_page_size));
390 field_value &= REC_NEXT_MASK;
391 }
392
393 mach_write_to_2(rec - REC_NEXT, field_value);
394}
395
396/******************************************************//**
397The following function is used to get the number of fields
398in an old-style record.
399@return number of data fields */
400UNIV_INLINE
401ulint
402rec_get_n_fields_old(
403/*=================*/
404 const rec_t* rec) /*!< in: physical record */
405{
406 ulint ret;
407
408 ut_ad(rec);
409
410 ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
411 REC_OLD_N_FIELDS_MASK,
412 REC_OLD_N_FIELDS_SHIFT);
413 ut_ad(ret <= REC_MAX_N_FIELDS);
414 ut_ad(ret > 0);
415
416 return(ret);
417}
418
419/******************************************************//**
420The following function is used to set the number of fields
421in an old-style record. */
422UNIV_INLINE
423void
424rec_set_n_fields_old(
425/*=================*/
426 rec_t* rec, /*!< in: physical record */
427 ulint n_fields) /*!< in: the number of fields */
428{
429 ut_ad(rec);
430 ut_ad(n_fields <= REC_MAX_N_FIELDS);
431 ut_ad(n_fields > 0);
432
433 rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
434 REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
435}
436
437/******************************************************//**
438The following function is used to get the number of fields
439in a record.
440@return number of data fields */
441UNIV_INLINE
442ulint
443rec_get_n_fields(
444/*=============*/
445 const rec_t* rec, /*!< in: physical record */
446 const dict_index_t* index) /*!< in: record descriptor */
447{
448 ut_ad(rec);
449 ut_ad(index);
450
451 if (!dict_table_is_comp(index->table)) {
452 return(rec_get_n_fields_old(rec));
453 }
454
455 switch (rec_get_status(rec)) {
456 case REC_STATUS_COLUMNS_ADDED:
457 case REC_STATUS_ORDINARY:
458 return(dict_index_get_n_fields(index));
459 case REC_STATUS_NODE_PTR:
460 return(dict_index_get_n_unique_in_tree(index) + 1);
461 case REC_STATUS_INFIMUM:
462 case REC_STATUS_SUPREMUM:
463 return(1);
464 }
465
466 ut_error;
467 return(ULINT_UNDEFINED);
468}
469
470/** Confirms the n_fields of the entry is sane with comparing the other
471record in the same page specified
472@param[in] index index
473@param[in] rec record of the same page
474@param[in] entry index entry
475@return true if n_fields is sane */
476UNIV_INLINE
477bool
478rec_n_fields_is_sane(
479 dict_index_t* index,
480 const rec_t* rec,
481 const dtuple_t* entry)
482{
483 const ulint n_fields = rec_get_n_fields(rec, index);
484
485 return(n_fields == dtuple_get_n_fields(entry)
486 || (index->is_instant()
487 && n_fields >= index->n_core_fields)
488 /* a record for older SYS_INDEXES table
489 (missing merge_threshold column) is acceptable. */
490 || (index->table->id == DICT_INDEXES_ID
491 && n_fields == dtuple_get_n_fields(entry) - 1));
492}
493
494/******************************************************//**
495The following function is used to get the number of records owned by the
496previous directory record.
497@return number of owned records */
498UNIV_INLINE
499ulint
500rec_get_n_owned_old(
501/*================*/
502 const rec_t* rec) /*!< in: old-style physical record */
503{
504 return(rec_get_bit_field_1(rec, REC_OLD_N_OWNED,
505 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT));
506}
507
508/******************************************************//**
509The following function is used to set the number of owned records. */
510UNIV_INLINE
511void
512rec_set_n_owned_old(
513/*================*/
514 rec_t* rec, /*!< in: old-style physical record */
515 ulint n_owned) /*!< in: the number of owned */
516{
517 rec_set_bit_field_1(rec, n_owned, REC_OLD_N_OWNED,
518 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
519}
520
521/******************************************************//**
522The following function is used to get the number of records owned by the
523previous directory record.
524@return number of owned records */
525UNIV_INLINE
526ulint
527rec_get_n_owned_new(
528/*================*/
529 const rec_t* rec) /*!< in: new-style physical record */
530{
531 return(rec_get_bit_field_1(rec, REC_NEW_N_OWNED,
532 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT));
533}
534
535/******************************************************//**
536The following function is used to set the number of owned records. */
537UNIV_INLINE
538void
539rec_set_n_owned_new(
540/*================*/
541 rec_t* rec, /*!< in/out: new-style physical record */
542 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
543 ulint n_owned)/*!< in: the number of owned */
544{
545 rec_set_bit_field_1(rec, n_owned, REC_NEW_N_OWNED,
546 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
547 if (page_zip && rec_get_status(rec) != REC_STATUS_SUPREMUM) {
548 page_zip_rec_set_owned(page_zip, rec, n_owned);
549 }
550}
551
552#ifdef UNIV_DEBUG
553/** Check if the info bits are valid.
554@param[in] bits info bits to check
555@return true if valid */
556inline
557bool
558rec_info_bits_valid(
559 ulint bits)
560{
561 return(0 == (bits & ~(REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG)));
562}
563#endif /* UNIV_DEBUG */
564
565/******************************************************//**
566The following function is used to retrieve the info bits of a record.
567@return info bits */
568UNIV_INLINE
569ulint
570rec_get_info_bits(
571/*==============*/
572 const rec_t* rec, /*!< in: physical record */
573 ulint comp) /*!< in: nonzero=compact page format */
574{
575 const ulint val = rec_get_bit_field_1(
576 rec, comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
577 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
578 ut_ad(rec_info_bits_valid(val));
579 return(val);
580}
581
582/******************************************************//**
583The following function is used to set the info bits of a record. */
584UNIV_INLINE
585void
586rec_set_info_bits_old(
587/*==================*/
588 rec_t* rec, /*!< in: old-style physical record */
589 ulint bits) /*!< in: info bits */
590{
591 ut_ad(rec_info_bits_valid(bits));
592 rec_set_bit_field_1(rec, bits, REC_OLD_INFO_BITS,
593 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
594}
595/******************************************************//**
596The following function is used to set the info bits of a record. */
597UNIV_INLINE
598void
599rec_set_info_bits_new(
600/*==================*/
601 rec_t* rec, /*!< in/out: new-style physical record */
602 ulint bits) /*!< in: info bits */
603{
604 ut_ad(rec_info_bits_valid(bits));
605 rec_set_bit_field_1(rec, bits, REC_NEW_INFO_BITS,
606 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
607}
608
609/******************************************************//**
610The following function is used to retrieve the info and status
611bits of a record. (Only compact records have status bits.)
612@return info bits */
613UNIV_INLINE
614ulint
615rec_get_info_and_status_bits(
616/*=========================*/
617 const rec_t* rec, /*!< in: physical record */
618 ulint comp) /*!< in: nonzero=compact page format */
619{
620 ulint bits;
621 compile_time_assert(!((REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT)
622 & (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
623 if (comp) {
624 bits = rec_get_info_bits(rec, TRUE)
625 | ulint(rec_get_status(rec));
626 } else {
627 bits = rec_get_info_bits(rec, FALSE);
628 ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
629 }
630 return(bits);
631}
632/******************************************************//**
633The following function is used to set the info and status
634bits of a record. (Only compact records have status bits.) */
635UNIV_INLINE
636void
637rec_set_info_and_status_bits(
638/*=========================*/
639 rec_t* rec, /*!< in/out: physical record */
640 ulint bits) /*!< in: info bits */
641{
642 compile_time_assert(!((REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT)
643 & (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
644 rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
645 rec_set_info_bits_new(rec, bits & ~REC_NEW_STATUS_MASK);
646}
647
648/******************************************************//**
649The following function tells if record is delete marked.
650@return nonzero if delete marked */
651UNIV_INLINE
652ulint
653rec_get_deleted_flag(
654/*=================*/
655 const rec_t* rec, /*!< in: physical record */
656 ulint comp) /*!< in: nonzero=compact page format */
657{
658 if (comp) {
659 return(rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
660 REC_INFO_DELETED_FLAG,
661 REC_INFO_BITS_SHIFT));
662 } else {
663 return(rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
664 REC_INFO_DELETED_FLAG,
665 REC_INFO_BITS_SHIFT));
666 }
667}
668
669/******************************************************//**
670The following function is used to set the deleted bit. */
671UNIV_INLINE
672void
673rec_set_deleted_flag_old(
674/*=====================*/
675 rec_t* rec, /*!< in: old-style physical record */
676 ulint flag) /*!< in: nonzero if delete marked */
677{
678 ulint val;
679
680 val = rec_get_info_bits(rec, FALSE);
681
682 if (flag) {
683 val |= REC_INFO_DELETED_FLAG;
684 } else {
685 val &= ~REC_INFO_DELETED_FLAG;
686 }
687
688 rec_set_info_bits_old(rec, val);
689}
690
691/******************************************************//**
692The following function is used to set the deleted bit. */
693UNIV_INLINE
694void
695rec_set_deleted_flag_new(
696/*=====================*/
697 rec_t* rec, /*!< in/out: new-style physical record */
698 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
699 ulint flag) /*!< in: nonzero if delete marked */
700{
701 ulint val;
702
703 val = rec_get_info_bits(rec, TRUE);
704
705 if (flag) {
706 val |= REC_INFO_DELETED_FLAG;
707 } else {
708 val &= ~REC_INFO_DELETED_FLAG;
709 }
710
711 rec_set_info_bits_new(rec, val);
712
713 if (page_zip) {
714 page_zip_rec_set_deleted(page_zip, rec, flag);
715 }
716}
717
718/******************************************************//**
719The following function tells if a new-style record is a node pointer.
720@return TRUE if node pointer */
721UNIV_INLINE
722bool
723rec_get_node_ptr_flag(
724/*==================*/
725 const rec_t* rec) /*!< in: physical record */
726{
727 return(REC_STATUS_NODE_PTR == rec_get_status(rec));
728}
729
730/******************************************************//**
731The following function is used to get the order number
732of an old-style record in the heap of the index page.
733@return heap order number */
734UNIV_INLINE
735ulint
736rec_get_heap_no_old(
737/*================*/
738 const rec_t* rec) /*!< in: physical record */
739{
740 return(rec_get_bit_field_2(rec, REC_OLD_HEAP_NO,
741 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT));
742}
743
744/******************************************************//**
745The following function is used to set the heap number
746field in an old-style record. */
747UNIV_INLINE
748void
749rec_set_heap_no_old(
750/*================*/
751 rec_t* rec, /*!< in: physical record */
752 ulint heap_no)/*!< in: the heap number */
753{
754 rec_set_bit_field_2(rec, heap_no, REC_OLD_HEAP_NO,
755 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
756}
757
758/******************************************************//**
759The following function is used to get the order number
760of a new-style record in the heap of the index page.
761@return heap order number */
762UNIV_INLINE
763ulint
764rec_get_heap_no_new(
765/*================*/
766 const rec_t* rec) /*!< in: physical record */
767{
768 return(rec_get_bit_field_2(rec, REC_NEW_HEAP_NO,
769 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT));
770}
771
772/******************************************************//**
773The following function is used to set the heap number
774field in a new-style record. */
775UNIV_INLINE
776void
777rec_set_heap_no_new(
778/*================*/
779 rec_t* rec, /*!< in/out: physical record */
780 ulint heap_no)/*!< in: the heap number */
781{
782 rec_set_bit_field_2(rec, heap_no, REC_NEW_HEAP_NO,
783 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
784}
785
786/******************************************************//**
787The following function is used to test whether the data offsets in the record
788are stored in one-byte or two-byte format.
789@return TRUE if 1-byte form */
790UNIV_INLINE
791ibool
792rec_get_1byte_offs_flag(
793/*====================*/
794 const rec_t* rec) /*!< in: physical record */
795{
796 return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
797 REC_OLD_SHORT_SHIFT));
798}
799
800/******************************************************//**
801The following function is used to set the 1-byte offsets flag. */
802UNIV_INLINE
803void
804rec_set_1byte_offs_flag(
805/*====================*/
806 rec_t* rec, /*!< in: physical record */
807 ibool flag) /*!< in: TRUE if 1byte form */
808{
809 ut_ad(flag <= 1);
810
811 rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
812 REC_OLD_SHORT_SHIFT);
813}
814
815/******************************************************//**
816Returns the offset of nth field end if the record is stored in the 1-byte
817offsets form. If the field is SQL null, the flag is ORed in the returned
818value.
819@return offset of the start of the field, SQL null flag ORed */
820UNIV_INLINE
821ulint
822rec_1_get_field_end_info(
823/*=====================*/
824 const rec_t* rec, /*!< in: record */
825 ulint n) /*!< in: field index */
826{
827 ut_ad(rec_get_1byte_offs_flag(rec));
828 ut_ad(n < rec_get_n_fields_old(rec));
829
830 return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
831}
832
833/******************************************************//**
834Returns the offset of nth field end if the record is stored in the 2-byte
835offsets form. If the field is SQL null, the flag is ORed in the returned
836value.
837@return offset of the start of the field, SQL null flag and extern
838storage flag ORed */
839UNIV_INLINE
840ulint
841rec_2_get_field_end_info(
842/*=====================*/
843 const rec_t* rec, /*!< in: record */
844 ulint n) /*!< in: field index */
845{
846 ut_ad(!rec_get_1byte_offs_flag(rec));
847 ut_ad(n < rec_get_n_fields_old(rec));
848
849 return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
850}
851
852/******************************************************//**
853Returns nonzero if the field is stored off-page.
854@retval 0 if the field is stored in-page
855@retval REC_2BYTE_EXTERN_MASK if the field is stored externally */
856UNIV_INLINE
857ulint
858rec_2_is_field_extern(
859/*==================*/
860 const rec_t* rec, /*!< in: record */
861 ulint n) /*!< in: field index */
862{
863 return(rec_2_get_field_end_info(rec, n) & REC_2BYTE_EXTERN_MASK);
864}
865
866/**********************************************************//**
867The following function sets the number of allocated elements
868for an array of offsets. */
869UNIV_INLINE
870void
871rec_offs_set_n_alloc(
872/*=================*/
873 ulint* offsets, /*!< out: array for rec_get_offsets(),
874 must be allocated */
875 ulint n_alloc) /*!< in: number of elements */
876{
877 ut_ad(offsets);
878 ut_ad(n_alloc > REC_OFFS_HEADER_SIZE);
879 UNIV_MEM_ALLOC(offsets, n_alloc * sizeof *offsets);
880 offsets[0] = n_alloc;
881}
882
883/************************************************************//**
884The following function is used to get an offset to the nth
885data field in a record.
886@return offset from the origin of rec */
887UNIV_INLINE
888ulint
889rec_get_nth_field_offs(
890/*===================*/
891 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
892 ulint n, /*!< in: index of the field */
893 ulint* len) /*!< out: length of the field; UNIV_SQL_NULL
894 if SQL null; UNIV_SQL_DEFAULT is default value */
895{
896 ulint offs;
897 ulint length;
898 ut_ad(n < rec_offs_n_fields(offsets));
899 ut_ad(len);
900
901 if (n == 0) {
902 offs = 0;
903 } else {
904 offs = rec_offs_base(offsets)[n] & REC_OFFS_MASK;
905 }
906
907 length = rec_offs_base(offsets)[1 + n];
908
909 if (length & REC_OFFS_SQL_NULL) {
910 length = UNIV_SQL_NULL;
911 } else if (length & REC_OFFS_DEFAULT) {
912 length = UNIV_SQL_DEFAULT;
913 } else {
914 length &= REC_OFFS_MASK;
915 length -= offs;
916 }
917
918 *len = length;
919 return(offs);
920}
921
922/******************************************************//**
923Determine if the offsets are for a record containing null BLOB pointers.
924@return first field containing a null BLOB pointer, or NULL if none found */
925UNIV_INLINE
926const byte*
927rec_offs_any_null_extern(
928/*=====================*/
929 const rec_t* rec, /*!< in: record */
930 const ulint* offsets) /*!< in: rec_get_offsets(rec) */
931{
932 ulint i;
933 ut_ad(rec_offs_validate(rec, NULL, offsets));
934
935 if (!rec_offs_any_extern(offsets)) {
936 return(NULL);
937 }
938
939 for (i = 0; i < rec_offs_n_fields(offsets); i++) {
940 if (rec_offs_nth_extern(offsets, i)) {
941 ulint len;
942 const byte* field
943 = rec_get_nth_field(rec, offsets, i, &len);
944
945 ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
946 if (!memcmp(field + len
947 - BTR_EXTERN_FIELD_REF_SIZE,
948 field_ref_zero,
949 BTR_EXTERN_FIELD_REF_SIZE)) {
950 return(field);
951 }
952 }
953 }
954
955 return(NULL);
956}
957
958/******************************************************//**
959Returns nonzero if the extern bit is set in nth field of rec.
960@return nonzero if externally stored */
961UNIV_INLINE
962ulint
963rec_offs_nth_extern_old(
964/*================*/
965 const rec_t* rec, /*!< in: record */
966 ulint n /*!< in: index of the field */)
967{
968 if(rec_get_1byte_offs_flag(rec))
969 return 0;
970 return (rec_2_get_field_end_info(rec,n) & REC_2BYTE_EXTERN_MASK);
971}
972
973/******************************************************//**
974Gets the physical size of a field.
975@return length of field */
976UNIV_INLINE
977ulint
978rec_offs_nth_size(
979/*==============*/
980 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
981 ulint n) /*!< in: nth field */
982{
983 ut_ad(rec_offs_validate(NULL, NULL, offsets));
984 ut_ad(n < rec_offs_n_fields(offsets));
985 if (!n) {
986 return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
987 }
988 return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
989 & REC_OFFS_MASK);
990}
991
992/******************************************************//**
993Returns the number of extern bits set in a record.
994@return number of externally stored fields */
995UNIV_INLINE
996ulint
997rec_offs_n_extern(
998/*==============*/
999 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1000{
1001 ulint n = 0;
1002
1003 if (rec_offs_any_extern(offsets)) {
1004 ulint i;
1005
1006 for (i = rec_offs_n_fields(offsets); i--; ) {
1007 if (rec_offs_nth_extern(offsets, i)) {
1008 n++;
1009 }
1010 }
1011 }
1012
1013 return(n);
1014}
1015
1016/******************************************************//**
1017Returns the offset of n - 1th field end if the record is stored in the 1-byte
1018offsets form. If the field is SQL null, the flag is ORed in the returned
1019value. This function and the 2-byte counterpart are defined here because the
1020C-compiler was not able to sum negative and positive constant offsets, and
1021warned of constant arithmetic overflow within the compiler.
1022@return offset of the start of the PREVIOUS field, SQL null flag ORed */
1023UNIV_INLINE
1024ulint
1025rec_1_get_prev_field_end_info(
1026/*==========================*/
1027 const rec_t* rec, /*!< in: record */
1028 ulint n) /*!< in: field index */
1029{
1030 ut_ad(rec_get_1byte_offs_flag(rec));
1031 ut_ad(n <= rec_get_n_fields_old(rec));
1032
1033 return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
1034}
1035
1036/******************************************************//**
1037Returns the offset of n - 1th field end if the record is stored in the 2-byte
1038offsets form. If the field is SQL null, the flag is ORed in the returned
1039value.
1040@return offset of the start of the PREVIOUS field, SQL null flag ORed */
1041UNIV_INLINE
1042ulint
1043rec_2_get_prev_field_end_info(
1044/*==========================*/
1045 const rec_t* rec, /*!< in: record */
1046 ulint n) /*!< in: field index */
1047{
1048 ut_ad(!rec_get_1byte_offs_flag(rec));
1049 ut_ad(n <= rec_get_n_fields_old(rec));
1050
1051 return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
1052}
1053
1054/******************************************************//**
1055Sets the field end info for the nth field if the record is stored in the
10561-byte format. */
1057UNIV_INLINE
1058void
1059rec_1_set_field_end_info(
1060/*=====================*/
1061 rec_t* rec, /*!< in: record */
1062 ulint n, /*!< in: field index */
1063 ulint info) /*!< in: value to set */
1064{
1065 ut_ad(rec_get_1byte_offs_flag(rec));
1066 ut_ad(n < rec_get_n_fields_old(rec));
1067
1068 mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
1069}
1070
1071/******************************************************//**
1072Sets the field end info for the nth field if the record is stored in the
10732-byte format. */
1074UNIV_INLINE
1075void
1076rec_2_set_field_end_info(
1077/*=====================*/
1078 rec_t* rec, /*!< in: record */
1079 ulint n, /*!< in: field index */
1080 ulint info) /*!< in: value to set */
1081{
1082 ut_ad(!rec_get_1byte_offs_flag(rec));
1083 ut_ad(n < rec_get_n_fields_old(rec));
1084
1085 mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
1086}
1087
1088/******************************************************//**
1089Returns the offset of nth field start if the record is stored in the 1-byte
1090offsets form.
1091@return offset of the start of the field */
1092UNIV_INLINE
1093ulint
1094rec_1_get_field_start_offs(
1095/*=======================*/
1096 const rec_t* rec, /*!< in: record */
1097 ulint n) /*!< in: field index */
1098{
1099 ut_ad(rec_get_1byte_offs_flag(rec));
1100 ut_ad(n <= rec_get_n_fields_old(rec));
1101
1102 if (n == 0) {
1103
1104 return(0);
1105 }
1106
1107 return(rec_1_get_prev_field_end_info(rec, n)
1108 & ~REC_1BYTE_SQL_NULL_MASK);
1109}
1110
1111/******************************************************//**
1112Returns the offset of nth field start if the record is stored in the 2-byte
1113offsets form.
1114@return offset of the start of the field */
1115UNIV_INLINE
1116ulint
1117rec_2_get_field_start_offs(
1118/*=======================*/
1119 const rec_t* rec, /*!< in: record */
1120 ulint n) /*!< in: field index */
1121{
1122 ut_ad(!rec_get_1byte_offs_flag(rec));
1123 ut_ad(n <= rec_get_n_fields_old(rec));
1124
1125 if (n == 0) {
1126
1127 return(0);
1128 }
1129
1130 return(rec_2_get_prev_field_end_info(rec, n)
1131 & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
1132}
1133
1134/******************************************************//**
1135The following function is used to read the offset of the start of a data field
1136in the record. The start of an SQL null field is the end offset of the
1137previous non-null field, or 0, if none exists. If n is the number of the last
1138field + 1, then the end offset of the last field is returned.
1139@return offset of the start of the field */
1140UNIV_INLINE
1141ulint
1142rec_get_field_start_offs(
1143/*=====================*/
1144 const rec_t* rec, /*!< in: record */
1145 ulint n) /*!< in: field index */
1146{
1147 ut_ad(rec);
1148 ut_ad(n <= rec_get_n_fields_old(rec));
1149
1150 if (n == 0) {
1151
1152 return(0);
1153 }
1154
1155 if (rec_get_1byte_offs_flag(rec)) {
1156
1157 return(rec_1_get_field_start_offs(rec, n));
1158 }
1159
1160 return(rec_2_get_field_start_offs(rec, n));
1161}
1162
1163/************************************************************//**
1164Gets the physical size of an old-style field.
1165Also an SQL null may have a field of size > 0,
1166if the data type is of a fixed size.
1167@return field size in bytes */
1168UNIV_INLINE
1169ulint
1170rec_get_nth_field_size(
1171/*===================*/
1172 const rec_t* rec, /*!< in: record */
1173 ulint n) /*!< in: index of the field */
1174{
1175 ulint os;
1176 ulint next_os;
1177
1178 os = rec_get_field_start_offs(rec, n);
1179 next_os = rec_get_field_start_offs(rec, n + 1);
1180
1181 ut_ad(next_os - os < srv_page_size);
1182
1183 return(next_os - os);
1184}
1185
1186/***********************************************************//**
1187This is used to modify the value of an already existing field in a record.
1188The previous value must have exactly the same size as the new value. If len
1189is UNIV_SQL_NULL then the field is treated as an SQL null.
1190For records in ROW_FORMAT=COMPACT (new-style records), len must not be
1191UNIV_SQL_NULL unless the field already is SQL null. */
1192UNIV_INLINE
1193void
1194rec_set_nth_field(
1195/*==============*/
1196 rec_t* rec, /*!< in: record */
1197 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1198 ulint n, /*!< in: index number of the field */
1199 const void* data, /*!< in: pointer to the data
1200 if not SQL null */
1201 ulint len) /*!< in: length of the data or UNIV_SQL_NULL */
1202{
1203 byte* data2;
1204 ulint len2;
1205
1206 ut_ad(rec);
1207 ut_ad(rec_offs_validate(rec, NULL, offsets));
1208 ut_ad(!rec_offs_nth_default(offsets, n));
1209
1210 if (len == UNIV_SQL_NULL) {
1211 if (!rec_offs_nth_sql_null(offsets, n)) {
1212 ut_a(!rec_offs_comp(offsets));
1213 rec_set_nth_field_sql_null(rec, n);
1214 }
1215
1216 return;
1217 }
1218
1219 data2 = (byte*)rec_get_nth_field(rec, offsets, n, &len2);
1220 if (len2 == UNIV_SQL_NULL) {
1221 ut_ad(!rec_offs_comp(offsets));
1222 rec_set_nth_field_null_bit(rec, n, FALSE);
1223 ut_ad(len == rec_get_nth_field_size(rec, n));
1224 } else {
1225 ut_ad(len2 == len);
1226 }
1227
1228 ut_memcpy(data2, data, len);
1229}
1230
1231/**********************************************************//**
1232The following function returns the data size of an old-style physical
1233record, that is the sum of field lengths. SQL null fields
1234are counted as length 0 fields. The value returned by the function
1235is the distance from record origin to record end in bytes.
1236@return size */
1237UNIV_INLINE
1238ulint
1239rec_get_data_size_old(
1240/*==================*/
1241 const rec_t* rec) /*!< in: physical record */
1242{
1243 ut_ad(rec);
1244
1245 return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
1246}
1247
1248/**********************************************************//**
1249The following function sets the number of fields in offsets. */
1250UNIV_INLINE
1251void
1252rec_offs_set_n_fields(
1253/*==================*/
1254 ulint* offsets, /*!< in/out: array returned by
1255 rec_get_offsets() */
1256 ulint n_fields) /*!< in: number of fields */
1257{
1258 ut_ad(offsets);
1259 ut_ad(n_fields > 0);
1260 ut_ad(n_fields <= REC_MAX_N_FIELDS);
1261 ut_ad(n_fields + REC_OFFS_HEADER_SIZE
1262 <= rec_offs_get_n_alloc(offsets));
1263 offsets[1] = n_fields;
1264}
1265
1266/**********************************************************//**
1267The following function returns the data size of a physical
1268record, that is the sum of field lengths. SQL null fields
1269are counted as length 0 fields. The value returned by the function
1270is the distance from record origin to record end in bytes.
1271@return size */
1272UNIV_INLINE
1273ulint
1274rec_offs_data_size(
1275/*===============*/
1276 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1277{
1278 ulint size;
1279
1280 ut_ad(rec_offs_validate(NULL, NULL, offsets));
1281 size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
1282 & REC_OFFS_MASK;
1283 ut_ad(size < srv_page_size);
1284 return(size);
1285}
1286
1287/**********************************************************//**
1288Returns the total size of record minus data size of record. The value
1289returned by the function is the distance from record start to record origin
1290in bytes.
1291@return size */
1292UNIV_INLINE
1293ulint
1294rec_offs_extra_size(
1295/*================*/
1296 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1297{
1298 ulint size;
1299 ut_ad(rec_offs_validate(NULL, NULL, offsets));
1300 size = *rec_offs_base(offsets) & REC_OFFS_MASK;
1301 ut_ad(size < srv_page_size);
1302 return(size);
1303}
1304
1305/**********************************************************//**
1306Returns the total size of a physical record.
1307@return size */
1308UNIV_INLINE
1309ulint
1310rec_offs_size(
1311/*==========*/
1312 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1313{
1314 return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
1315}
1316
1317#ifdef UNIV_DEBUG
1318/**********************************************************//**
1319Returns a pointer to the end of the record.
1320@return pointer to end */
1321UNIV_INLINE
1322byte*
1323rec_get_end(
1324/*========*/
1325 const rec_t* rec, /*!< in: pointer to record */
1326 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1327{
1328 ut_ad(rec_offs_validate(rec, NULL, offsets));
1329 return(const_cast<rec_t*>(rec + rec_offs_data_size(offsets)));
1330}
1331
1332/**********************************************************//**
1333Returns a pointer to the start of the record.
1334@return pointer to start */
1335UNIV_INLINE
1336byte*
1337rec_get_start(
1338/*==========*/
1339 const rec_t* rec, /*!< in: pointer to record */
1340 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1341{
1342 ut_ad(rec_offs_validate(rec, NULL, offsets));
1343 return(const_cast<rec_t*>(rec - rec_offs_extra_size(offsets)));
1344}
1345#endif /* UNIV_DEBUG */
1346
1347/** Copy a physical record to a buffer.
1348@param[in] buf buffer
1349@param[in] rec physical record
1350@param[in] offsets array returned by rec_get_offsets()
1351@return pointer to the origin of the copy */
1352UNIV_INLINE
1353rec_t*
1354rec_copy(
1355 void* buf,
1356 const rec_t* rec,
1357 const ulint* offsets)
1358{
1359 ulint extra_len;
1360 ulint data_len;
1361
1362 ut_ad(rec != NULL);
1363 ut_ad(buf != NULL);
1364 ut_ad(rec_offs_validate(rec, NULL, offsets));
1365 ut_ad(rec_validate(rec, offsets));
1366
1367 extra_len = rec_offs_extra_size(offsets);
1368 data_len = rec_offs_data_size(offsets);
1369
1370 ut_memcpy(buf, rec - extra_len, extra_len + data_len);
1371
1372 return((byte*) buf + extra_len);
1373}
1374
1375/**********************************************************//**
1376Returns the extra size of an old-style physical record if we know its
1377data size and number of fields.
1378@return extra size */
1379UNIV_INLINE
1380ulint
1381rec_get_converted_extra_size(
1382/*=========================*/
1383 ulint data_size, /*!< in: data size */
1384 ulint n_fields, /*!< in: number of fields */
1385 ulint n_ext) /*!< in: number of externally stored columns */
1386{
1387 if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1388
1389 return(REC_N_OLD_EXTRA_BYTES + n_fields);
1390 }
1391
1392 return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
1393}
1394
1395/**********************************************************//**
1396The following function returns the size of a data tuple when converted to
1397a physical record.
1398@return size */
1399UNIV_INLINE
1400ulint
1401rec_get_converted_size(
1402/*===================*/
1403 dict_index_t* index, /*!< in: record descriptor */
1404 const dtuple_t* dtuple, /*!< in: data tuple */
1405 ulint n_ext) /*!< in: number of externally stored columns */
1406{
1407 ulint data_size;
1408 ulint extra_size;
1409
1410 ut_ad(index);
1411 ut_ad(dtuple);
1412 ut_ad(dtuple_check_typed(dtuple));
1413#ifdef UNIV_DEBUG
1414 if (dict_index_is_ibuf(index)) {
1415 ut_ad(dtuple->n_fields > 1);
1416 } else if ((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
1417 == REC_STATUS_NODE_PTR) {
1418 ut_ad(dtuple->n_fields
1419 == dict_index_get_n_unique_in_tree_nonleaf(index) + 1);
1420 } else if (index->table->id == DICT_INDEXES_ID) {
1421 /* The column SYS_INDEXES.MERGE_THRESHOLD was
1422 instantly added in MariaDB 10.2.2 (MySQL 5.7). */
1423 ut_ad(index->n_fields == DICT_NUM_FIELDS__SYS_INDEXES);
1424 ut_ad(dtuple->n_fields == DICT_NUM_FIELDS__SYS_INDEXES
1425 || dtuple->n_fields
1426 == DICT_FLD__SYS_INDEXES__MERGE_THRESHOLD);
1427 } else {
1428 ut_ad(dtuple->n_fields >= index->n_core_fields);
1429 ut_ad(dtuple->n_fields <= index->n_fields);
1430 }
1431#endif
1432
1433 if (dict_table_is_comp(index->table)) {
1434 return(rec_get_converted_size_comp(
1435 index,
1436 static_cast<rec_comp_status_t>(
1437 dtuple->info_bits
1438 & REC_NEW_STATUS_MASK),
1439 dtuple->fields,
1440 dtuple->n_fields, NULL));
1441 }
1442
1443 data_size = dtuple_get_data_size(dtuple, 0);
1444
1445 extra_size = rec_get_converted_extra_size(
1446 data_size, dtuple_get_n_fields(dtuple), n_ext);
1447
1448 return(data_size + extra_size);
1449}
1450