1
/************************************************************************
4
(c) 1994-1996 Innobase Oy
6
Created 5/30/1994 Heikki Tuuri
7
*************************************************************************/
11
#include "dict0dict.h"
13
/* Compact flag ORed to the extra size returned by rec_get_offsets() */
14
#define REC_OFFS_COMPACT ((ulint) 1 << 31)
15
/* SQL NULL flag in offsets returned by rec_get_offsets() */
16
#define REC_OFFS_SQL_NULL ((ulint) 1 << 31)
17
/* External flag in offsets returned by rec_get_offsets() */
18
#define REC_OFFS_EXTERNAL ((ulint) 1 << 30)
19
/* Mask for offsets returned by rec_get_offsets() */
20
#define REC_OFFS_MASK (REC_OFFS_EXTERNAL - 1)
22
/* Offsets of the bit-fields in an old-style record. NOTE! In the table the
23
most significant bytes and bits are written below less significant.
25
(1) byte offset (2) bit usage within byte
27
origin -> 1 8 bits pointer to next record
28
2 8 bits pointer to next record
30
7 bits number of fields
31
4 3 bits number of fields
38
/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
39
most significant bytes and bits are written below less significant.
41
(1) byte offset (2) bit usage within byte
43
origin -> 1 8 bits relative offset of next record
44
2 8 bits relative offset of next record
45
the relative offset is an unsigned 16-bit
47
(offset_of_next_record
48
- offset_of_this_record) mod 64Ki,
49
where mod is the modulo as a non-negative
51
we can calculate the the offset of the next
52
record with the formula:
53
relative_offset + offset_of_this_record
56
000=conventional record
57
001=node pointer record (inside B-tree)
67
/* We list the byte offsets from the origin of the record, the mask,
68
and the shift needed to obtain each bit-field of the record. */
71
#define REC_NEXT_MASK 0xFFFFUL
72
#define REC_NEXT_SHIFT 0
74
#define REC_OLD_SHORT 3 /* This is single byte bit-field */
75
#define REC_OLD_SHORT_MASK 0x1UL
76
#define REC_OLD_SHORT_SHIFT 0
78
#define REC_OLD_N_FIELDS 4
79
#define REC_OLD_N_FIELDS_MASK 0x7FEUL
80
#define REC_OLD_N_FIELDS_SHIFT 1
82
#define REC_NEW_STATUS 3 /* This is single byte bit-field */
83
#define REC_NEW_STATUS_MASK 0x7UL
84
#define REC_NEW_STATUS_SHIFT 0
86
#define REC_OLD_HEAP_NO 5
87
#define REC_NEW_HEAP_NO 4
88
#define REC_HEAP_NO_MASK 0xFFF8UL
89
#define REC_HEAP_NO_SHIFT 3
91
#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */
92
#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */
93
#define REC_N_OWNED_MASK 0xFUL
94
#define REC_N_OWNED_SHIFT 0
96
#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */
97
#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */
98
#define REC_INFO_BITS_MASK 0xF0UL
99
#define REC_INFO_BITS_SHIFT 0
101
/* The deleted flag in info bits */
102
#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the
103
record has been delete marked */
104
/* The following masks are used to filter the SQL null bit from
105
one-byte and two-byte offsets */
107
#define REC_1BYTE_SQL_NULL_MASK 0x80UL
108
#define REC_2BYTE_SQL_NULL_MASK 0x8000UL
110
/* In a 2-byte offset the second most significant bit denotes
111
a field stored to another page: */
113
#define REC_2BYTE_EXTERN_MASK 0x4000UL
115
#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
116
^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
117
^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
118
^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
119
^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
121
# error "sum of old-style masks != 0xFFFFFFFFUL"
123
#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
124
^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
125
^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
126
^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
128
# error "sum of new-style masks != 0xFFFFFFUL"
131
/***************************************************************
132
Sets the value of the ith field SQL null bit of an old-style record. */
135
rec_set_nth_field_null_bit(
136
/*=======================*/
137
rec_t* rec, /* in: record */
138
ulint i, /* in: ith field */
139
ibool val); /* in: value to set */
140
/***************************************************************
141
Sets an old-style record field to SQL null.
142
The physical size of the field is not changed. */
145
rec_set_nth_field_sql_null(
146
/*=======================*/
147
rec_t* rec, /* in: record */
148
ulint n); /* in: index of the field */
150
/***************************************************************
151
Sets the value of the ith field extern storage bit of an old-style record. */
154
rec_set_nth_field_extern_bit_old(
155
/*=============================*/
156
rec_t* rec, /* in: old-style record */
157
ulint i, /* in: ith field */
158
ibool val, /* in: value to set */
159
mtr_t* mtr); /* in: mtr holding an X-latch to the page where
160
rec is, or NULL; in the NULL case we do not
161
write to log about the change */
162
/***************************************************************
163
Sets the value of the ith field extern storage bit of a new-style record. */
166
rec_set_nth_field_extern_bit_new(
167
/*=============================*/
168
rec_t* rec, /* in: record */
169
dict_index_t* index, /* in: record descriptor */
170
ulint ith, /* in: ith field */
171
ibool val, /* in: value to set */
172
mtr_t* mtr); /* in: mtr holding an X-latch to the page
173
where rec is, or NULL; in the NULL case
174
we do not write to log about the change */
176
/**********************************************************
177
Gets a bit field from within 1 byte. */
182
rec_t* rec, /* in: pointer to record origin */
183
ulint offs, /* in: offset from the origin down */
184
ulint mask, /* in: mask used to filter bits */
185
ulint shift) /* in: shift right applied after masking */
189
return((mach_read_from_1(rec - offs) & mask) >> shift);
192
/**********************************************************
193
Sets a bit field within 1 byte. */
198
rec_t* rec, /* in: pointer to record origin */
199
ulint val, /* in: value to set */
200
ulint offs, /* in: offset from the origin down */
201
ulint mask, /* in: mask used to filter bits */
202
ulint shift) /* in: shift right applied after masking */
205
ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
207
ut_ad(mask <= 0xFFUL);
208
ut_ad(((mask >> shift) << shift) == mask);
209
ut_ad(((val << shift) & mask) == (val << shift));
211
mach_write_to_1(rec - offs,
212
(mach_read_from_1(rec - offs) & ~mask)
216
/**********************************************************
217
Gets a bit field from within 2 bytes. */
222
rec_t* rec, /* in: pointer to record origin */
223
ulint offs, /* in: offset from the origin down */
224
ulint mask, /* in: mask used to filter bits */
225
ulint shift) /* in: shift right applied after masking */
229
return((mach_read_from_2(rec - offs) & mask) >> shift);
232
/**********************************************************
233
Sets a bit field within 2 bytes. */
238
rec_t* rec, /* in: pointer to record origin */
239
ulint val, /* in: value to set */
240
ulint offs, /* in: offset from the origin down */
241
ulint mask, /* in: mask used to filter bits */
242
ulint shift) /* in: shift right applied after masking */
245
ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
246
ut_ad(mask > 0xFFUL);
247
ut_ad(mask <= 0xFFFFUL);
248
ut_ad((mask >> shift) & 1);
249
ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
250
ut_ad(((mask >> shift) << shift) == mask);
251
ut_ad(((val << shift) & mask) == (val << shift));
253
mach_write_to_2(rec - offs,
254
(mach_read_from_2(rec - offs) & ~mask)
258
/**********************************************************
259
The following function is used to get the offset of the next chained record
265
/* out: the page offset of the next chained record, or
267
rec_t* rec, /* in: physical record */
268
ulint comp) /* in: nonzero=compact page format */
271
#if REC_NEXT_MASK != 0xFFFFUL
272
# error "REC_NEXT_MASK != 0xFFFFUL"
275
# error "REC_NEXT_SHIFT != 0"
278
field_value = mach_read_from_2(rec - REC_NEXT);
281
#if UNIV_PAGE_SIZE <= 32768
282
/* Note that for 64 KiB pages, field_value can 'wrap around'
283
and the debug assertion is not valid */
285
/* In the following assertion, field_value is interpreted
286
as signed 16-bit integer in 2's complement arithmetics.
287
If all platforms defined int16_t in the standard headers,
288
the expression could be written simpler as
289
(int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
291
ut_ad((field_value >= 32768
292
? field_value - 65536
294
+ ut_align_offset(rec, UNIV_PAGE_SIZE)
297
if (field_value == 0) {
302
return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
304
ut_ad(field_value < UNIV_PAGE_SIZE);
310
/**********************************************************
311
The following function is used to set the next record offset field of the
317
rec_t* rec, /* in: physical record */
318
ulint comp, /* in: nonzero=compact page format */
319
ulint next) /* in: offset of the next record, or 0 if none */
322
ut_ad(UNIV_PAGE_SIZE > next);
323
#if REC_NEXT_MASK != 0xFFFFUL
324
# error "REC_NEXT_MASK != 0xFFFFUL"
327
# error "REC_NEXT_SHIFT != 0"
334
/* The following two statements calculate
335
next - offset_of_rec mod 64Ki, where mod is the modulo
336
as a non-negative number */
338
field_value = (ulint)((lint)next
339
- (lint)ut_align_offset(
340
rec, UNIV_PAGE_SIZE));
341
field_value &= REC_NEXT_MASK;
346
mach_write_to_2(rec - REC_NEXT, field_value);
348
mach_write_to_2(rec - REC_NEXT, next);
352
/**********************************************************
353
The following function is used to get the number of fields
354
in an old-style record. */
357
rec_get_n_fields_old(
358
/*=================*/
359
/* out: number of data fields */
360
rec_t* rec) /* in: physical record */
366
ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
367
REC_OLD_N_FIELDS_MASK,
368
REC_OLD_N_FIELDS_SHIFT);
369
ut_ad(ret <= REC_MAX_N_FIELDS);
375
/**********************************************************
376
The following function is used to set the number of fields
377
in an old-style record. */
380
rec_set_n_fields_old(
381
/*=================*/
382
rec_t* rec, /* in: physical record */
383
ulint n_fields) /* in: the number of fields */
386
ut_ad(n_fields <= REC_MAX_N_FIELDS);
389
rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
390
REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
393
/**********************************************************
394
The following function retrieves the status bits of a new-style record. */
399
/* out: status bits */
400
rec_t* rec) /* in: physical record */
406
ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
407
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
408
ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
413
/**********************************************************
414
The following function is used to get the number of fields
420
/* out: number of data fields */
421
rec_t* rec, /* in: physical record */
422
dict_index_t* index) /* in: record descriptor */
427
if (!dict_table_is_comp(index->table)) {
428
return(rec_get_n_fields_old(rec));
431
switch (rec_get_status(rec)) {
432
case REC_STATUS_ORDINARY:
433
return(dict_index_get_n_fields(index));
434
case REC_STATUS_NODE_PTR:
435
return(dict_index_get_n_unique_in_tree(index) + 1);
436
case REC_STATUS_INFIMUM:
437
case REC_STATUS_SUPREMUM:
441
return(ULINT_UNDEFINED);
445
/**********************************************************
446
The following function is used to get the number of records owned by the
447
previous directory record. */
452
/* out: number of owned records */
453
rec_t* rec, /* in: physical record */
454
ulint comp) /* in: nonzero=compact page format */
460
ret = rec_get_bit_field_1(rec,
461
comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
462
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
463
ut_ad(ret <= REC_MAX_N_OWNED);
468
/**********************************************************
469
The following function is used to set the number of owned records. */
474
rec_t* rec, /* in: physical record */
475
ulint comp, /* in: nonzero=compact page format */
476
ulint n_owned) /* in: the number of owned */
479
ut_ad(n_owned <= REC_MAX_N_OWNED);
481
rec_set_bit_field_1(rec, n_owned,
482
comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
483
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
486
/**********************************************************
487
The following function is used to retrieve the info bits of a record. */
493
rec_t* rec, /* in: physical record */
494
ulint comp) /* in: nonzero=compact page format */
500
ret = rec_get_bit_field_1(rec,
501
comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
502
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
503
ut_ad((ret & ~REC_INFO_BITS_MASK) == 0);
508
/**********************************************************
509
The following function is used to set the info bits of a record. */
514
rec_t* rec, /* in: physical record */
515
ulint comp, /* in: nonzero=compact page format */
516
ulint bits) /* in: info bits */
519
ut_ad((bits & ~REC_INFO_BITS_MASK) == 0);
521
rec_set_bit_field_1(rec, bits,
522
comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
523
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
526
/**********************************************************
527
The following function is used to set the status bits of a new-style record. */
532
rec_t* rec, /* in: physical record */
533
ulint bits) /* in: info bits */
536
ut_ad((bits & ~REC_NEW_STATUS_MASK) == 0);
538
rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
539
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
542
/**********************************************************
543
The following function is used to retrieve the info and status
544
bits of a record. (Only compact records have status bits.) */
547
rec_get_info_and_status_bits(
548
/*=========================*/
550
rec_t* rec, /* in: physical record */
551
ulint comp) /* in: nonzero=compact page format */
554
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
555
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
556
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
558
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
559
bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
561
bits = rec_get_info_bits(rec, FALSE);
562
ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
566
/**********************************************************
567
The following function is used to set the info and status
568
bits of a record. (Only compact records have status bits.) */
571
rec_set_info_and_status_bits(
572
/*=========================*/
573
rec_t* rec, /* in: physical record */
574
ulint comp, /* in: nonzero=compact page format */
575
ulint bits) /* in: info bits */
577
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
578
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
579
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
582
rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
584
ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
586
rec_set_info_bits(rec, comp, bits & ~REC_NEW_STATUS_MASK);
589
/**********************************************************
590
The following function tells if record is delete marked. */
593
rec_get_deleted_flag(
594
/*=================*/
595
/* out: nonzero if delete marked */
596
rec_t* rec, /* in: physical record */
597
ulint comp) /* in: nonzero=compact page format */
599
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
600
return(UNIV_UNLIKELY(
601
rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
602
REC_INFO_DELETED_FLAG,
603
REC_INFO_BITS_SHIFT)));
605
return(UNIV_UNLIKELY(
606
rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
607
REC_INFO_DELETED_FLAG,
608
REC_INFO_BITS_SHIFT)));
612
/**********************************************************
613
The following function is used to set the deleted bit. */
616
rec_set_deleted_flag(
617
/*=================*/
618
rec_t* rec, /* in: physical record */
619
ulint comp, /* in: nonzero=compact page format */
620
ulint flag) /* in: nonzero if delete marked */
624
val = rec_get_info_bits(rec, comp);
627
val |= REC_INFO_DELETED_FLAG;
629
val &= ~REC_INFO_DELETED_FLAG;
632
rec_set_info_bits(rec, comp, val);
635
/**********************************************************
636
The following function tells if a new-style record is a node pointer. */
639
rec_get_node_ptr_flag(
640
/*==================*/
641
/* out: TRUE if node pointer */
642
rec_t* rec) /* in: physical record */
644
return(REC_STATUS_NODE_PTR == rec_get_status(rec));
647
/**********************************************************
648
The following function is used to get the order number of the record in the
649
heap of the index page. */
654
/* out: heap order number */
655
rec_t* rec, /* in: physical record */
656
ulint comp) /* in: nonzero=compact page format */
662
ret = rec_get_bit_field_2(rec,
663
comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
664
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
665
ut_ad(ret <= REC_MAX_HEAP_NO);
670
/**********************************************************
671
The following function is used to set the heap number field in the record. */
676
rec_t* rec, /* in: physical record */
677
ulint comp, /* in: nonzero=compact page format */
678
ulint heap_no)/* in: the heap number */
680
ut_ad(heap_no <= REC_MAX_HEAP_NO);
682
rec_set_bit_field_2(rec, heap_no,
683
comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
684
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
687
/**********************************************************
688
The following function is used to test whether the data offsets in the record
689
are stored in one-byte or two-byte format. */
692
rec_get_1byte_offs_flag(
693
/*====================*/
694
/* out: TRUE if 1-byte form */
695
rec_t* rec) /* in: physical record */
701
return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
702
REC_OLD_SHORT_SHIFT));
705
/**********************************************************
706
The following function is used to set the 1-byte offsets flag. */
709
rec_set_1byte_offs_flag(
710
/*====================*/
711
rec_t* rec, /* in: physical record */
712
ibool flag) /* in: TRUE if 1byte form */
719
rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
720
REC_OLD_SHORT_SHIFT);
723
/**********************************************************
724
Returns the offset of nth field end if the record is stored in the 1-byte
725
offsets form. If the field is SQL null, the flag is ORed in the returned
729
rec_1_get_field_end_info(
730
/*=====================*/
731
/* out: offset of the start of the field, SQL null
733
rec_t* rec, /* in: record */
734
ulint n) /* in: field index */
736
ut_ad(rec_get_1byte_offs_flag(rec));
737
ut_ad(n < rec_get_n_fields_old(rec));
739
return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
742
/**********************************************************
743
Returns the offset of nth field end if the record is stored in the 2-byte
744
offsets form. If the field is SQL null, the flag is ORed in the returned
748
rec_2_get_field_end_info(
749
/*=====================*/
750
/* out: offset of the start of the field, SQL null
751
flag and extern storage flag ORed */
752
rec_t* rec, /* in: record */
753
ulint n) /* in: field index */
755
ut_ad(!rec_get_1byte_offs_flag(rec));
756
ut_ad(n < rec_get_n_fields_old(rec));
758
return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
762
/* Length of the rec_get_offsets() header */
763
# define REC_OFFS_HEADER_SIZE 4
764
#else /* UNIV_DEBUG */
765
/* Length of the rec_get_offsets() header */
766
# define REC_OFFS_HEADER_SIZE 2
767
#endif /* UNIV_DEBUG */
769
/* Get the base address of offsets. The extra_size is stored at
770
this position, and following positions hold the end offsets of
772
#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
774
/**************************************************************
775
The following function returns the number of allocated elements
776
for an array of offsets. */
779
rec_offs_get_n_alloc(
780
/*=================*/
781
/* out: number of elements */
782
const ulint* offsets)/* in: array for rec_get_offsets() */
786
n_alloc = offsets[0];
791
/**************************************************************
792
The following function sets the number of allocated elements
793
for an array of offsets. */
796
rec_offs_set_n_alloc(
797
/*=================*/
798
ulint* offsets, /* out: array for rec_get_offsets(),
800
ulint n_alloc) /* in: number of elements */
804
UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
805
offsets[0] = n_alloc;
808
/**************************************************************
809
The following function returns the number of fields in a record. */
814
/* out: number of fields */
815
const ulint* offsets)/* in: array returned by rec_get_offsets() */
819
n_fields = offsets[1];
821
ut_ad(n_fields <= REC_MAX_N_FIELDS);
822
ut_ad(n_fields + REC_OFFS_HEADER_SIZE
823
<= rec_offs_get_n_alloc(offsets));
827
/****************************************************************
828
Validates offsets returned by rec_get_offsets(). */
833
/* out: TRUE if valid */
834
rec_t* rec, /* in: record or NULL */
835
dict_index_t* index, /* in: record descriptor or NULL */
836
const ulint* offsets)/* in: array returned by rec_get_offsets() */
838
ulint i = rec_offs_n_fields(offsets);
839
ulint last = ULINT_MAX;
840
ulint comp = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
843
ut_ad((ulint) rec == offsets[2]);
845
ut_a(rec_get_n_fields_old(rec) >= i);
850
ut_ad((ulint) index == offsets[3]);
851
max_n_fields = ut_max(
852
dict_index_get_n_fields(index),
853
dict_index_get_n_unique_in_tree(index) + 1);
855
switch (rec_get_status(rec)) {
856
case REC_STATUS_ORDINARY:
858
case REC_STATUS_NODE_PTR:
859
max_n_fields = dict_index_get_n_unique_in_tree(
862
case REC_STATUS_INFIMUM:
863
case REC_STATUS_SUPREMUM:
870
/* index->n_def == 0 for dummy indexes if !comp */
871
ut_a(!comp || index->n_def);
872
ut_a(!index->n_def || i <= max_n_fields);
875
ulint curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
881
/****************************************************************
882
Updates debug data in offsets, in order to avoid bogus
883
rec_offs_validate() failures. */
888
rec_t* rec __attribute__((unused)),
890
dict_index_t* index __attribute__((unused)),
891
/* in: record descriptor */
892
ulint* offsets __attribute__((unused)))
893
/* in: array returned by rec_get_offsets() */
896
ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
897
offsets[2] = (ulint) rec;
898
offsets[3] = (ulint) index;
899
#endif /* UNIV_DEBUG */
902
/****************************************************************
903
The following function is used to get a pointer to the nth
904
data field in a record. */
909
/* out: pointer to the field */
910
rec_t* rec, /* in: record */
911
const ulint* offsets,/* in: array returned by rec_get_offsets() */
912
ulint n, /* in: index of the field */
913
ulint* len) /* out: length of the field; UNIV_SQL_NULL
919
ut_ad(rec_offs_validate(rec, NULL, offsets));
920
ut_ad(n < rec_offs_n_fields(offsets));
923
if (UNIV_UNLIKELY(n == 0)) {
926
field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
929
length = rec_offs_base(offsets)[1 + n];
931
if (length & REC_OFFS_SQL_NULL) {
932
length = UNIV_SQL_NULL;
934
length &= REC_OFFS_MASK;
935
length -= field - rec;
942
/**********************************************************
943
Determine if the offsets are for a record in the new
949
/* out: nonzero if compact format */
950
const ulint* offsets)/* in: array returned by rec_get_offsets() */
952
ut_ad(rec_offs_validate(NULL, NULL, offsets));
953
return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
956
/**********************************************************
957
Returns nonzero if the extern bit is set in nth field of rec. */
962
/* out: nonzero if externally stored */
963
const ulint* offsets,/* in: array returned by rec_get_offsets() */
964
ulint n) /* in: nth field */
966
ut_ad(rec_offs_validate(NULL, NULL, offsets));
967
ut_ad(n < rec_offs_n_fields(offsets));
968
return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
969
& REC_OFFS_EXTERNAL));
972
/**********************************************************
973
Returns nonzero if the SQL NULL bit is set in nth field of rec. */
976
rec_offs_nth_sql_null(
977
/*==================*/
978
/* out: nonzero if SQL NULL */
979
const ulint* offsets,/* in: array returned by rec_get_offsets() */
980
ulint n) /* in: nth field */
982
ut_ad(rec_offs_validate(NULL, NULL, offsets));
983
ut_ad(n < rec_offs_n_fields(offsets));
984
return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
985
& REC_OFFS_SQL_NULL));
988
/**********************************************************
989
Gets the physical size of a field. */
994
/* out: length of field */
995
const ulint* offsets,/* in: array returned by rec_get_offsets() */
996
ulint n) /* in: nth field */
998
ut_ad(rec_offs_validate(NULL, NULL, offsets));
999
ut_ad(n < rec_offs_n_fields(offsets));
1001
return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
1003
return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
1007
/**********************************************************
1008
Returns TRUE if the extern bit is set in any of the fields
1009
of an old-style record. */
1012
rec_offs_any_extern(
1013
/*================*/
1014
/* out: TRUE if a field is stored externally */
1015
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1018
for (i = rec_offs_n_fields(offsets); i--; ) {
1019
if (rec_offs_nth_extern(offsets, i)) {
1026
/***************************************************************
1027
Sets the value of the ith field extern storage bit. */
1030
rec_set_nth_field_extern_bit(
1031
/*=========================*/
1032
rec_t* rec, /* in: record */
1033
dict_index_t* index, /* in: record descriptor */
1034
ulint i, /* in: ith field */
1035
ibool val, /* in: value to set */
1036
mtr_t* mtr) /* in: mtr holding an X-latch to the page
1037
where rec is, or NULL; in the NULL case
1038
we do not write to log about the change */
1040
if (dict_table_is_comp(index->table)) {
1041
rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
1043
rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
1047
/**********************************************************
1048
Returns the offset of n - 1th field end if the record is stored in the 1-byte
1049
offsets form. If the field is SQL null, the flag is ORed in the returned
1050
value. This function and the 2-byte counterpart are defined here because the
1051
C-compiler was not able to sum negative and positive constant offsets, and
1052
warned of constant arithmetic overflow within the compiler. */
1055
rec_1_get_prev_field_end_info(
1056
/*==========================*/
1057
/* out: offset of the start of the PREVIOUS field, SQL
1059
rec_t* rec, /* in: record */
1060
ulint n) /* in: field index */
1062
ut_ad(rec_get_1byte_offs_flag(rec));
1063
ut_ad(n <= rec_get_n_fields_old(rec));
1065
return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
1068
/**********************************************************
1069
Returns the offset of n - 1th field end if the record is stored in the 2-byte
1070
offsets form. If the field is SQL null, the flag is ORed in the returned
1074
rec_2_get_prev_field_end_info(
1075
/*==========================*/
1076
/* out: offset of the start of the PREVIOUS field, SQL
1078
rec_t* rec, /* in: record */
1079
ulint n) /* in: field index */
1081
ut_ad(!rec_get_1byte_offs_flag(rec));
1082
ut_ad(n <= rec_get_n_fields_old(rec));
1084
return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
1087
/**********************************************************
1088
Sets the field end info for the nth field if the record is stored in the
1092
rec_1_set_field_end_info(
1093
/*=====================*/
1094
rec_t* rec, /* in: record */
1095
ulint n, /* in: field index */
1096
ulint info) /* in: value to set */
1098
ut_ad(rec_get_1byte_offs_flag(rec));
1099
ut_ad(n < rec_get_n_fields_old(rec));
1101
mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
1104
/**********************************************************
1105
Sets the field end info for the nth field if the record is stored in the
1109
rec_2_set_field_end_info(
1110
/*=====================*/
1111
rec_t* rec, /* in: record */
1112
ulint n, /* in: field index */
1113
ulint info) /* in: value to set */
1115
ut_ad(!rec_get_1byte_offs_flag(rec));
1116
ut_ad(n < rec_get_n_fields_old(rec));
1118
mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
1121
/**********************************************************
1122
Returns the offset of nth field start if the record is stored in the 1-byte
1126
rec_1_get_field_start_offs(
1127
/*=======================*/
1128
/* out: offset of the start of the field */
1129
rec_t* rec, /* in: record */
1130
ulint n) /* in: field index */
1132
ut_ad(rec_get_1byte_offs_flag(rec));
1133
ut_ad(n <= rec_get_n_fields_old(rec));
1140
return(rec_1_get_prev_field_end_info(rec, n)
1141
& ~REC_1BYTE_SQL_NULL_MASK);
1144
/**********************************************************
1145
Returns the offset of nth field start if the record is stored in the 2-byte
1149
rec_2_get_field_start_offs(
1150
/*=======================*/
1151
/* out: offset of the start of the field */
1152
rec_t* rec, /* in: record */
1153
ulint n) /* in: field index */
1155
ut_ad(!rec_get_1byte_offs_flag(rec));
1156
ut_ad(n <= rec_get_n_fields_old(rec));
1163
return(rec_2_get_prev_field_end_info(rec, n)
1164
& ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
1167
/**********************************************************
1168
The following function is used to read the offset of the start of a data field
1169
in the record. The start of an SQL null field is the end offset of the
1170
previous non-null field, or 0, if none exists. If n is the number of the last
1171
field + 1, then the end offset of the last field is returned. */
1174
rec_get_field_start_offs(
1175
/*=====================*/
1176
/* out: offset of the start of the field */
1177
rec_t* rec, /* in: record */
1178
ulint n) /* in: field index */
1181
ut_ad(n <= rec_get_n_fields_old(rec));
1188
if (rec_get_1byte_offs_flag(rec)) {
1190
return(rec_1_get_field_start_offs(rec, n));
1193
return(rec_2_get_field_start_offs(rec, n));
1196
/****************************************************************
1197
Gets the physical size of an old-style field.
1198
Also an SQL null may have a field of size > 0,
1199
if the data type is of a fixed size. */
1202
rec_get_nth_field_size(
1203
/*===================*/
1204
/* out: field size in bytes */
1205
rec_t* rec, /* in: record */
1206
ulint n) /* in: index of the field */
1211
os = rec_get_field_start_offs(rec, n);
1212
next_os = rec_get_field_start_offs(rec, n + 1);
1214
ut_ad(next_os - os < UNIV_PAGE_SIZE);
1216
return(next_os - os);
1219
/***************************************************************
1220
This is used to modify the value of an already existing field in a record.
1221
The previous value must have exactly the same size as the new value. If len
1222
is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
1223
records. For new-style records, len must not be UNIV_SQL_NULL. */
1228
rec_t* rec, /* in: record */
1229
const ulint* offsets,/* in: array returned by rec_get_offsets() */
1230
ulint n, /* in: index number of the field */
1231
const void* data, /* in: pointer to the data
1233
ulint len) /* in: length of the data or UNIV_SQL_NULL.
1234
If not SQL null, must have the same
1235
length as the previous value.
1236
If SQL null, previous value must be
1243
ut_ad(rec_offs_validate(rec, NULL, offsets));
1245
if (len == UNIV_SQL_NULL) {
1246
ut_ad(!rec_offs_comp(offsets));
1247
rec_set_nth_field_sql_null(rec, n);
1252
data2 = rec_get_nth_field(rec, offsets, n, &len2);
1253
if (len2 == UNIV_SQL_NULL) {
1254
ut_ad(!rec_offs_comp(offsets));
1255
rec_set_nth_field_null_bit(rec, n, FALSE);
1256
ut_ad(len == rec_get_nth_field_size(rec, n));
1261
ut_memcpy(data2, data, len);
1264
/**************************************************************
1265
The following function returns the data size of an old-style physical
1266
record, that is the sum of field lengths. SQL null fields
1267
are counted as length 0 fields. The value returned by the function
1268
is the distance from record origin to record end in bytes. */
1271
rec_get_data_size_old(
1272
/*==================*/
1274
rec_t* rec) /* in: physical record */
1278
return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
1281
/**************************************************************
1282
The following function sets the number of fields in offsets. */
1285
rec_offs_set_n_fields(
1286
/*==================*/
1287
ulint* offsets, /* in/out: array returned by
1288
rec_get_offsets() */
1289
ulint n_fields) /* in: number of fields */
1292
ut_ad(n_fields > 0);
1293
ut_ad(n_fields <= REC_MAX_N_FIELDS);
1294
ut_ad(n_fields + REC_OFFS_HEADER_SIZE
1295
<= rec_offs_get_n_alloc(offsets));
1296
offsets[1] = n_fields;
1299
/**************************************************************
1300
The following function returns the data size of a physical
1301
record, that is the sum of field lengths. SQL null fields
1302
are counted as length 0 fields. The value returned by the function
1303
is the distance from record origin to record end in bytes. */
1309
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1313
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1314
size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
1316
ut_ad(size < UNIV_PAGE_SIZE);
1320
/**************************************************************
1321
Returns the total size of record minus data size of record. The value
1322
returned by the function is the distance from record start to record origin
1326
rec_offs_extra_size(
1327
/*================*/
1329
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1332
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1333
size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT;
1334
ut_ad(size < UNIV_PAGE_SIZE);
1338
/**************************************************************
1339
Returns the total size of a physical record. */
1345
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1347
return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
1350
/**************************************************************
1351
Returns a pointer to the end of the record. */
1356
/* out: pointer to end */
1357
rec_t* rec, /* in: pointer to record */
1358
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1360
return(rec + rec_offs_data_size(offsets));
1363
/**************************************************************
1364
Returns a pointer to the start of the record. */
1369
/* out: pointer to start */
1370
rec_t* rec, /* in: pointer to record */
1371
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1373
return(rec - rec_offs_extra_size(offsets));
1376
/*******************************************************************
1377
Copies a physical record to a buffer. */
1382
/* out: pointer to the origin of the copy */
1383
void* buf, /* in: buffer */
1384
const rec_t* rec, /* in: physical record */
1385
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1391
ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
1392
ut_ad(rec_validate((rec_t*) rec, offsets));
1394
extra_len = rec_offs_extra_size(offsets);
1395
data_len = rec_offs_data_size(offsets);
1397
ut_memcpy(buf, rec - extra_len, extra_len + data_len);
1399
return((byte*)buf + extra_len);
1402
/**************************************************************
1403
Returns the extra size of an old-style physical record if we know its
1404
data size and number of fields. */
1407
rec_get_converted_extra_size(
1408
/*=========================*/
1409
/* out: extra size */
1410
ulint data_size, /* in: data size */
1411
ulint n_fields) /* in: number of fields */
1413
if (data_size <= REC_1BYTE_OFFS_LIMIT) {
1415
return(REC_N_OLD_EXTRA_BYTES + n_fields);
1418
return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
1421
/**************************************************************
1422
The following function returns the size of a data tuple when converted to
1423
a new-style physical record. */
1426
rec_get_converted_size_new(
1427
/*=======================*/
1429
dict_index_t* index, /* in: record descriptor */
1430
dtuple_t* dtuple);/* in: data tuple */
1431
/**************************************************************
1432
The following function returns the size of a data tuple when converted to
1433
a physical record. */
1436
rec_get_converted_size(
1437
/*===================*/
1439
dict_index_t* index, /* in: record descriptor */
1440
dtuple_t* dtuple) /* in: data tuple */
1447
ut_ad(dtuple_check_typed(dtuple));
1449
ut_ad(index->type & DICT_UNIVERSAL
1450
|| dtuple_get_n_fields(dtuple)
1451
== (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
1452
== REC_STATUS_NODE_PTR)
1453
? dict_index_get_n_unique_in_tree(index) + 1
1454
: dict_index_get_n_fields(index)));
1456
if (dict_table_is_comp(index->table)) {
1457
return(rec_get_converted_size_new(index, dtuple));
1460
data_size = dtuple_get_data_size(dtuple);
1462
extra_size = rec_get_converted_extra_size(
1463
data_size, dtuple_get_n_fields(dtuple));
1465
return(data_size + extra_size);
1468
/****************************************************************
1469
Folds a prefix of a physical record to a ulint. Folds only existing fields,
1470
that is, checks that we do not run out of the record. */
1475
/* out: the folded value */
1476
rec_t* rec, /* in: the physical record */
1477
const ulint* offsets, /* in: array returned by
1478
rec_get_offsets() */
1479
ulint n_fields, /* in: number of complete
1481
ulint n_bytes, /* in: number of bytes to fold
1482
in an incomplete last field */
1483
dulint tree_id) /* in: index tree id */
1491
ut_ad(rec_offs_validate(rec, NULL, offsets));
1492
ut_ad(rec_validate((rec_t*) rec, offsets));
1493
ut_ad(n_fields + n_bytes > 0);
1495
n_fields_rec = rec_offs_n_fields(offsets);
1496
ut_ad(n_fields <= n_fields_rec);
1497
ut_ad(n_fields < n_fields_rec || n_bytes == 0);
1499
if (n_fields > n_fields_rec) {
1500
n_fields = n_fields_rec;
1503
if (n_fields == n_fields_rec) {
1507
fold = ut_fold_dulint(tree_id);
1509
for (i = 0; i < n_fields; i++) {
1510
data = rec_get_nth_field(rec, offsets, i, &len);
1512
if (len != UNIV_SQL_NULL) {
1513
fold = ut_fold_ulint_pair(fold,
1514
ut_fold_binary(data, len));
1519
data = rec_get_nth_field(rec, offsets, i, &len);
1521
if (len != UNIV_SQL_NULL) {
1522
if (len > n_bytes) {
1526
fold = ut_fold_ulint_pair(fold,
1527
ut_fold_binary(data, len));