mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / include / rem0rec.ic
blob566c62e30f256685ed88725985f25a01d7d21ad3
1 /************************************************************************
2 Record manager
4 (c) 1994-1996 Innobase Oy
6 Created 5/30/1994 Heikki Tuuri
7 *************************************************************************/
9 #include "mach0data.h"
10 #include "ut0byte.h"
11 #include "dict0dict.h"
12 #include "btr0types.h"
14 /* Compact flag ORed to the extra size returned by rec_get_offsets() */
15 #define REC_OFFS_COMPACT        ((ulint) 1 << 31)
16 /* SQL NULL flag in offsets returned by rec_get_offsets() */
17 #define REC_OFFS_SQL_NULL       ((ulint) 1 << 31)
18 /* External flag in offsets returned by rec_get_offsets() */
19 #define REC_OFFS_EXTERNAL       ((ulint) 1 << 30)
20 /* Mask for offsets returned by rec_get_offsets() */
21 #define REC_OFFS_MASK           (REC_OFFS_EXTERNAL - 1)
23 /* Offsets of the bit-fields in an old-style record. NOTE! In the table the
24 most significant bytes and bits are written below less significant.
26         (1) byte offset         (2) bit usage within byte
27         downward from
28         origin ->       1       8 bits pointer to next record
29                         2       8 bits pointer to next record
30                         3       1 bit short flag
31                                 7 bits number of fields
32                         4       3 bits number of fields
33                                 5 bits heap number
34                         5       8 bits heap number
35                         6       4 bits n_owned
36                                 4 bits info bits
39 /* Offsets of the bit-fields in a new-style record. NOTE! In the table the
40 most significant bytes and bits are written below less significant.
42         (1) byte offset         (2) bit usage within byte
43         downward from
44         origin ->       1       8 bits relative offset of next record
45                         2       8 bits relative offset of next record
46                                   the relative offset is an unsigned 16-bit
47                                   integer:
48                                   (offset_of_next_record
49                                    - offset_of_this_record) mod 64Ki,
50                                   where mod is the modulo as a non-negative
51                                   number;
52                                   we can calculate the the offset of the next
53                                   record with the formula:
54                                   relative_offset + offset_of_this_record
55                                   mod UNIV_PAGE_SIZE
56                         3       3 bits status:
57                                         000=conventional record
58                                         001=node pointer record (inside B-tree)
59                                         010=infimum record
60                                         011=supremum record
61                                         1xx=reserved
62                                 5 bits heap number
63                         4       8 bits heap number
64                         5       4 bits n_owned
65                                 4 bits info bits
68 /* We list the byte offsets from the origin of the record, the mask,
69 and the shift needed to obtain each bit-field of the record. */
71 #define REC_NEXT                2
72 #define REC_NEXT_MASK           0xFFFFUL
73 #define REC_NEXT_SHIFT          0
75 #define REC_OLD_SHORT           3       /* This is single byte bit-field */
76 #define REC_OLD_SHORT_MASK      0x1UL
77 #define REC_OLD_SHORT_SHIFT     0
79 #define REC_OLD_N_FIELDS        4
80 #define REC_OLD_N_FIELDS_MASK   0x7FEUL
81 #define REC_OLD_N_FIELDS_SHIFT  1
83 #define REC_NEW_STATUS          3       /* This is single byte bit-field */
84 #define REC_NEW_STATUS_MASK     0x7UL
85 #define REC_NEW_STATUS_SHIFT    0
87 #define REC_OLD_HEAP_NO         5
88 #define REC_NEW_HEAP_NO         4
89 #define REC_HEAP_NO_MASK        0xFFF8UL
90 #define REC_HEAP_NO_SHIFT       3
92 #define REC_OLD_N_OWNED         6       /* This is single byte bit-field */
93 #define REC_NEW_N_OWNED         5       /* This is single byte bit-field */
94 #define REC_N_OWNED_MASK        0xFUL
95 #define REC_N_OWNED_SHIFT       0
97 #define REC_OLD_INFO_BITS       6       /* This is single byte bit-field */
98 #define REC_NEW_INFO_BITS       5       /* This is single byte bit-field */
99 #define REC_INFO_BITS_MASK      0xF0UL
100 #define REC_INFO_BITS_SHIFT     0
102 /* The following masks are used to filter the SQL null bit from
103 one-byte and two-byte offsets */
105 #define REC_1BYTE_SQL_NULL_MASK 0x80UL
106 #define REC_2BYTE_SQL_NULL_MASK 0x8000UL
108 /* In a 2-byte offset the second most significant bit denotes
109 a field stored to another page: */
111 #define REC_2BYTE_EXTERN_MASK   0x4000UL
113 #if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
114                 ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
115                 ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
116                 ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
117                 ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
118                 ^ 0xFFFFFFFFUL
119 # error "sum of old-style masks != 0xFFFFFFFFUL"
120 #endif
121 #if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
122                 ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
123                 ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
124                 ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
125                 ^ 0xFFFFFFUL
126 # error "sum of new-style masks != 0xFFFFFFUL"
127 #endif
129 /***************************************************************
130 Sets the value of the ith field SQL null bit of an old-style record. */
132 void
133 rec_set_nth_field_null_bit(
134 /*=======================*/
135         rec_t*  rec,    /* in: record */
136         ulint   i,      /* in: ith field */
137         ibool   val);   /* in: value to set */
138 /***************************************************************
139 Sets an old-style record field to SQL null.
140 The physical size of the field is not changed. */
142 void
143 rec_set_nth_field_sql_null(
144 /*=======================*/
145         rec_t*  rec,    /* in: record */
146         ulint   n);     /* in: index of the field */
148 /***************************************************************
149 Sets the value of the ith field extern storage bit of an old-style record. */
151 void
152 rec_set_nth_field_extern_bit_old(
153 /*=============================*/
154         rec_t*  rec,    /* in: old-style record */
155         ulint   i,      /* in: ith field */
156         ibool   val,    /* in: value to set */
157         mtr_t*  mtr);   /* in: mtr holding an X-latch to the page where
158                         rec is, or NULL; in the NULL case we do not
159                         write to log about the change */
160 /***************************************************************
161 Sets the value of the ith field extern storage bit of a new-style record. */
163 void
164 rec_set_nth_field_extern_bit_new(
165 /*=============================*/
166         rec_t*          rec,    /* in: record */
167         dict_index_t*   index,  /* in: record descriptor */
168         ulint           ith,    /* in: ith field */
169         ibool           val,    /* in: value to set */
170         mtr_t*          mtr);   /* in: mtr holding an X-latch to the page
171                                 where rec is, or NULL; in the NULL case
172                                 we do not write to log about the change */
174 /**********************************************************
175 Gets a bit field from within 1 byte. */
176 UNIV_INLINE
177 ulint
178 rec_get_bit_field_1(
179 /*================*/
180         rec_t*  rec,    /* in: pointer to record origin */
181         ulint   offs,   /* in: offset from the origin down */
182         ulint   mask,   /* in: mask used to filter bits */
183         ulint   shift)  /* in: shift right applied after masking */
185         ut_ad(rec);
187         return((mach_read_from_1(rec - offs) & mask) >> shift);
190 /**********************************************************
191 Sets a bit field within 1 byte. */
192 UNIV_INLINE
193 void
194 rec_set_bit_field_1(
195 /*================*/
196         rec_t*  rec,    /* in: pointer to record origin */
197         ulint   val,    /* in: value to set */
198         ulint   offs,   /* in: offset from the origin down */
199         ulint   mask,   /* in: mask used to filter bits */
200         ulint   shift)  /* in: shift right applied after masking */
202         ut_ad(rec);
203         ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
204         ut_ad(mask);
205         ut_ad(mask <= 0xFFUL);
206         ut_ad(((mask >> shift) << shift) == mask);
207         ut_ad(((val << shift) & mask) == (val << shift));
209         mach_write_to_1(rec - offs,
210                         (mach_read_from_1(rec - offs) & ~mask)
211                         | (val << shift));
214 /**********************************************************
215 Gets a bit field from within 2 bytes. */
216 UNIV_INLINE
217 ulint
218 rec_get_bit_field_2(
219 /*================*/
220         rec_t*  rec,    /* in: pointer to record origin */
221         ulint   offs,   /* in: offset from the origin down */
222         ulint   mask,   /* in: mask used to filter bits */
223         ulint   shift)  /* in: shift right applied after masking */
225         ut_ad(rec);
227         return((mach_read_from_2(rec - offs) & mask) >> shift);
230 /**********************************************************
231 Sets a bit field within 2 bytes. */
232 UNIV_INLINE
233 void
234 rec_set_bit_field_2(
235 /*================*/
236         rec_t*  rec,    /* in: pointer to record origin */
237         ulint   val,    /* in: value to set */
238         ulint   offs,   /* in: offset from the origin down */
239         ulint   mask,   /* in: mask used to filter bits */
240         ulint   shift)  /* in: shift right applied after masking */
242         ut_ad(rec);
243         ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
244         ut_ad(mask > 0xFFUL);
245         ut_ad(mask <= 0xFFFFUL);
246         ut_ad((mask >> shift) & 1);
247         ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
248         ut_ad(((mask >> shift) << shift) == mask);
249         ut_ad(((val << shift) & mask) == (val << shift));
251         mach_write_to_2(rec - offs,
252                         (mach_read_from_2(rec - offs) & ~mask)
253                         | (val << shift));
256 /**********************************************************
257 The following function is used to get the offset of the next chained record
258 on the same page. */
259 UNIV_INLINE
260 ulint
261 rec_get_next_offs(
262 /*==============*/
263                         /* out: the page offset of the next chained record, or
264                         0 if none */
265         rec_t*  rec,    /* in: physical record */
266         ulint   comp)   /* in: nonzero=compact page format */
268         ulint   field_value;
269 #if REC_NEXT_MASK != 0xFFFFUL
270 # error "REC_NEXT_MASK != 0xFFFFUL"
271 #endif
272 #if REC_NEXT_SHIFT
273 # error "REC_NEXT_SHIFT != 0"
274 #endif
276         field_value = mach_read_from_2(rec - REC_NEXT);
278         if (comp) {
279 #if UNIV_PAGE_SIZE <= 32768
280                 /* Note that for 64 KiB pages, field_value can 'wrap around'
281                 and the debug assertion is not valid */
283                 /* In the following assertion, field_value is interpreted
284                 as signed 16-bit integer in 2's complement arithmetics.
285                 If all platforms defined int16_t in the standard headers,
286                 the expression could be written simpler as
287                 (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
288                 */
289                 ut_ad((field_value >= 32768
290                        ? field_value - 65536
291                        : field_value)
292                       + ut_align_offset(rec, UNIV_PAGE_SIZE)
293                       < UNIV_PAGE_SIZE);
294 #endif
295                 if (field_value == 0) {
297                         return(0);
298                 }
300                 return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
301         } else {
302                 ut_ad(field_value < UNIV_PAGE_SIZE);
304                 return(field_value);
305         }
308 /**********************************************************
309 The following function is used to set the next record offset field of the
310 record. */
311 UNIV_INLINE
312 void
313 rec_set_next_offs(
314 /*==============*/
315         rec_t*  rec,    /* in: physical record */
316         ulint   comp,   /* in: nonzero=compact page format */
317         ulint   next)   /* in: offset of the next record, or 0 if none */
319         ut_ad(rec);
320         ut_ad(UNIV_PAGE_SIZE > next);
321 #if REC_NEXT_MASK != 0xFFFFUL
322 # error "REC_NEXT_MASK != 0xFFFFUL"
323 #endif
324 #if REC_NEXT_SHIFT
325 # error "REC_NEXT_SHIFT != 0"
326 #endif
328         if (comp) {
329                 ulint field_value;
331                 if (next) {
332                         /* The following two statements calculate
333                         next - offset_of_rec mod 64Ki, where mod is the modulo
334                         as a non-negative number */
336                         field_value = (ulint)((lint)next
337                                               - (lint)ut_align_offset(
338                                                       rec, UNIV_PAGE_SIZE));
339                         field_value &= REC_NEXT_MASK;
340                 } else {
341                         field_value = 0;
342                 }
344                 mach_write_to_2(rec - REC_NEXT, field_value);
345         } else {
346                 mach_write_to_2(rec - REC_NEXT, next);
347         }
350 /**********************************************************
351 The following function is used to get the number of fields
352 in an old-style record. */
353 UNIV_INLINE
354 ulint
355 rec_get_n_fields_old(
356 /*=================*/
357                         /* out: number of data fields */
358         rec_t*  rec)    /* in: physical record */
360         ulint   ret;
362         ut_ad(rec);
364         ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
365                                   REC_OLD_N_FIELDS_MASK,
366                                   REC_OLD_N_FIELDS_SHIFT);
367         ut_ad(ret <= REC_MAX_N_FIELDS);
368         ut_ad(ret > 0);
370         return(ret);
373 /**********************************************************
374 The following function is used to set the number of fields
375 in an old-style record. */
376 UNIV_INLINE
377 void
378 rec_set_n_fields_old(
379 /*=================*/
380         rec_t*  rec,            /* in: physical record */
381         ulint   n_fields)       /* in: the number of fields */
383         ut_ad(rec);
384         ut_ad(n_fields <= REC_MAX_N_FIELDS);
385         ut_ad(n_fields > 0);
387         rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
388                             REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
391 /**********************************************************
392 The following function retrieves the status bits of a new-style record. */
393 UNIV_INLINE
394 ulint
395 rec_get_status(
396 /*===========*/
397                         /* out: status bits */
398         rec_t*  rec)    /* in: physical record */
400         ulint   ret;
402         ut_ad(rec);
404         ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
405                                   REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
406         ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
408         return(ret);
411 /**********************************************************
412 The following function is used to get the number of fields
413 in a record. */
414 UNIV_INLINE
415 ulint
416 rec_get_n_fields(
417 /*=============*/
418                                 /* out: number of data fields */
419         rec_t*          rec,    /* in: physical record */
420         dict_index_t*   index)  /* in: record descriptor */
422         ut_ad(rec);
423         ut_ad(index);
425         if (!dict_table_is_comp(index->table)) {
426                 return(rec_get_n_fields_old(rec));
427         }
429         switch (rec_get_status(rec)) {
430         case REC_STATUS_ORDINARY:
431                 return(dict_index_get_n_fields(index));
432         case REC_STATUS_NODE_PTR:
433                 return(dict_index_get_n_unique_in_tree(index) + 1);
434         case REC_STATUS_INFIMUM:
435         case REC_STATUS_SUPREMUM:
436                 return(1);
437         default:
438                 ut_error;
439                 return(ULINT_UNDEFINED);
440         }
443 /**********************************************************
444 The following function is used to get the number of records owned by the
445 previous directory record. */
446 UNIV_INLINE
447 ulint
448 rec_get_n_owned(
449 /*============*/
450                         /* out: number of owned records */
451         rec_t*  rec,    /* in: physical record */
452         ulint   comp)   /* in: nonzero=compact page format */
454         ulint   ret;
456         ut_ad(rec);
458         ret = rec_get_bit_field_1(rec,
459                                   comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
460                                   REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
461         ut_ad(ret <= REC_MAX_N_OWNED);
463         return(ret);
466 /**********************************************************
467 The following function is used to set the number of owned records. */
468 UNIV_INLINE
469 void
470 rec_set_n_owned(
471 /*============*/
472         rec_t*  rec,            /* in: physical record */
473         ulint   comp,           /* in: nonzero=compact page format */
474         ulint   n_owned)        /* in: the number of owned */
476         ut_ad(rec);
477         ut_ad(n_owned <= REC_MAX_N_OWNED);
479         rec_set_bit_field_1(rec, n_owned,
480                             comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
481                             REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
484 /**********************************************************
485 The following function is used to retrieve the info bits of a record. */
486 UNIV_INLINE
487 ulint
488 rec_get_info_bits(
489 /*==============*/
490                         /* out: info bits */
491         rec_t*  rec,    /* in: physical record */
492         ulint   comp)   /* in: nonzero=compact page format */
494         ulint   ret;
496         ut_ad(rec);
498         ret = rec_get_bit_field_1(rec,
499                                   comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
500                                   REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
501         ut_ad((ret & ~REC_INFO_BITS_MASK) == 0);
503         return(ret);
506 /**********************************************************
507 The following function is used to set the info bits of a record. */
508 UNIV_INLINE
509 void
510 rec_set_info_bits(
511 /*==============*/
512         rec_t*  rec,    /* in: physical record */
513         ulint   comp,   /* in: nonzero=compact page format */
514         ulint   bits)   /* in: info bits */
516         ut_ad(rec);
517         ut_ad((bits & ~REC_INFO_BITS_MASK) == 0);
519         rec_set_bit_field_1(rec, bits,
520                             comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
521                             REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
524 /**********************************************************
525 The following function is used to set the status bits of a new-style record. */
526 UNIV_INLINE
527 void
528 rec_set_status(
529 /*===========*/
530         rec_t*  rec,    /* in: physical record */
531         ulint   bits)   /* in: info bits */
533         ut_ad(rec);
534         ut_ad((bits & ~REC_NEW_STATUS_MASK) == 0);
536         rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
537                             REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
540 /**********************************************************
541 The following function is used to retrieve the info and status
542 bits of a record.  (Only compact records have status bits.) */
543 UNIV_INLINE
544 ulint
545 rec_get_info_and_status_bits(
546 /*=========================*/
547                         /* out: info bits */
548         rec_t*  rec,    /* in: physical record */
549         ulint   comp)   /* in: nonzero=compact page format */
551         ulint   bits;
552 #if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
553 & (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
554 # error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
555 #endif
556         if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
557                 bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
558         } else {
559                 bits = rec_get_info_bits(rec, FALSE);
560                 ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
561         }
562         return(bits);
564 /**********************************************************
565 The following function is used to set the info and status
566 bits of a record.  (Only compact records have status bits.) */
567 UNIV_INLINE
568 void
569 rec_set_info_and_status_bits(
570 /*=========================*/
571         rec_t*  rec,    /* in: physical record */
572         ulint   comp,   /* in: nonzero=compact page format */
573         ulint   bits)   /* in: info bits */
575 #if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
576 & (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
577 # error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
578 #endif
579         if (comp) {
580                 rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
581         } else {
582                 ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
583         }
584         rec_set_info_bits(rec, comp, bits & ~REC_NEW_STATUS_MASK);
587 /**********************************************************
588 The following function tells if record is delete marked. */
589 UNIV_INLINE
590 ulint
591 rec_get_deleted_flag(
592 /*=================*/
593                         /* out: nonzero if delete marked */
594         rec_t*  rec,    /* in: physical record */
595         ulint   comp)   /* in: nonzero=compact page format */
597         if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
598                 return(UNIV_UNLIKELY(
599                                rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
600                                                    REC_INFO_DELETED_FLAG,
601                                                    REC_INFO_BITS_SHIFT)));
602         } else {
603                 return(UNIV_UNLIKELY(
604                                rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
605                                                    REC_INFO_DELETED_FLAG,
606                                                    REC_INFO_BITS_SHIFT)));
607         }
610 /**********************************************************
611 The following function is used to set the deleted bit. */
612 UNIV_INLINE
613 void
614 rec_set_deleted_flag(
615 /*=================*/
616         rec_t*  rec,    /* in: physical record */
617         ulint   comp,   /* in: nonzero=compact page format */
618         ulint   flag)   /* in: nonzero if delete marked */
620         ulint   val;
622         val = rec_get_info_bits(rec, comp);
624         if (flag) {
625                 val |= REC_INFO_DELETED_FLAG;
626         } else {
627                 val &= ~REC_INFO_DELETED_FLAG;
628         }
630         rec_set_info_bits(rec, comp, val);
633 /**********************************************************
634 The following function tells if a new-style record is a node pointer. */
635 UNIV_INLINE
636 ibool
637 rec_get_node_ptr_flag(
638 /*==================*/
639                         /* out: TRUE if node pointer */
640         rec_t*  rec)    /* in: physical record */
642         return(REC_STATUS_NODE_PTR == rec_get_status(rec));
645 /**********************************************************
646 The following function is used to get the order number of the record in the
647 heap of the index page. */
648 UNIV_INLINE
649 ulint
650 rec_get_heap_no(
651 /*============*/
652                         /* out: heap order number */
653         rec_t*  rec,    /* in: physical record */
654         ulint   comp)   /* in: nonzero=compact page format */
656         ulint   ret;
658         ut_ad(rec);
660         ret = rec_get_bit_field_2(rec,
661                                   comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
662                                   REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
663         ut_ad(ret <= REC_MAX_HEAP_NO);
665         return(ret);
668 /**********************************************************
669 The following function is used to set the heap number field in the record. */
670 UNIV_INLINE
671 void
672 rec_set_heap_no(
673 /*============*/
674         rec_t*  rec,    /* in: physical record */
675         ulint   comp,   /* in: nonzero=compact page format */
676         ulint   heap_no)/* in: the heap number */
678         ut_ad(heap_no <= REC_MAX_HEAP_NO);
680         rec_set_bit_field_2(rec, heap_no,
681                             comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
682                             REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
685 /**********************************************************
686 The following function is used to test whether the data offsets in the record
687 are stored in one-byte or two-byte format. */
688 UNIV_INLINE
689 ibool
690 rec_get_1byte_offs_flag(
691 /*====================*/
692                         /* out: TRUE if 1-byte form */
693         rec_t*  rec)    /* in: physical record */
695 #if TRUE != 1
696 #error "TRUE != 1"
697 #endif
699         return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
700                                    REC_OLD_SHORT_SHIFT));
703 /**********************************************************
704 The following function is used to set the 1-byte offsets flag. */
705 UNIV_INLINE
706 void
707 rec_set_1byte_offs_flag(
708 /*====================*/
709         rec_t*  rec,    /* in: physical record */
710         ibool   flag)   /* in: TRUE if 1byte form */
712 #if TRUE != 1
713 #error "TRUE != 1"
714 #endif
715         ut_ad(flag <= TRUE);
717         rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
718                             REC_OLD_SHORT_SHIFT);
721 /**********************************************************
722 Returns the offset of nth field end if the record is stored in the 1-byte
723 offsets form. If the field is SQL null, the flag is ORed in the returned
724 value. */
725 UNIV_INLINE
726 ulint
727 rec_1_get_field_end_info(
728 /*=====================*/
729                         /* out: offset of the start of the field, SQL null
730                         flag ORed */
731         rec_t*  rec,    /* in: record */
732         ulint   n)      /* in: field index */
734         ut_ad(rec_get_1byte_offs_flag(rec));
735         ut_ad(n < rec_get_n_fields_old(rec));
737         return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
740 /**********************************************************
741 Returns the offset of nth field end if the record is stored in the 2-byte
742 offsets form. If the field is SQL null, the flag is ORed in the returned
743 value. */
744 UNIV_INLINE
745 ulint
746 rec_2_get_field_end_info(
747 /*=====================*/
748                         /* out: offset of the start of the field, SQL null
749                         flag and extern storage flag ORed */
750         rec_t*  rec,    /* in: record */
751         ulint   n)      /* in: field index */
753         ut_ad(!rec_get_1byte_offs_flag(rec));
754         ut_ad(n < rec_get_n_fields_old(rec));
756         return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
759 #ifdef UNIV_DEBUG
760 /* Length of the rec_get_offsets() header */
761 # define REC_OFFS_HEADER_SIZE   4
762 #else /* UNIV_DEBUG */
763 /* Length of the rec_get_offsets() header */
764 # define REC_OFFS_HEADER_SIZE   2
765 #endif /* UNIV_DEBUG */
767 /* Get the base address of offsets.  The extra_size is stored at
768 this position, and following positions hold the end offsets of
769 the fields. */
770 #define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
772 /**************************************************************
773 The following function returns the number of allocated elements
774 for an array of offsets. */
775 UNIV_INLINE
776 ulint
777 rec_offs_get_n_alloc(
778 /*=================*/
779                                 /* out: number of elements */
780         const ulint*    offsets)/* in: array for rec_get_offsets() */
782         ulint   n_alloc;
783         ut_ad(offsets);
784         n_alloc = offsets[0];
785         ut_ad(n_alloc > 0);
786         return(n_alloc);
789 /**************************************************************
790 The following function sets the number of allocated elements
791 for an array of offsets. */
792 UNIV_INLINE
793 void
794 rec_offs_set_n_alloc(
795 /*=================*/
796         ulint*  offsets,        /* out: array for rec_get_offsets(),
797                                 must be allocated */
798         ulint   n_alloc)        /* in: number of elements */
800         ut_ad(offsets);
801         ut_ad(n_alloc > 0);
802         UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
803         offsets[0] = n_alloc;
806 /**************************************************************
807 The following function returns the number of fields in a record. */
808 UNIV_INLINE
809 ulint
810 rec_offs_n_fields(
811 /*==============*/
812                                 /* out: number of fields */
813         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
815         ulint   n_fields;
816         ut_ad(offsets);
817         n_fields = offsets[1];
818         ut_ad(n_fields > 0);
819         ut_ad(n_fields <= REC_MAX_N_FIELDS);
820         ut_ad(n_fields + REC_OFFS_HEADER_SIZE
821               <= rec_offs_get_n_alloc(offsets));
822         return(n_fields);
825 /****************************************************************
826 Validates offsets returned by rec_get_offsets(). */
827 UNIV_INLINE
828 ibool
829 rec_offs_validate(
830 /*==============*/
831                                 /* out: TRUE if valid */
832         rec_t*          rec,    /* in: record or NULL */
833         dict_index_t*   index,  /* in: record descriptor or NULL */
834         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
836         ulint   i       = rec_offs_n_fields(offsets);
837         ulint   last    = ULINT_MAX;
838         ulint   comp    = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
840         if (rec) {
841                 ut_ad((ulint) rec == offsets[2]);
842                 if (!comp) {
843                         ut_a(rec_get_n_fields_old(rec) >= i);
844                 }
845         }
846         if (index) {
847                 ulint max_n_fields;
848                 ut_ad((ulint) index == offsets[3]);
849                 max_n_fields = ut_max(
850                         dict_index_get_n_fields(index),
851                         dict_index_get_n_unique_in_tree(index) + 1);
852                 if (comp && rec) {
853                         switch (rec_get_status(rec)) {
854                         case REC_STATUS_ORDINARY:
855                                 break;
856                         case REC_STATUS_NODE_PTR:
857                                 max_n_fields = dict_index_get_n_unique_in_tree(
858                                         index) + 1;
859                                 break;
860                         case REC_STATUS_INFIMUM:
861                         case REC_STATUS_SUPREMUM:
862                                 max_n_fields = 1;
863                                 break;
864                         default:
865                                 ut_error;
866                         }
867                 }
868                 /* index->n_def == 0 for dummy indexes if !comp */
869                 ut_a(!comp || index->n_def);
870                 ut_a(!index->n_def || i <= max_n_fields);
871         }
872         while (i--) {
873                 ulint   curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
874                 ut_a(curr <= last);
875                 last = curr;
876         }
877         return(TRUE);
879 /****************************************************************
880 Updates debug data in offsets, in order to avoid bogus
881 rec_offs_validate() failures. */
882 UNIV_INLINE
883 void
884 rec_offs_make_valid(
885 /*================*/
886         rec_t*          rec __attribute__((unused)),
887                                 /* in: record */
888         dict_index_t*   index __attribute__((unused)),
889                                 /* in: record descriptor */
890         ulint*          offsets __attribute__((unused)))
891                                 /* in: array returned by rec_get_offsets() */
893 #ifdef UNIV_DEBUG
894         ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
895         offsets[2] = (ulint) rec;
896         offsets[3] = (ulint) index;
897 #endif /* UNIV_DEBUG */
900 /****************************************************************
901 The following function is used to get a pointer to the nth
902 data field in a record. */
903 UNIV_INLINE
904 byte*
905 rec_get_nth_field(
906 /*==============*/
907                                 /* out: pointer to the field */
908         rec_t*          rec,    /* in: record */
909         const ulint*    offsets,/* in: array returned by rec_get_offsets() */
910         ulint           n,      /* in: index of the field */
911         ulint*          len)    /* out: length of the field; UNIV_SQL_NULL
912                                 if SQL null */
914         byte*   field;
915         ulint   length;
916         ut_ad(rec);
917         ut_ad(rec_offs_validate(rec, NULL, offsets));
918         ut_ad(n < rec_offs_n_fields(offsets));
919         ut_ad(len);
921         if (UNIV_UNLIKELY(n == 0)) {
922                 field = rec;
923         } else {
924                 field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
925         }
927         length = rec_offs_base(offsets)[1 + n];
929         if (length & REC_OFFS_SQL_NULL) {
930                 length = UNIV_SQL_NULL;
931         } else {
932                 length &= REC_OFFS_MASK;
933                 length -= field - rec;
934         }
936         *len = length;
937         return(field);
940 /**********************************************************
941 Determine if the offsets are for a record in the new
942 compact format. */
943 UNIV_INLINE
944 ulint
945 rec_offs_comp(
946 /*==========*/
947                                 /* out: nonzero if compact format */
948         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
950         ut_ad(rec_offs_validate(NULL, NULL, offsets));
951         return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
954 /**********************************************************
955 Returns nonzero if the extern bit is set in nth field of rec. */
956 UNIV_INLINE
957 ulint
958 rec_offs_nth_extern(
959 /*================*/
960                                 /* out: nonzero if externally stored */
961         const ulint*    offsets,/* in: array returned by rec_get_offsets() */
962         ulint           n)      /* in: nth field */
964         ut_ad(rec_offs_validate(NULL, NULL, offsets));
965         ut_ad(n < rec_offs_n_fields(offsets));
966         return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
967                              & REC_OFFS_EXTERNAL));
970 /**********************************************************
971 Returns nonzero if the SQL NULL bit is set in nth field of rec. */
972 UNIV_INLINE
973 ulint
974 rec_offs_nth_sql_null(
975 /*==================*/
976                                 /* out: nonzero if SQL NULL */
977         const ulint*    offsets,/* in: array returned by rec_get_offsets() */
978         ulint           n)      /* in: nth field */
980         ut_ad(rec_offs_validate(NULL, NULL, offsets));
981         ut_ad(n < rec_offs_n_fields(offsets));
982         return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
983                              & REC_OFFS_SQL_NULL));
986 /**********************************************************
987 Gets the physical size of a field. */
988 UNIV_INLINE
989 ulint
990 rec_offs_nth_size(
991 /*==============*/
992                                 /* out: length of field */
993         const ulint*    offsets,/* in: array returned by rec_get_offsets() */
994         ulint           n)      /* in: nth field */
996         ut_ad(rec_offs_validate(NULL, NULL, offsets));
997         ut_ad(n < rec_offs_n_fields(offsets));
998         if (!n) {
999                 return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
1000         }
1001         return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
1002                & REC_OFFS_MASK);
1005 /**********************************************************
1006 Returns TRUE if the extern bit is set in any of the fields
1007 of an old-style record. */
1008 UNIV_INLINE
1009 ibool
1010 rec_offs_any_extern(
1011 /*================*/
1012                                 /* out: TRUE if a field is stored externally */
1013         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1015         ulint   i;
1016         for (i = rec_offs_n_fields(offsets); i--; ) {
1017                 if (rec_offs_nth_extern(offsets, i)) {
1018                         return(TRUE);
1019                 }
1020         }
1021         return(FALSE);
1024 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
1025 /********************************************************
1026 Determine if the offsets are for a record containing null BLOB pointers. */
1027 UNIV_INLINE
1028 const byte*
1029 rec_offs_any_null_extern(
1030 /*=====================*/
1031                                         /* out: first field containing
1032                                         a null BLOB pointer,
1033                                         or NULL if none found */
1034         rec_t*          rec,            /*!< in: record */
1035         const ulint*    offsets)        /*!< in: rec_get_offsets(rec) */
1037         ulint   i;
1038         ut_ad(rec_offs_validate(rec, NULL, offsets));
1040         for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1041                 if (rec_offs_nth_extern(offsets, i)) {
1042                         ulint           len;
1043                         const byte*     field
1044                                 = rec_get_nth_field(rec, offsets, i, &len);
1046                         ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
1047                         if (!memcmp(field + len
1048                                     - BTR_EXTERN_FIELD_REF_SIZE,
1049                                     field_ref_zero,
1050                                     BTR_EXTERN_FIELD_REF_SIZE)) {
1051                                 return(field);
1052                         }
1053                 }
1054         }
1056         return(NULL);
1058 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
1060 /***************************************************************
1061 Sets the value of the ith field extern storage bit. */
1062 UNIV_INLINE
1063 void
1064 rec_set_nth_field_extern_bit(
1065 /*=========================*/
1066         rec_t*          rec,    /* in: record */
1067         dict_index_t*   index,  /* in: record descriptor */
1068         ulint           i,      /* in: ith field */
1069         ibool           val,    /* in: value to set */
1070         mtr_t*          mtr)    /* in: mtr holding an X-latch to the page
1071                                 where rec is, or NULL; in the NULL case
1072                                 we do not write to log about the change */
1074         if (dict_table_is_comp(index->table)) {
1075                 rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
1076         } else {
1077                 rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
1078         }
1081 /**********************************************************
1082 Returns the offset of n - 1th field end if the record is stored in the 1-byte
1083 offsets form. If the field is SQL null, the flag is ORed in the returned
1084 value. This function and the 2-byte counterpart are defined here because the
1085 C-compiler was not able to sum negative and positive constant offsets, and
1086 warned of constant arithmetic overflow within the compiler. */
1087 UNIV_INLINE
1088 ulint
1089 rec_1_get_prev_field_end_info(
1090 /*==========================*/
1091                         /* out: offset of the start of the PREVIOUS field, SQL
1092                         null flag ORed */
1093         rec_t*  rec,    /* in: record */
1094         ulint   n)      /* in: field index */
1096         ut_ad(rec_get_1byte_offs_flag(rec));
1097         ut_ad(n <= rec_get_n_fields_old(rec));
1099         return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
1102 /**********************************************************
1103 Returns the offset of n - 1th field end if the record is stored in the 2-byte
1104 offsets form. If the field is SQL null, the flag is ORed in the returned
1105 value. */
1106 UNIV_INLINE
1107 ulint
1108 rec_2_get_prev_field_end_info(
1109 /*==========================*/
1110                         /* out: offset of the start of the PREVIOUS field, SQL
1111                         null flag ORed */
1112         rec_t*  rec,    /* in: record */
1113         ulint   n)      /* in: field index */
1115         ut_ad(!rec_get_1byte_offs_flag(rec));
1116         ut_ad(n <= rec_get_n_fields_old(rec));
1118         return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
1121 /**********************************************************
1122 Sets the field end info for the nth field if the record is stored in the
1123 1-byte format. */
1124 UNIV_INLINE
1125 void
1126 rec_1_set_field_end_info(
1127 /*=====================*/
1128         rec_t*  rec,    /* in: record */
1129         ulint   n,      /* in: field index */
1130         ulint   info)   /* in: value to set */
1132         ut_ad(rec_get_1byte_offs_flag(rec));
1133         ut_ad(n < rec_get_n_fields_old(rec));
1135         mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
1138 /**********************************************************
1139 Sets the field end info for the nth field if the record is stored in the
1140 2-byte format. */
1141 UNIV_INLINE
1142 void
1143 rec_2_set_field_end_info(
1144 /*=====================*/
1145         rec_t*  rec,    /* in: record */
1146         ulint   n,      /* in: field index */
1147         ulint   info)   /* in: value to set */
1149         ut_ad(!rec_get_1byte_offs_flag(rec));
1150         ut_ad(n < rec_get_n_fields_old(rec));
1152         mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
1155 /**********************************************************
1156 Returns the offset of nth field start if the record is stored in the 1-byte
1157 offsets form. */
1158 UNIV_INLINE
1159 ulint
1160 rec_1_get_field_start_offs(
1161 /*=======================*/
1162                         /* out: offset of the start of the field */
1163         rec_t*  rec,    /* in: record */
1164         ulint   n)      /* in: field index */
1166         ut_ad(rec_get_1byte_offs_flag(rec));
1167         ut_ad(n <= rec_get_n_fields_old(rec));
1169         if (n == 0) {
1171                 return(0);
1172         }
1174         return(rec_1_get_prev_field_end_info(rec, n)
1175                & ~REC_1BYTE_SQL_NULL_MASK);
1178 /**********************************************************
1179 Returns the offset of nth field start if the record is stored in the 2-byte
1180 offsets form. */
1181 UNIV_INLINE
1182 ulint
1183 rec_2_get_field_start_offs(
1184 /*=======================*/
1185                         /* out: offset of the start of the field */
1186         rec_t*  rec,    /* in: record */
1187         ulint   n)      /* in: field index */
1189         ut_ad(!rec_get_1byte_offs_flag(rec));
1190         ut_ad(n <= rec_get_n_fields_old(rec));
1192         if (n == 0) {
1194                 return(0);
1195         }
1197         return(rec_2_get_prev_field_end_info(rec, n)
1198                & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
1201 /**********************************************************
1202 The following function is used to read the offset of the start of a data field
1203 in the record. The start of an SQL null field is the end offset of the
1204 previous non-null field, or 0, if none exists. If n is the number of the last
1205 field + 1, then the end offset of the last field is returned. */
1206 UNIV_INLINE
1207 ulint
1208 rec_get_field_start_offs(
1209 /*=====================*/
1210                         /* out: offset of the start of the field */
1211         rec_t*  rec,    /* in: record */
1212         ulint   n)      /* in: field index */
1214         ut_ad(rec);
1215         ut_ad(n <= rec_get_n_fields_old(rec));
1217         if (n == 0) {
1219                 return(0);
1220         }
1222         if (rec_get_1byte_offs_flag(rec)) {
1224                 return(rec_1_get_field_start_offs(rec, n));
1225         }
1227         return(rec_2_get_field_start_offs(rec, n));
1230 /****************************************************************
1231 Gets the physical size of an old-style field.
1232 Also an SQL null may have a field of size > 0,
1233 if the data type is of a fixed size. */
1234 UNIV_INLINE
1235 ulint
1236 rec_get_nth_field_size(
1237 /*===================*/
1238                         /* out: field size in bytes */
1239         rec_t*  rec,    /* in: record */
1240         ulint   n)      /* in: index of the field */
1242         ulint   os;
1243         ulint   next_os;
1245         os = rec_get_field_start_offs(rec, n);
1246         next_os = rec_get_field_start_offs(rec, n + 1);
1248         ut_ad(next_os - os < UNIV_PAGE_SIZE);
1250         return(next_os - os);
1253 /***************************************************************
1254 This is used to modify the value of an already existing field in a record.
1255 The previous value must have exactly the same size as the new value. If len
1256 is UNIV_SQL_NULL then the field is treated as an SQL null.
1257 For records in ROW_FORMAT=COMPACT (new-style records), len must not be
1258 UNIV_SQL_NULL unless the field already is SQL null. */
1259 UNIV_INLINE
1260 void
1261 rec_set_nth_field(
1262 /*==============*/
1263         rec_t*          rec,    /* in: record */
1264         const ulint*    offsets,/* in: array returned by rec_get_offsets() */
1265         ulint           n,      /* in: index number of the field */
1266         const void*     data,   /* in: pointer to the data
1267                                 if not SQL null */
1268         ulint           len)    /* in: length of the data or UNIV_SQL_NULL */
1270         byte*   data2;
1271         ulint   len2;
1273         ut_ad(rec);
1274         ut_ad(rec_offs_validate(rec, NULL, offsets));
1276         if (UNIV_UNLIKELY(len == UNIV_SQL_NULL)) {
1277                 if (!rec_offs_nth_sql_null(offsets, n)) {
1278                         ut_a(!rec_offs_comp(offsets));
1279                         rec_set_nth_field_sql_null(rec, n);
1280                 }
1282                 return;
1283         }
1285         data2 = rec_get_nth_field(rec, offsets, n, &len2);
1286         if (len2 == UNIV_SQL_NULL) {
1287                 ut_ad(!rec_offs_comp(offsets));
1288                 rec_set_nth_field_null_bit(rec, n, FALSE);
1289                 ut_ad(len == rec_get_nth_field_size(rec, n));
1290         } else {
1291                 ut_ad(len2 == len);
1292         }
1294         ut_memcpy(data2, data, len);
1297 /**************************************************************
1298 The following function returns the data size of an old-style physical
1299 record, that is the sum of field lengths. SQL null fields
1300 are counted as length 0 fields. The value returned by the function
1301 is the distance from record origin to record end in bytes. */
1302 UNIV_INLINE
1303 ulint
1304 rec_get_data_size_old(
1305 /*==================*/
1306                                 /* out: size */
1307         rec_t*  rec)    /* in: physical record */
1309         ut_ad(rec);
1311         return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
1314 /**************************************************************
1315 The following function sets the number of fields in offsets. */
1316 UNIV_INLINE
1317 void
1318 rec_offs_set_n_fields(
1319 /*==================*/
1320         ulint*  offsets,        /* in/out: array returned by
1321                                 rec_get_offsets() */
1322         ulint   n_fields)       /* in: number of fields */
1324         ut_ad(offsets);
1325         ut_ad(n_fields > 0);
1326         ut_ad(n_fields <= REC_MAX_N_FIELDS);
1327         ut_ad(n_fields + REC_OFFS_HEADER_SIZE
1328               <= rec_offs_get_n_alloc(offsets));
1329         offsets[1] = n_fields;
1332 /**************************************************************
1333 The following function returns the data size of a physical
1334 record, that is the sum of field lengths. SQL null fields
1335 are counted as length 0 fields. The value returned by the function
1336 is the distance from record origin to record end in bytes. */
1337 UNIV_INLINE
1338 ulint
1339 rec_offs_data_size(
1340 /*===============*/
1341                                 /* out: size */
1342         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1344         ulint   size;
1346         ut_ad(rec_offs_validate(NULL, NULL, offsets));
1347         size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
1348                 & REC_OFFS_MASK;
1349         ut_ad(size < UNIV_PAGE_SIZE);
1350         return(size);
1353 /**************************************************************
1354 Returns the total size of record minus data size of record. The value
1355 returned by the function is the distance from record start to record origin
1356 in bytes. */
1357 UNIV_INLINE
1358 ulint
1359 rec_offs_extra_size(
1360 /*================*/
1361                                 /* out: size */
1362         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1364         ulint   size;
1365         ut_ad(rec_offs_validate(NULL, NULL, offsets));
1366         size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT;
1367         ut_ad(size < UNIV_PAGE_SIZE);
1368         return(size);
1371 /**************************************************************
1372 Returns the total size of a physical record.  */
1373 UNIV_INLINE
1374 ulint
1375 rec_offs_size(
1376 /*==========*/
1377                                 /* out: size */
1378         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1380         return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
1383 /**************************************************************
1384 Returns a pointer to the end of the record. */
1385 UNIV_INLINE
1386 byte*
1387 rec_get_end(
1388 /*========*/
1389                                 /* out: pointer to end */
1390         rec_t*          rec,    /* in: pointer to record */
1391         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1393         return(rec + rec_offs_data_size(offsets));
1396 /**************************************************************
1397 Returns a pointer to the start of the record. */
1398 UNIV_INLINE
1399 byte*
1400 rec_get_start(
1401 /*==========*/
1402                                 /* out: pointer to start */
1403         rec_t*          rec,    /* in: pointer to record */
1404         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1406         return(rec - rec_offs_extra_size(offsets));
1409 /*******************************************************************
1410 Copies a physical record to a buffer. */
1411 UNIV_INLINE
1412 rec_t*
1413 rec_copy(
1414 /*=====*/
1415                                 /* out: pointer to the origin of the copy */
1416         void*           buf,    /* in: buffer */
1417         const rec_t*    rec,    /* in: physical record */
1418         const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1420         ulint   extra_len;
1421         ulint   data_len;
1423         ut_ad(rec && buf);
1424         ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
1425         ut_ad(rec_validate((rec_t*) rec, offsets));
1427         extra_len = rec_offs_extra_size(offsets);
1428         data_len = rec_offs_data_size(offsets);
1430         ut_memcpy(buf, rec - extra_len, extra_len + data_len);
1432         return((byte*)buf + extra_len);
1435 /**************************************************************
1436 Returns the extra size of an old-style physical record if we know its
1437 data size and number of fields. */
1438 UNIV_INLINE
1439 ulint
1440 rec_get_converted_extra_size(
1441 /*=========================*/
1442                                 /* out: extra size */
1443         ulint   data_size,      /* in: data size */
1444         ulint   n_fields)       /* in: number of fields */
1446         if (data_size <= REC_1BYTE_OFFS_LIMIT) {
1448                 return(REC_N_OLD_EXTRA_BYTES + n_fields);
1449         }
1451         return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
1454 /**************************************************************
1455 The following function returns the size of a data tuple when converted to
1456 a new-style physical record. */
1458 ulint
1459 rec_get_converted_size_new(
1460 /*=======================*/
1461                                 /* out: size */
1462         dict_index_t*   index,  /* in: record descriptor */
1463         dtuple_t*       dtuple);/* in: data tuple */
1464 /**************************************************************
1465 The following function returns the size of a data tuple when converted to
1466 a physical record. */
1467 UNIV_INLINE
1468 ulint
1469 rec_get_converted_size(
1470 /*===================*/
1471                                 /* out: size */
1472         dict_index_t*   index,  /* in: record descriptor */
1473         dtuple_t*       dtuple) /* in: data tuple */
1475         ulint   data_size;
1476         ulint   extra_size;
1478         ut_ad(index);
1479         ut_ad(dtuple);
1480         ut_ad(dtuple_check_typed(dtuple));
1482         ut_ad(index->type & DICT_UNIVERSAL
1483               || dtuple_get_n_fields(dtuple)
1484               == (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
1485                    == REC_STATUS_NODE_PTR)
1486                   ? dict_index_get_n_unique_in_tree(index) + 1
1487                   : dict_index_get_n_fields(index)));
1489         if (dict_table_is_comp(index->table)) {
1490                 return(rec_get_converted_size_new(index, dtuple));
1491         }
1493         data_size = dtuple_get_data_size(dtuple);
1495         extra_size = rec_get_converted_extra_size(
1496                 data_size, dtuple_get_n_fields(dtuple));
1498         return(data_size + extra_size);
1501 /****************************************************************
1502 Folds a prefix of a physical record to a ulint. Folds only existing fields,
1503 that is, checks that we do not run out of the record. */
1504 UNIV_INLINE
1505 ulint
1506 rec_fold(
1507 /*=====*/
1508                                         /* out: the folded value */
1509         rec_t*          rec,            /* in: the physical record */
1510         const ulint*    offsets,        /* in: array returned by
1511                                         rec_get_offsets() */
1512         ulint           n_fields,       /* in: number of complete
1513                                         fields to fold */
1514         ulint           n_bytes,        /* in: number of bytes to fold
1515                                         in an incomplete last field */
1516         dulint          tree_id)        /* in: index tree id */
1518         ulint   i;
1519         byte*   data;
1520         ulint   len;
1521         ulint   fold;
1522         ulint   n_fields_rec;
1524         ut_ad(rec_offs_validate(rec, NULL, offsets));
1525         ut_ad(rec_validate((rec_t*) rec, offsets));
1526         ut_ad(n_fields + n_bytes > 0);
1528         n_fields_rec = rec_offs_n_fields(offsets);
1529         ut_ad(n_fields <= n_fields_rec);
1530         ut_ad(n_fields < n_fields_rec || n_bytes == 0);
1532         if (n_fields > n_fields_rec) {
1533                 n_fields = n_fields_rec;
1534         }
1536         if (n_fields == n_fields_rec) {
1537                 n_bytes = 0;
1538         }
1540         fold = ut_fold_dulint(tree_id);
1542         for (i = 0; i < n_fields; i++) {
1543                 data = rec_get_nth_field(rec, offsets, i, &len);
1545                 if (len != UNIV_SQL_NULL) {
1546                         fold = ut_fold_ulint_pair(fold,
1547                                                   ut_fold_binary(data, len));
1548                 }
1549         }
1551         if (n_bytes > 0) {
1552                 data = rec_get_nth_field(rec, offsets, i, &len);
1554                 if (len != UNIV_SQL_NULL) {
1555                         if (len > n_bytes) {
1556                                 len = n_bytes;
1557                         }
1559                         fold = ut_fold_ulint_pair(fold,
1560                                                   ut_fold_binary(data, len));
1561                 }
1562         }
1564         return(fold);