1
/*****************************************************************************
3
Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/********************************************************************//**
20
@file include/rem0rec.ic
23
Created 5/30/1994 Heikki Tuuri
24
*************************************************************************/
26
#include "mach0data.h"
28
#include "dict0dict.h"
30
/* Compact flag ORed to the extra size returned by rec_get_offsets() */
31
#define REC_OFFS_COMPACT ((ulint) 1 << 31)
32
/* SQL NULL flag in offsets returned by rec_get_offsets() */
33
#define REC_OFFS_SQL_NULL ((ulint) 1 << 31)
34
/* External flag in offsets returned by rec_get_offsets() */
35
#define REC_OFFS_EXTERNAL ((ulint) 1 << 30)
36
/* Mask for offsets returned by rec_get_offsets() */
37
#define REC_OFFS_MASK (REC_OFFS_EXTERNAL - 1)
39
/* Offsets of the bit-fields in an old-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
44
origin -> 1 8 bits pointer to next record
45
2 8 bits pointer to next record
47
7 bits number of fields
48
4 3 bits number of fields
55
/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
56
most significant bytes and bits are written below less significant.
58
(1) byte offset (2) bit usage within byte
60
origin -> 1 8 bits relative offset of next record
61
2 8 bits relative offset of next record
62
the relative offset is an unsigned 16-bit
64
(offset_of_next_record
65
- offset_of_this_record) mod 64Ki,
66
where mod is the modulo as a non-negative
68
we can calculate the the offset of the next
69
record with the formula:
70
relative_offset + offset_of_this_record
73
000=conventional record
74
001=node pointer record (inside B-tree)
84
/* We list the byte offsets from the origin of the record, the mask,
85
and the shift needed to obtain each bit-field of the record. */
88
#define REC_NEXT_MASK 0xFFFFUL
89
#define REC_NEXT_SHIFT 0
91
#define REC_OLD_SHORT 3 /* This is single byte bit-field */
92
#define REC_OLD_SHORT_MASK 0x1UL
93
#define REC_OLD_SHORT_SHIFT 0
95
#define REC_OLD_N_FIELDS 4
96
#define REC_OLD_N_FIELDS_MASK 0x7FEUL
97
#define REC_OLD_N_FIELDS_SHIFT 1
99
#define REC_NEW_STATUS 3 /* This is single byte bit-field */
100
#define REC_NEW_STATUS_MASK 0x7UL
101
#define REC_NEW_STATUS_SHIFT 0
103
#define REC_OLD_HEAP_NO 5
104
#define REC_HEAP_NO_MASK 0xFFF8UL
105
#if 0 /* defined in rem0rec.h for use of page0zip.c */
106
#define REC_NEW_HEAP_NO 4
107
#define REC_HEAP_NO_SHIFT 3
110
#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */
111
#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */
112
#define REC_N_OWNED_MASK 0xFUL
113
#define REC_N_OWNED_SHIFT 0
115
#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */
116
#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */
117
#define REC_INFO_BITS_MASK 0xF0UL
118
#define REC_INFO_BITS_SHIFT 0
120
/* The following masks are used to filter the SQL null bit from
121
one-byte and two-byte offsets */
123
#define REC_1BYTE_SQL_NULL_MASK 0x80UL
124
#define REC_2BYTE_SQL_NULL_MASK 0x8000UL
126
/* In a 2-byte offset the second most significant bit denotes
127
a field stored to another page: */
129
#define REC_2BYTE_EXTERN_MASK 0x4000UL
131
#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
132
^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
133
^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
134
^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
135
^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
137
# error "sum of old-style masks != 0xFFFFFFFFUL"
139
#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
140
^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
141
^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
142
^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
144
# error "sum of new-style masks != 0xFFFFFFUL"
147
/***********************************************************//**
148
Sets the value of the ith field SQL null bit of an old-style record. */
151
rec_set_nth_field_null_bit(
152
/*=======================*/
153
rec_t* rec, /*!< in: record */
154
ulint i, /*!< in: ith field */
155
ibool val); /*!< in: value to set */
156
/***********************************************************//**
157
Sets an old-style record field to SQL null.
158
The physical size of the field is not changed. */
161
rec_set_nth_field_sql_null(
162
/*=======================*/
163
rec_t* rec, /*!< in: record */
164
ulint n); /*!< in: index of the field */
166
/******************************************************//**
167
Gets a bit field from within 1 byte. */
172
const rec_t* rec, /*!< in: pointer to record origin */
173
ulint offs, /*!< in: offset from the origin down */
174
ulint mask, /*!< in: mask used to filter bits */
175
ulint shift) /*!< in: shift right applied after masking */
179
return((mach_read_from_1(rec - offs) & mask) >> shift);
182
/******************************************************//**
183
Sets a bit field within 1 byte. */
188
rec_t* rec, /*!< in: pointer to record origin */
189
ulint val, /*!< in: value to set */
190
ulint offs, /*!< in: offset from the origin down */
191
ulint mask, /*!< in: mask used to filter bits */
192
ulint shift) /*!< in: shift right applied after masking */
195
ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
197
ut_ad(mask <= 0xFFUL);
198
ut_ad(((mask >> shift) << shift) == mask);
199
ut_ad(((val << shift) & mask) == (val << shift));
201
mach_write_to_1(rec - offs,
202
(mach_read_from_1(rec - offs) & ~mask)
206
/******************************************************//**
207
Gets a bit field from within 2 bytes. */
212
const rec_t* rec, /*!< in: pointer to record origin */
213
ulint offs, /*!< in: offset from the origin down */
214
ulint mask, /*!< in: mask used to filter bits */
215
ulint shift) /*!< in: shift right applied after masking */
219
return((mach_read_from_2(rec - offs) & mask) >> shift);
222
/******************************************************//**
223
Sets a bit field within 2 bytes. */
228
rec_t* rec, /*!< in: pointer to record origin */
229
ulint val, /*!< in: value to set */
230
ulint offs, /*!< in: offset from the origin down */
231
ulint mask, /*!< in: mask used to filter bits */
232
ulint shift) /*!< in: shift right applied after masking */
235
ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
236
ut_ad(mask > 0xFFUL);
237
ut_ad(mask <= 0xFFFFUL);
238
ut_ad((mask >> shift) & 1);
239
ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
240
ut_ad(((mask >> shift) << shift) == mask);
241
ut_ad(((val << shift) & mask) == (val << shift));
243
mach_write_to_2(rec - offs,
244
(mach_read_from_2(rec - offs) & ~mask)
248
/******************************************************//**
249
The following function is used to get the pointer of the next chained record
251
@return pointer to the next chained record, or NULL if none */
254
rec_get_next_ptr_const(
255
/*===================*/
256
const rec_t* rec, /*!< in: physical record */
257
ulint comp) /*!< in: nonzero=compact page format */
261
ut_ad(REC_NEXT_MASK == 0xFFFFUL);
262
ut_ad(REC_NEXT_SHIFT == 0);
264
field_value = mach_read_from_2(rec - REC_NEXT);
266
if (UNIV_UNLIKELY(field_value == 0)) {
271
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
272
#if UNIV_PAGE_SIZE <= 32768
273
/* Note that for 64 KiB pages, field_value can 'wrap around'
274
and the debug assertion is not valid */
276
/* In the following assertion, field_value is interpreted
277
as signed 16-bit integer in 2's complement arithmetics.
278
If all platforms defined int16_t in the standard headers,
279
the expression could be written simpler as
280
(int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
282
ut_ad((field_value >= 32768
283
? field_value - 65536
285
+ ut_align_offset(rec, UNIV_PAGE_SIZE)
288
/* There must be at least REC_N_NEW_EXTRA_BYTES + 1
289
between each record. */
290
ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
291
&& field_value < 32768)
292
|| field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
294
return((byte*) ut_align_down(rec, UNIV_PAGE_SIZE)
295
+ ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
297
ut_ad(field_value < UNIV_PAGE_SIZE);
299
return((byte*) ut_align_down(rec, UNIV_PAGE_SIZE)
304
/******************************************************//**
305
The following function is used to get the pointer of the next chained record
307
@return pointer to the next chained record, or NULL if none */
312
rec_t* rec, /*!< in: physical record */
313
ulint comp) /*!< in: nonzero=compact page format */
315
return((rec_t*) rec_get_next_ptr_const(rec, comp));
318
/******************************************************//**
319
The following function is used to get the offset of the next chained record
321
@return the page offset of the next chained record, or 0 if none */
326
const rec_t* rec, /*!< in: physical record */
327
ulint comp) /*!< in: nonzero=compact page format */
330
#if REC_NEXT_MASK != 0xFFFFUL
331
# error "REC_NEXT_MASK != 0xFFFFUL"
334
# error "REC_NEXT_SHIFT != 0"
337
field_value = mach_read_from_2(rec - REC_NEXT);
339
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
340
#if UNIV_PAGE_SIZE <= 32768
341
/* Note that for 64 KiB pages, field_value can 'wrap around'
342
and the debug assertion is not valid */
344
/* In the following assertion, field_value is interpreted
345
as signed 16-bit integer in 2's complement arithmetics.
346
If all platforms defined int16_t in the standard headers,
347
the expression could be written simpler as
348
(int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
350
ut_ad((field_value >= 32768
351
? field_value - 65536
353
+ ut_align_offset(rec, UNIV_PAGE_SIZE)
356
if (UNIV_UNLIKELY(field_value == 0)) {
361
/* There must be at least REC_N_NEW_EXTRA_BYTES + 1
362
between each record. */
363
ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
364
&& field_value < 32768)
365
|| field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
367
return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
369
ut_ad(field_value < UNIV_PAGE_SIZE);
375
/******************************************************//**
376
The following function is used to set the next record offset field
377
of an old-style record. */
380
rec_set_next_offs_old(
381
/*==================*/
382
rec_t* rec, /*!< in: old-style physical record */
383
ulint next) /*!< in: offset of the next record */
386
ut_ad(UNIV_PAGE_SIZE > next);
387
#if REC_NEXT_MASK != 0xFFFFUL
388
# error "REC_NEXT_MASK != 0xFFFFUL"
391
# error "REC_NEXT_SHIFT != 0"
394
mach_write_to_2(rec - REC_NEXT, next);
397
/******************************************************//**
398
The following function is used to set the next record offset field
399
of a new-style record. */
402
rec_set_next_offs_new(
403
/*==================*/
404
rec_t* rec, /*!< in/out: new-style physical record */
405
ulint next) /*!< in: offset of the next record */
410
ut_ad(UNIV_PAGE_SIZE > next);
412
if (UNIV_UNLIKELY(!next)) {
415
/* The following two statements calculate
416
next - offset_of_rec mod 64Ki, where mod is the modulo
417
as a non-negative number */
419
field_value = (ulint)
421
- (lint) ut_align_offset(rec, UNIV_PAGE_SIZE));
422
field_value &= REC_NEXT_MASK;
425
mach_write_to_2(rec - REC_NEXT, field_value);
428
/******************************************************//**
429
The following function is used to get the number of fields
430
in an old-style record.
431
@return number of data fields */
434
rec_get_n_fields_old(
435
/*=================*/
436
const rec_t* rec) /*!< in: physical record */
442
ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
443
REC_OLD_N_FIELDS_MASK,
444
REC_OLD_N_FIELDS_SHIFT);
445
ut_ad(ret <= REC_MAX_N_FIELDS);
451
/******************************************************//**
452
The following function is used to set the number of fields
453
in an old-style record. */
456
rec_set_n_fields_old(
457
/*=================*/
458
rec_t* rec, /*!< in: physical record */
459
ulint n_fields) /*!< in: the number of fields */
462
ut_ad(n_fields <= REC_MAX_N_FIELDS);
465
rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
466
REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
469
/******************************************************//**
470
The following function retrieves the status bits of a new-style record.
471
@return status bits */
476
const rec_t* rec) /*!< in: physical record */
482
ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
483
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
484
ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
489
/******************************************************//**
490
The following function is used to get the number of fields
492
@return number of data fields */
497
const rec_t* rec, /*!< in: physical record */
498
const dict_index_t* index) /*!< in: record descriptor */
503
if (!dict_table_is_comp(index->table)) {
504
return(rec_get_n_fields_old(rec));
507
switch (rec_get_status(rec)) {
508
case REC_STATUS_ORDINARY:
509
return(dict_index_get_n_fields(index));
510
case REC_STATUS_NODE_PTR:
511
return(dict_index_get_n_unique_in_tree(index) + 1);
512
case REC_STATUS_INFIMUM:
513
case REC_STATUS_SUPREMUM:
517
return(ULINT_UNDEFINED);
521
/******************************************************//**
522
The following function is used to get the number of records owned by the
523
previous directory record.
524
@return number of owned records */
529
const rec_t* rec) /*!< in: old-style physical record */
531
return(rec_get_bit_field_1(rec, REC_OLD_N_OWNED,
532
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT));
535
/******************************************************//**
536
The following function is used to set the number of owned records. */
541
rec_t* rec, /*!< in: old-style physical record */
542
ulint n_owned) /*!< in: the number of owned */
544
rec_set_bit_field_1(rec, n_owned, REC_OLD_N_OWNED,
545
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
548
/******************************************************//**
549
The following function is used to get the number of records owned by the
550
previous directory record.
551
@return number of owned records */
556
const rec_t* rec) /*!< in: new-style physical record */
558
return(rec_get_bit_field_1(rec, REC_NEW_N_OWNED,
559
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT));
562
/******************************************************//**
563
The following function is used to set the number of owned records. */
568
rec_t* rec, /*!< in/out: new-style physical record */
569
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
570
ulint n_owned)/*!< in: the number of owned */
572
rec_set_bit_field_1(rec, n_owned, REC_NEW_N_OWNED,
573
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
574
if (UNIV_LIKELY_NULL(page_zip)
575
&& UNIV_LIKELY(rec_get_status(rec)
576
!= REC_STATUS_SUPREMUM)) {
577
page_zip_rec_set_owned(page_zip, rec, n_owned);
581
/******************************************************//**
582
The following function is used to retrieve the info bits of a record.
588
const rec_t* rec, /*!< in: physical record */
589
ulint comp) /*!< in: nonzero=compact page format */
591
return(rec_get_bit_field_1(
592
rec, comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
593
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT));
596
/******************************************************//**
597
The following function is used to set the info bits of a record. */
600
rec_set_info_bits_old(
601
/*==================*/
602
rec_t* rec, /*!< in: old-style physical record */
603
ulint bits) /*!< in: info bits */
605
rec_set_bit_field_1(rec, bits, REC_OLD_INFO_BITS,
606
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
608
/******************************************************//**
609
The following function is used to set the info bits of a record. */
612
rec_set_info_bits_new(
613
/*==================*/
614
rec_t* rec, /*!< in/out: new-style physical record */
615
ulint bits) /*!< in: info bits */
617
rec_set_bit_field_1(rec, bits, REC_NEW_INFO_BITS,
618
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
621
/******************************************************//**
622
The following function is used to set the status bits of a new-style record. */
627
rec_t* rec, /*!< in/out: physical record */
628
ulint bits) /*!< in: info bits */
630
rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
631
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
634
/******************************************************//**
635
The following function is used to retrieve the info and status
636
bits of a record. (Only compact records have status bits.)
640
rec_get_info_and_status_bits(
641
/*=========================*/
642
const rec_t* rec, /*!< in: physical record */
643
ulint comp) /*!< in: nonzero=compact page format */
646
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
647
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
648
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
650
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
651
bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
653
bits = rec_get_info_bits(rec, FALSE);
654
ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
658
/******************************************************//**
659
The following function is used to set the info and status
660
bits of a record. (Only compact records have status bits.) */
663
rec_set_info_and_status_bits(
664
/*=========================*/
665
rec_t* rec, /*!< in/out: physical record */
666
ulint bits) /*!< in: info bits */
668
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
669
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
670
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
672
rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
673
rec_set_info_bits_new(rec, bits & ~REC_NEW_STATUS_MASK);
676
/******************************************************//**
677
The following function tells if record is delete marked.
678
@return nonzero if delete marked */
681
rec_get_deleted_flag(
682
/*=================*/
683
const rec_t* rec, /*!< in: physical record */
684
ulint comp) /*!< in: nonzero=compact page format */
686
if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
687
return(UNIV_UNLIKELY(
688
rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
689
REC_INFO_DELETED_FLAG,
690
REC_INFO_BITS_SHIFT)));
692
return(UNIV_UNLIKELY(
693
rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
694
REC_INFO_DELETED_FLAG,
695
REC_INFO_BITS_SHIFT)));
699
/******************************************************//**
700
The following function is used to set the deleted bit. */
703
rec_set_deleted_flag_old(
704
/*=====================*/
705
rec_t* rec, /*!< in: old-style physical record */
706
ulint flag) /*!< in: nonzero if delete marked */
710
val = rec_get_info_bits(rec, FALSE);
713
val |= REC_INFO_DELETED_FLAG;
715
val &= ~REC_INFO_DELETED_FLAG;
718
rec_set_info_bits_old(rec, val);
721
/******************************************************//**
722
The following function is used to set the deleted bit. */
725
rec_set_deleted_flag_new(
726
/*=====================*/
727
rec_t* rec, /*!< in/out: new-style physical record */
728
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
729
ulint flag) /*!< in: nonzero if delete marked */
733
val = rec_get_info_bits(rec, TRUE);
736
val |= REC_INFO_DELETED_FLAG;
738
val &= ~REC_INFO_DELETED_FLAG;
741
rec_set_info_bits_new(rec, val);
743
if (UNIV_LIKELY_NULL(page_zip)) {
744
page_zip_rec_set_deleted(page_zip, rec, flag);
748
/******************************************************//**
749
The following function tells if a new-style record is a node pointer.
750
@return TRUE if node pointer */
753
rec_get_node_ptr_flag(
754
/*==================*/
755
const rec_t* rec) /*!< in: physical record */
757
return(REC_STATUS_NODE_PTR == rec_get_status(rec));
760
/******************************************************//**
761
The following function is used to get the order number
762
of an old-style record in the heap of the index page.
763
@return heap order number */
768
const rec_t* rec) /*!< in: physical record */
770
return(rec_get_bit_field_2(rec, REC_OLD_HEAP_NO,
771
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT));
774
/******************************************************//**
775
The following function is used to set the heap number
776
field in an old-style record. */
781
rec_t* rec, /*!< in: physical record */
782
ulint heap_no)/*!< in: the heap number */
784
rec_set_bit_field_2(rec, heap_no, REC_OLD_HEAP_NO,
785
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
788
/******************************************************//**
789
The following function is used to get the order number
790
of a new-style record in the heap of the index page.
791
@return heap order number */
796
const rec_t* rec) /*!< in: physical record */
798
return(rec_get_bit_field_2(rec, REC_NEW_HEAP_NO,
799
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT));
802
/******************************************************//**
803
The following function is used to set the heap number
804
field in a new-style record. */
809
rec_t* rec, /*!< in/out: physical record */
810
ulint heap_no)/*!< in: the heap number */
812
rec_set_bit_field_2(rec, heap_no, REC_NEW_HEAP_NO,
813
REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
816
/******************************************************//**
817
The following function is used to test whether the data offsets in the record
818
are stored in one-byte or two-byte format.
819
@return TRUE if 1-byte form */
822
rec_get_1byte_offs_flag(
823
/*====================*/
824
const rec_t* rec) /*!< in: physical record */
830
return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
831
REC_OLD_SHORT_SHIFT));
834
/******************************************************//**
835
The following function is used to set the 1-byte offsets flag. */
838
rec_set_1byte_offs_flag(
839
/*====================*/
840
rec_t* rec, /*!< in: physical record */
841
ibool flag) /*!< in: TRUE if 1byte form */
848
rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
849
REC_OLD_SHORT_SHIFT);
852
/******************************************************//**
853
Returns the offset of nth field end if the record is stored in the 1-byte
854
offsets form. If the field is SQL null, the flag is ORed in the returned
856
@return offset of the start of the field, SQL null flag ORed */
859
rec_1_get_field_end_info(
860
/*=====================*/
861
const rec_t* rec, /*!< in: record */
862
ulint n) /*!< in: field index */
864
ut_ad(rec_get_1byte_offs_flag(rec));
865
ut_ad(n < rec_get_n_fields_old(rec));
867
return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
870
/******************************************************//**
871
Returns the offset of nth field end if the record is stored in the 2-byte
872
offsets form. If the field is SQL null, the flag is ORed in the returned
874
@return offset of the start of the field, SQL null flag and extern
878
rec_2_get_field_end_info(
879
/*=====================*/
880
const rec_t* rec, /*!< in: record */
881
ulint n) /*!< in: field index */
883
ut_ad(!rec_get_1byte_offs_flag(rec));
884
ut_ad(n < rec_get_n_fields_old(rec));
886
return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
889
/* Get the base address of offsets. The extra_size is stored at
890
this position, and following positions hold the end offsets of
892
#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
894
/**********************************************************//**
895
The following function returns the number of allocated elements
896
for an array of offsets.
897
@return number of elements */
900
rec_offs_get_n_alloc(
901
/*=================*/
902
const ulint* offsets)/*!< in: array for rec_get_offsets() */
906
n_alloc = offsets[0];
907
ut_ad(n_alloc > REC_OFFS_HEADER_SIZE);
908
UNIV_MEM_ASSERT_W(offsets, n_alloc * sizeof *offsets);
912
/**********************************************************//**
913
The following function sets the number of allocated elements
914
for an array of offsets. */
917
rec_offs_set_n_alloc(
918
/*=================*/
919
ulint* offsets, /*!< out: array for rec_get_offsets(),
921
ulint n_alloc) /*!< in: number of elements */
924
ut_ad(n_alloc > REC_OFFS_HEADER_SIZE);
925
UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
926
offsets[0] = n_alloc;
929
/**********************************************************//**
930
The following function returns the number of fields in a record.
931
@return number of fields */
936
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
940
n_fields = offsets[1];
942
ut_ad(n_fields <= REC_MAX_N_FIELDS);
943
ut_ad(n_fields + REC_OFFS_HEADER_SIZE
944
<= rec_offs_get_n_alloc(offsets));
948
/************************************************************//**
949
Validates offsets returned by rec_get_offsets().
950
@return TRUE if valid */
955
const rec_t* rec, /*!< in: record or NULL */
956
const dict_index_t* index, /*!< in: record descriptor or NULL */
957
const ulint* offsets)/*!< in: array returned by
960
ulint i = rec_offs_n_fields(offsets);
961
ulint last = ULINT_MAX;
962
ulint comp = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
965
ut_ad((ulint) rec == offsets[2]);
967
ut_a(rec_get_n_fields_old(rec) >= i);
972
ut_ad((ulint) index == offsets[3]);
973
max_n_fields = ut_max(
974
dict_index_get_n_fields(index),
975
dict_index_get_n_unique_in_tree(index) + 1);
977
switch (rec_get_status(rec)) {
978
case REC_STATUS_ORDINARY:
980
case REC_STATUS_NODE_PTR:
981
max_n_fields = dict_index_get_n_unique_in_tree(
984
case REC_STATUS_INFIMUM:
985
case REC_STATUS_SUPREMUM:
992
/* index->n_def == 0 for dummy indexes if !comp */
993
ut_a(!comp || index->n_def);
994
ut_a(!index->n_def || i <= max_n_fields);
997
ulint curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
1004
/************************************************************//**
1005
Updates debug data in offsets, in order to avoid bogus
1006
rec_offs_validate() failures. */
1009
rec_offs_make_valid(
1010
/*================*/
1011
const rec_t* rec, /*!< in: record */
1012
const dict_index_t* index, /*!< in: record descriptor */
1013
ulint* offsets)/*!< in: array returned by
1014
rec_get_offsets() */
1019
ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
1020
offsets[2] = (ulint) rec;
1021
offsets[3] = (ulint) index;
1023
#endif /* UNIV_DEBUG */
1025
/************************************************************//**
1026
The following function is used to get an offset to the nth
1027
data field in a record.
1028
@return offset from the origin of rec */
1031
rec_get_nth_field_offs(
1032
/*===================*/
1033
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1034
ulint n, /*!< in: index of the field */
1035
ulint* len) /*!< out: length of the field; UNIV_SQL_NULL
1040
ut_ad(n < rec_offs_n_fields(offsets));
1043
if (UNIV_UNLIKELY(n == 0)) {
1046
offs = rec_offs_base(offsets)[n] & REC_OFFS_MASK;
1049
length = rec_offs_base(offsets)[1 + n];
1051
if (length & REC_OFFS_SQL_NULL) {
1052
length = UNIV_SQL_NULL;
1054
length &= REC_OFFS_MASK;
1062
/******************************************************//**
1063
Determine if the offsets are for a record in the new
1065
@return nonzero if compact format */
1070
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1072
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1073
return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
1076
/******************************************************//**
1077
Determine if the offsets are for a record containing
1078
externally stored columns.
1079
@return nonzero if externally stored */
1082
rec_offs_any_extern(
1083
/*================*/
1084
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1086
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1087
return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL));
1090
/******************************************************//**
1091
Returns nonzero if the extern bit is set in nth field of rec.
1092
@return nonzero if externally stored */
1095
rec_offs_nth_extern(
1096
/*================*/
1097
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1098
ulint n) /*!< in: nth field */
1100
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1101
ut_ad(n < rec_offs_n_fields(offsets));
1102
return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
1103
& REC_OFFS_EXTERNAL));
1106
/******************************************************//**
1107
Returns nonzero if the SQL NULL bit is set in nth field of rec.
1108
@return nonzero if SQL NULL */
1111
rec_offs_nth_sql_null(
1112
/*==================*/
1113
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1114
ulint n) /*!< in: nth field */
1116
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1117
ut_ad(n < rec_offs_n_fields(offsets));
1118
return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
1119
& REC_OFFS_SQL_NULL));
1122
/******************************************************//**
1123
Gets the physical size of a field.
1124
@return length of field */
1129
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1130
ulint n) /*!< in: nth field */
1132
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1133
ut_ad(n < rec_offs_n_fields(offsets));
1135
return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
1137
return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
1141
/******************************************************//**
1142
Returns the number of extern bits set in a record.
1143
@return number of externally stored fields */
1148
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1152
if (rec_offs_any_extern(offsets)) {
1155
for (i = rec_offs_n_fields(offsets); i--; ) {
1156
if (rec_offs_nth_extern(offsets, i)) {
1165
/******************************************************//**
1166
Returns the offset of n - 1th field end if the record is stored in the 1-byte
1167
offsets form. If the field is SQL null, the flag is ORed in the returned
1168
value. This function and the 2-byte counterpart are defined here because the
1169
C-compiler was not able to sum negative and positive constant offsets, and
1170
warned of constant arithmetic overflow within the compiler.
1171
@return offset of the start of the PREVIOUS field, SQL null flag ORed */
1174
rec_1_get_prev_field_end_info(
1175
/*==========================*/
1176
const rec_t* rec, /*!< in: record */
1177
ulint n) /*!< in: field index */
1179
ut_ad(rec_get_1byte_offs_flag(rec));
1180
ut_ad(n <= rec_get_n_fields_old(rec));
1182
return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
1185
/******************************************************//**
1186
Returns the offset of n - 1th field end if the record is stored in the 2-byte
1187
offsets form. If the field is SQL null, the flag is ORed in the returned
1189
@return offset of the start of the PREVIOUS field, SQL null flag ORed */
1192
rec_2_get_prev_field_end_info(
1193
/*==========================*/
1194
const rec_t* rec, /*!< in: record */
1195
ulint n) /*!< in: field index */
1197
ut_ad(!rec_get_1byte_offs_flag(rec));
1198
ut_ad(n <= rec_get_n_fields_old(rec));
1200
return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
1203
/******************************************************//**
1204
Sets the field end info for the nth field if the record is stored in the
1208
rec_1_set_field_end_info(
1209
/*=====================*/
1210
rec_t* rec, /*!< in: record */
1211
ulint n, /*!< in: field index */
1212
ulint info) /*!< in: value to set */
1214
ut_ad(rec_get_1byte_offs_flag(rec));
1215
ut_ad(n < rec_get_n_fields_old(rec));
1217
mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
1220
/******************************************************//**
1221
Sets the field end info for the nth field if the record is stored in the
1225
rec_2_set_field_end_info(
1226
/*=====================*/
1227
rec_t* rec, /*!< in: record */
1228
ulint n, /*!< in: field index */
1229
ulint info) /*!< in: value to set */
1231
ut_ad(!rec_get_1byte_offs_flag(rec));
1232
ut_ad(n < rec_get_n_fields_old(rec));
1234
mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
1237
/******************************************************//**
1238
Returns the offset of nth field start if the record is stored in the 1-byte
1240
@return offset of the start of the field */
1243
rec_1_get_field_start_offs(
1244
/*=======================*/
1245
const rec_t* rec, /*!< in: record */
1246
ulint n) /*!< in: field index */
1248
ut_ad(rec_get_1byte_offs_flag(rec));
1249
ut_ad(n <= rec_get_n_fields_old(rec));
1256
return(rec_1_get_prev_field_end_info(rec, n)
1257
& ~REC_1BYTE_SQL_NULL_MASK);
1260
/******************************************************//**
1261
Returns the offset of nth field start if the record is stored in the 2-byte
1263
@return offset of the start of the field */
1266
rec_2_get_field_start_offs(
1267
/*=======================*/
1268
const rec_t* rec, /*!< in: record */
1269
ulint n) /*!< in: field index */
1271
ut_ad(!rec_get_1byte_offs_flag(rec));
1272
ut_ad(n <= rec_get_n_fields_old(rec));
1279
return(rec_2_get_prev_field_end_info(rec, n)
1280
& ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
1283
/******************************************************//**
1284
The following function is used to read the offset of the start of a data field
1285
in the record. The start of an SQL null field is the end offset of the
1286
previous non-null field, or 0, if none exists. If n is the number of the last
1287
field + 1, then the end offset of the last field is returned.
1288
@return offset of the start of the field */
1291
rec_get_field_start_offs(
1292
/*=====================*/
1293
const rec_t* rec, /*!< in: record */
1294
ulint n) /*!< in: field index */
1297
ut_ad(n <= rec_get_n_fields_old(rec));
1304
if (rec_get_1byte_offs_flag(rec)) {
1306
return(rec_1_get_field_start_offs(rec, n));
1309
return(rec_2_get_field_start_offs(rec, n));
1312
/************************************************************//**
1313
Gets the physical size of an old-style field.
1314
Also an SQL null may have a field of size > 0,
1315
if the data type is of a fixed size.
1316
@return field size in bytes */
1319
rec_get_nth_field_size(
1320
/*===================*/
1321
const rec_t* rec, /*!< in: record */
1322
ulint n) /*!< in: index of the field */
1327
os = rec_get_field_start_offs(rec, n);
1328
next_os = rec_get_field_start_offs(rec, n + 1);
1330
ut_ad(next_os - os < UNIV_PAGE_SIZE);
1332
return(next_os - os);
1335
/***********************************************************//**
1336
This is used to modify the value of an already existing field in a record.
1337
The previous value must have exactly the same size as the new value. If len
1338
is UNIV_SQL_NULL then the field is treated as an SQL null.
1339
For records in ROW_FORMAT=COMPACT (new-style records), len must not be
1340
UNIV_SQL_NULL unless the field already is SQL null. */
1345
rec_t* rec, /*!< in: record */
1346
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1347
ulint n, /*!< in: index number of the field */
1348
const void* data, /*!< in: pointer to the data
1350
ulint len) /*!< in: length of the data or UNIV_SQL_NULL */
1356
ut_ad(rec_offs_validate(rec, NULL, offsets));
1358
if (UNIV_UNLIKELY(len == UNIV_SQL_NULL)) {
1359
if (!rec_offs_nth_sql_null(offsets, n)) {
1360
ut_a(!rec_offs_comp(offsets));
1361
rec_set_nth_field_sql_null(rec, n);
1367
data2 = rec_get_nth_field(rec, offsets, n, &len2);
1368
if (len2 == UNIV_SQL_NULL) {
1369
ut_ad(!rec_offs_comp(offsets));
1370
rec_set_nth_field_null_bit(rec, n, FALSE);
1371
ut_ad(len == rec_get_nth_field_size(rec, n));
1376
ut_memcpy(data2, data, len);
1379
/**********************************************************//**
1380
The following function returns the data size of an old-style physical
1381
record, that is the sum of field lengths. SQL null fields
1382
are counted as length 0 fields. The value returned by the function
1383
is the distance from record origin to record end in bytes.
1387
rec_get_data_size_old(
1388
/*==================*/
1389
const rec_t* rec) /*!< in: physical record */
1393
return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
1396
/**********************************************************//**
1397
The following function sets the number of fields in offsets. */
1400
rec_offs_set_n_fields(
1401
/*==================*/
1402
ulint* offsets, /*!< in/out: array returned by
1403
rec_get_offsets() */
1404
ulint n_fields) /*!< in: number of fields */
1407
ut_ad(n_fields > 0);
1408
ut_ad(n_fields <= REC_MAX_N_FIELDS);
1409
ut_ad(n_fields + REC_OFFS_HEADER_SIZE
1410
<= rec_offs_get_n_alloc(offsets));
1411
offsets[1] = n_fields;
1414
/**********************************************************//**
1415
The following function returns the data size of a physical
1416
record, that is the sum of field lengths. SQL null fields
1417
are counted as length 0 fields. The value returned by the function
1418
is the distance from record origin to record end in bytes.
1424
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1428
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1429
size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
1431
ut_ad(size < UNIV_PAGE_SIZE);
1435
/**********************************************************//**
1436
Returns the total size of record minus data size of record. The value
1437
returned by the function is the distance from record start to record origin
1442
rec_offs_extra_size(
1443
/*================*/
1444
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1447
ut_ad(rec_offs_validate(NULL, NULL, offsets));
1448
size = *rec_offs_base(offsets) & ~(REC_OFFS_COMPACT | REC_OFFS_EXTERNAL);
1449
ut_ad(size < UNIV_PAGE_SIZE);
1453
/**********************************************************//**
1454
Returns the total size of a physical record.
1460
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1462
return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
1465
/**********************************************************//**
1466
Returns a pointer to the end of the record.
1467
@return pointer to end */
1472
rec_t* rec, /*!< in: pointer to record */
1473
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1475
ut_ad(rec_offs_validate(rec, NULL, offsets));
1476
return(rec + rec_offs_data_size(offsets));
1479
/**********************************************************//**
1480
Returns a pointer to the start of the record.
1481
@return pointer to start */
1486
rec_t* rec, /*!< in: pointer to record */
1487
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1489
ut_ad(rec_offs_validate(rec, NULL, offsets));
1490
return(rec - rec_offs_extra_size(offsets));
1493
/***************************************************************//**
1494
Copies a physical record to a buffer.
1495
@return pointer to the origin of the copy */
1500
void* buf, /*!< in: buffer */
1501
const rec_t* rec, /*!< in: physical record */
1502
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1508
ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
1509
ut_ad(rec_validate(rec, offsets));
1511
extra_len = rec_offs_extra_size(offsets);
1512
data_len = rec_offs_data_size(offsets);
1514
ut_memcpy(buf, rec - extra_len, extra_len + data_len);
1516
return((byte*)buf + extra_len);
1519
/**********************************************************//**
1520
Returns the extra size of an old-style physical record if we know its
1521
data size and number of fields.
1522
@return extra size */
1525
rec_get_converted_extra_size(
1526
/*=========================*/
1527
ulint data_size, /*!< in: data size */
1528
ulint n_fields, /*!< in: number of fields */
1529
ulint n_ext) /*!< in: number of externally stored columns */
1531
if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1533
return(REC_N_OLD_EXTRA_BYTES + n_fields);
1536
return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
1539
/**********************************************************//**
1540
The following function returns the size of a data tuple when converted to
1545
rec_get_converted_size(
1546
/*===================*/
1547
dict_index_t* index, /*!< in: record descriptor */
1548
const dtuple_t* dtuple, /*!< in: data tuple */
1549
ulint n_ext) /*!< in: number of externally stored columns */
1556
ut_ad(dtuple_check_typed(dtuple));
1558
ut_ad(index->type & DICT_UNIVERSAL
1559
|| dtuple_get_n_fields(dtuple)
1560
== (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
1561
== REC_STATUS_NODE_PTR)
1562
? dict_index_get_n_unique_in_tree(index) + 1
1563
: dict_index_get_n_fields(index)));
1565
if (dict_table_is_comp(index->table)) {
1566
return(rec_get_converted_size_comp(index,
1567
dtuple_get_info_bits(dtuple)
1568
& REC_NEW_STATUS_MASK,
1570
dtuple->n_fields, NULL));
1573
data_size = dtuple_get_data_size(dtuple, 0);
1575
extra_size = rec_get_converted_extra_size(
1576
data_size, dtuple_get_n_fields(dtuple), n_ext);
1578
return(data_size + extra_size);
1581
#ifndef UNIV_HOTBACKUP
1582
/************************************************************//**
1583
Folds a prefix of a physical record to a ulint. Folds only existing fields,
1584
that is, checks that we do not run out of the record.
1585
@return the folded value */
1590
const rec_t* rec, /*!< in: the physical record */
1591
const ulint* offsets, /*!< in: array returned by
1592
rec_get_offsets() */
1593
ulint n_fields, /*!< in: number of complete
1595
ulint n_bytes, /*!< in: number of bytes to fold
1596
in an incomplete last field */
1597
index_id_t tree_id) /*!< in: index tree id */
1605
ut_ad(rec_offs_validate(rec, NULL, offsets));
1606
ut_ad(rec_validate(rec, offsets));
1607
ut_ad(n_fields + n_bytes > 0);
1609
n_fields_rec = rec_offs_n_fields(offsets);
1610
ut_ad(n_fields <= n_fields_rec);
1611
ut_ad(n_fields < n_fields_rec || n_bytes == 0);
1613
if (n_fields > n_fields_rec) {
1614
n_fields = n_fields_rec;
1617
if (n_fields == n_fields_rec) {
1621
fold = ut_fold_ull(tree_id);
1623
for (i = 0; i < n_fields; i++) {
1624
data = rec_get_nth_field(rec, offsets, i, &len);
1626
if (len != UNIV_SQL_NULL) {
1627
fold = ut_fold_ulint_pair(fold,
1628
ut_fold_binary(data, len));
1633
data = rec_get_nth_field(rec, offsets, i, &len);
1635
if (len != UNIV_SQL_NULL) {
1636
if (len > n_bytes) {
1640
fold = ut_fold_ulint_pair(fold,
1641
ut_fold_binary(data, len));
1647
#endif /* !UNIV_HOTBACKUP */