1
/*****************************************************************************
3
Copyright (C) 1994, 2010, 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
/********************************************************************//**
23
Created 5/30/1994 Heikki Tuuri
24
*************************************************************************/
35
/* PHYSICAL RECORD (OLD STYLE)
36
===========================
38
The physical record, which is the data type of all the records
39
found in index pages of the database, has the following format
40
(lower addresses and more significant bits inside a byte are below
41
represented on a higher text line):
43
| offset of the end of the last field of data, the most significant
44
bit is set to 1 if and only if the field is SQL-null,
45
if the offset is 2-byte, then the second most significant
46
bit is set to 1 if the field is stored on another page:
47
mostly this will occur in the case of big BLOB fields |
49
| offset of the end of the first field of data + the SQL-null bit |
50
| 4 bits used to delete mark a record, and mark a predefined
51
minimum record in alphabetical order |
52
| 4 bits giving the number of records owned by this record
53
(this term is explained in page0page.h) |
54
| 13 bits giving the order number of this record in the
55
heap of the index page |
56
| 10 bits giving the number of fields in this record |
57
| 1 bit which is set to 1 if the offsets above are given in
58
one byte format, 0 if in two byte format |
59
| two bytes giving an absolute pointer to the next record in the page |
61
| first field of data |
63
| last field of data |
65
The origin of the record is the start address of the first field
66
of data. The offsets are given relative to the origin.
67
The offsets of the data fields are stored in an inverted
68
order because then the offset of the first fields are near the
69
origin, giving maybe a better processor cache hit rate in searches.
71
The offsets of the data fields are given as one-byte
72
(if there are less than 127 bytes of data in the record)
73
or two-byte unsigned integers. The most significant bit
74
is not part of the offset, instead it indicates the SQL-null
75
if the bit is set to 1. */
77
/* PHYSICAL RECORD (NEW STYLE)
78
===========================
80
The physical record, which is the data type of all the records
81
found in index pages of the database, has the following format
82
(lower addresses and more significant bits inside a byte are below
83
represented on a higher text line):
85
| length of the last non-null variable-length field of data:
86
if the maximum length is 255, one byte; otherwise,
87
0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
88
length=128..16383, extern storage flag) |
90
| length of first variable-length field of data |
91
| SQL-null flags (1 bit per nullable field), padded to full bytes |
92
| 4 bits used to delete mark a record, and mark a predefined
93
minimum record in alphabetical order |
94
| 4 bits giving the number of records owned by this record
95
(this term is explained in page0page.h) |
96
| 13 bits giving the order number of this record in the
97
heap of the index page |
98
| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
99
010=infimum, 011=supremum, 1xx=reserved |
100
| two bytes giving a relative pointer to the next record in the page |
102
| first field of data |
104
| last field of data |
106
The origin of the record is the start address of the first field
107
of data. The offsets are given relative to the origin.
108
The offsets of the data fields are stored in an inverted
109
order because then the offset of the first fields are near the
110
origin, giving maybe a better processor cache hit rate in searches.
112
The offsets of the data fields are given as one-byte
113
(if there are less than 127 bytes of data in the record)
114
or two-byte unsigned integers. The most significant bit
115
is not part of the offset, instead it indicates the SQL-null
116
if the bit is set to 1. */
118
/* CANONICAL COORDINATES. A record can be seen as a single
119
string of 'characters' in the following way: catenate the bytes
120
in each field, in the order of fields. An SQL-null field
121
is taken to be an empty sequence of bytes. Then after
122
the position of each field insert in the string
123
the 'character' <FIELD-END>, except that after an SQL-null field
124
insert <NULL-FIELD-END>. Now the ordinal position of each
125
byte in this canonical string is its canonical coordinate.
126
So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
127
string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
128
We identify prefixes (= initial segments) of a record
129
with prefixes of the canonical string. The canonical
130
length of the prefix is the length of the corresponding
131
prefix of the canonical string. The canonical length of
132
a record is the length of its canonical string.
134
For example, the maximal common prefix of records
135
("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
136
is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
139
A complete-field prefix of a record is a prefix which ends at the
140
end of some field (containing also <FIELD-END>).
141
A record is a complete-field prefix of another record, if
142
the corresponding canonical strings have the same property. */
144
/* this is used to fool compiler in rec_validate */
145
UNIV_INTERN ulint rec_dummy;
147
/***************************************************************//**
148
Validates the consistency of an old-style physical record.
149
@return TRUE if ok */
154
const rec_t* rec); /*!< in: physical record */
156
/******************************************************//**
157
Determine how many of the first n columns in a compact
158
physical record are stored externally.
159
@return number of externally stored columns */
162
rec_get_n_extern_new(
163
/*=================*/
164
const rec_t* rec, /*!< in: compact physical record */
165
dict_index_t* index, /*!< in: record descriptor */
166
ulint n) /*!< in: number of columns to scan */
175
ut_ad(dict_table_is_comp(index->table));
176
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
177
ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
179
if (n == ULINT_UNDEFINED) {
180
n = dict_index_get_n_fields(index);
183
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
184
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
189
/* read the lengths of fields 0..n */
193
field = dict_index_get_nth_field(index, i);
194
if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
195
/* nullable field => read the null flag */
197
if (UNIV_UNLIKELY(!(byte) null_mask)) {
202
if (*nulls & null_mask) {
204
/* No length is stored for NULL fields. */
210
if (UNIV_UNLIKELY(!field->fixed_len)) {
211
/* Variable-length field: read the length */
212
const dict_col_t* col
213
= dict_field_get_col(field);
215
/* If the maximum length of the field is up
216
to 255 bytes, the actual length is always
217
stored in one byte. If the maximum length is
218
more than 255 bytes, the actual length is
219
stored in one byte for 0..127. The length
220
will be encoded in two bytes when it is 128 or
221
more, or when the field is stored externally. */
222
if (UNIV_UNLIKELY(col->len > 255)
223
|| UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
225
/* 1exxxxxxx xxxxxxxx */
238
/******************************************************//**
239
Determine the offset to each field in a leaf-page record
240
in ROW_FORMAT=COMPACT. This is a special case of
241
rec_init_offsets() and rec_get_offsets_func(). */
244
rec_init_offsets_comp_ordinary(
245
/*===========================*/
246
const rec_t* rec, /*!< in: physical record in
247
ROW_FORMAT=COMPACT */
248
ulint extra, /*!< in: number of bytes to reserve
249
between the record header and
251
(usually REC_N_NEW_EXTRA_BYTES) */
252
const dict_index_t* index, /*!< in: record descriptor */
253
ulint* offsets)/*!< in/out: array of offsets;
254
in: n=rec_offs_n_fields(offsets) */
259
const byte* nulls = rec - (extra + 1);
260
const byte* lens = nulls
261
- UT_BITS_IN_BYTES(index->n_nullable);
266
/* We cannot invoke rec_offs_make_valid() here, because it can hold
267
that extra != REC_N_NEW_EXTRA_BYTES. Similarly, rec_offs_validate()
268
will fail in that case, because it invokes rec_get_status(). */
269
offsets[2] = (ulint) rec;
270
offsets[3] = (ulint) index;
271
#endif /* UNIV_DEBUG */
273
/* read the lengths of fields 0..n */
277
field = dict_index_get_nth_field(index, i);
278
if (!(dict_field_get_col(field)->prtype
280
/* nullable field => read the null flag */
282
if (UNIV_UNLIKELY(!(byte) null_mask)) {
287
if (*nulls & null_mask) {
289
/* No length is stored for NULL fields.
290
We do not advance offs, and we set
291
the length to zero and enable the
292
SQL NULL flag in offsets[]. */
293
len = offs | REC_OFFS_SQL_NULL;
299
if (UNIV_UNLIKELY(!field->fixed_len)) {
300
/* Variable-length field: read the length */
301
const dict_col_t* col
302
= dict_field_get_col(field);
304
/* If the maximum length of the field is up
305
to 255 bytes, the actual length is always
306
stored in one byte. If the maximum length is
307
more than 255 bytes, the actual length is
308
stored in one byte for 0..127. The length
309
will be encoded in two bytes when it is 128 or
310
more, or when the field is stored externally. */
311
if (UNIV_UNLIKELY(col->len > 255)
312
|| UNIV_UNLIKELY(col->mtype
315
/* 1exxxxxxx xxxxxxxx */
319
offs += len & 0x3fff;
320
if (UNIV_UNLIKELY(len
322
ut_ad(dict_index_is_clust
324
any_ext = REC_OFFS_EXTERNAL;
337
len = offs += field->fixed_len;
340
rec_offs_base(offsets)[i + 1] = len;
341
} while (++i < rec_offs_n_fields(offsets));
343
*rec_offs_base(offsets)
344
= (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
347
/******************************************************//**
348
The following function determines the offsets to each field in the
349
record. The offsets are written to a previously allocated array of
350
ulint, where rec_offs_n_fields(offsets) has been initialized to the
351
number of fields in the record. The rest of the array will be
352
initialized by this function. rec_offs_base(offsets)[0] will be set
353
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
354
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
355
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
356
offsets past the end of fields 0..n_fields, or to the beginning of
357
fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
358
is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
359
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
360
field i is being stored externally. */
365
const rec_t* rec, /*!< in: physical record */
366
const dict_index_t* index, /*!< in: record descriptor */
367
ulint* offsets)/*!< in/out: array of offsets;
368
in: n=rec_offs_n_fields(offsets) */
373
rec_offs_make_valid(rec, index, offsets);
375
if (dict_table_is_comp(index->table)) {
380
ulint status = rec_get_status(rec);
381
ulint n_node_ptr_field = ULINT_UNDEFINED;
383
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
384
case REC_STATUS_INFIMUM:
385
case REC_STATUS_SUPREMUM:
386
/* the field is 8 bytes long */
387
rec_offs_base(offsets)[0]
388
= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
389
rec_offs_base(offsets)[1] = 8;
391
case REC_STATUS_NODE_PTR:
393
= dict_index_get_n_unique_in_tree(index);
395
case REC_STATUS_ORDINARY:
396
rec_init_offsets_comp_ordinary(rec,
397
REC_N_NEW_EXTRA_BYTES,
402
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
403
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
407
/* read the lengths of fields 0..n */
410
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
415
field = dict_index_get_nth_field(index, i);
416
if (!(dict_field_get_col(field)->prtype
418
/* nullable field => read the null flag */
420
if (UNIV_UNLIKELY(!(byte) null_mask)) {
425
if (*nulls & null_mask) {
427
/* No length is stored for NULL fields.
428
We do not advance offs, and we set
429
the length to zero and enable the
430
SQL NULL flag in offsets[]. */
431
len = offs | REC_OFFS_SQL_NULL;
437
if (UNIV_UNLIKELY(!field->fixed_len)) {
438
/* Variable-length field: read the length */
439
const dict_col_t* col
440
= dict_field_get_col(field);
442
/* If the maximum length of the field
443
is up to 255 bytes, the actual length
444
is always stored in one byte. If the
445
maximum length is more than 255 bytes,
446
the actual length is stored in one
447
byte for 0..127. The length will be
448
encoded in two bytes when it is 128 or
449
more, or when the field is stored
451
if (UNIV_UNLIKELY(col->len > 255)
452
|| UNIV_UNLIKELY(col->mtype
455
/* 1exxxxxxx xxxxxxxx */
460
/* B-tree node pointers
461
must not contain externally
463
the "e" flag must be 0. */
464
ut_a(!(len & 0x4000));
465
offs += len & 0x3fff;
474
len = offs += field->fixed_len;
477
rec_offs_base(offsets)[i + 1] = len;
478
} while (++i < rec_offs_n_fields(offsets));
480
*rec_offs_base(offsets)
481
= (rec - (lens + 1)) | REC_OFFS_COMPACT;
483
/* Old-style record: determine extra size and end offsets */
484
offs = REC_N_OLD_EXTRA_BYTES;
485
if (rec_get_1byte_offs_flag(rec)) {
486
offs += rec_offs_n_fields(offsets);
487
*rec_offs_base(offsets) = offs;
488
/* Determine offsets to fields */
490
offs = rec_1_get_field_end_info(rec, i);
491
if (offs & REC_1BYTE_SQL_NULL_MASK) {
492
offs &= ~REC_1BYTE_SQL_NULL_MASK;
493
offs |= REC_OFFS_SQL_NULL;
495
rec_offs_base(offsets)[1 + i] = offs;
496
} while (++i < rec_offs_n_fields(offsets));
498
offs += 2 * rec_offs_n_fields(offsets);
499
*rec_offs_base(offsets) = offs;
500
/* Determine offsets to fields */
502
offs = rec_2_get_field_end_info(rec, i);
503
if (offs & REC_2BYTE_SQL_NULL_MASK) {
504
offs &= ~REC_2BYTE_SQL_NULL_MASK;
505
offs |= REC_OFFS_SQL_NULL;
507
if (offs & REC_2BYTE_EXTERN_MASK) {
508
offs &= ~REC_2BYTE_EXTERN_MASK;
509
offs |= REC_OFFS_EXTERNAL;
510
*rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
512
rec_offs_base(offsets)[1 + i] = offs;
513
} while (++i < rec_offs_n_fields(offsets));
518
/******************************************************//**
519
The following function determines the offsets to each field
520
in the record. It can reuse a previously returned array.
521
@return the new offsets */
524
rec_get_offsets_func(
525
/*=================*/
526
const rec_t* rec, /*!< in: physical record */
527
const dict_index_t* index, /*!< in: record descriptor */
528
ulint* offsets,/*!< in/out: array consisting of
529
offsets[0] allocated elements,
530
or an array from rec_get_offsets(),
532
ulint n_fields,/*!< in: maximum number of
534
(ULINT_UNDEFINED if all fields) */
535
mem_heap_t** heap, /*!< in/out: memory heap */
536
const char* file, /*!< in: file name where called */
537
ulint line) /*!< in: line number where called */
546
if (dict_table_is_comp(index->table)) {
547
switch (UNIV_EXPECT(rec_get_status(rec),
548
REC_STATUS_ORDINARY)) {
549
case REC_STATUS_ORDINARY:
550
n = dict_index_get_n_fields(index);
552
case REC_STATUS_NODE_PTR:
553
n = dict_index_get_n_unique_in_tree(index) + 1;
555
case REC_STATUS_INFIMUM:
556
case REC_STATUS_SUPREMUM:
557
/* infimum or supremum record */
565
n = rec_get_n_fields_old(rec);
568
if (UNIV_UNLIKELY(n_fields < n)) {
572
size = n + (1 + REC_OFFS_HEADER_SIZE);
574
if (UNIV_UNLIKELY(!offsets)
575
|| UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
576
if (UNIV_UNLIKELY(!*heap)) {
577
*heap = mem_heap_create_func(size * sizeof(ulint),
581
offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
582
rec_offs_set_n_alloc(offsets, size);
585
rec_offs_set_n_fields(offsets, n);
586
rec_init_offsets(rec, index, offsets);
590
/******************************************************//**
591
The following function determines the offsets to each field
592
in the record. It can reuse a previously allocated array. */
595
rec_get_offsets_reverse(
596
/*====================*/
597
const byte* extra, /*!< in: the extra bytes of a
598
compact record in reverse order,
599
excluding the fixed-size
600
REC_N_NEW_EXTRA_BYTES */
601
const dict_index_t* index, /*!< in: record descriptor */
602
ulint node_ptr,/*!< in: nonzero=node pointer,
604
ulint* offsets)/*!< in/out: array consisting of
605
offsets[0] allocated elements */
615
ulint n_node_ptr_field;
620
ut_ad(dict_table_is_comp(index->table));
622
if (UNIV_UNLIKELY(node_ptr)) {
623
n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
624
n = n_node_ptr_field + 1;
626
n_node_ptr_field = ULINT_UNDEFINED;
627
n = dict_index_get_n_fields(index);
630
ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
631
rec_offs_set_n_fields(offsets, n);
634
lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
639
/* read the lengths of fields 0..n */
642
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
647
field = dict_index_get_nth_field(index, i);
648
if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
649
/* nullable field => read the null flag */
651
if (UNIV_UNLIKELY(!(byte) null_mask)) {
656
if (*nulls & null_mask) {
658
/* No length is stored for NULL fields.
659
We do not advance offs, and we set
660
the length to zero and enable the
661
SQL NULL flag in offsets[]. */
662
len = offs | REC_OFFS_SQL_NULL;
668
if (UNIV_UNLIKELY(!field->fixed_len)) {
669
/* Variable-length field: read the length */
670
const dict_col_t* col
671
= dict_field_get_col(field);
673
/* If the maximum length of the field is up
674
to 255 bytes, the actual length is always
675
stored in one byte. If the maximum length is
676
more than 255 bytes, the actual length is
677
stored in one byte for 0..127. The length
678
will be encoded in two bytes when it is 128 or
679
more, or when the field is stored externally. */
680
if (UNIV_UNLIKELY(col->len > 255)
681
|| UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
683
/* 1exxxxxxx xxxxxxxx */
687
offs += len & 0x3fff;
688
if (UNIV_UNLIKELY(len & 0x4000)) {
689
any_ext = REC_OFFS_EXTERNAL;
690
len = offs | REC_OFFS_EXTERNAL;
701
len = offs += field->fixed_len;
704
rec_offs_base(offsets)[i + 1] = len;
705
} while (++i < rec_offs_n_fields(offsets));
707
ut_ad(lens >= extra);
708
*rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
709
| REC_OFFS_COMPACT | any_ext;
712
/************************************************************//**
713
The following function is used to get the offset to the nth
714
data field in an old-style record.
715
@return offset to the field */
718
rec_get_nth_field_offs_old(
719
/*=======================*/
720
const rec_t* rec, /*!< in: record */
721
ulint n, /*!< in: index of the field */
722
ulint* len) /*!< out: length of the field;
723
UNIV_SQL_NULL if SQL null */
730
ut_a(n < rec_get_n_fields_old(rec));
732
if (rec_get_1byte_offs_flag(rec)) {
733
os = rec_1_get_field_start_offs(rec, n);
735
next_os = rec_1_get_field_end_info(rec, n);
737
if (next_os & REC_1BYTE_SQL_NULL_MASK) {
738
*len = UNIV_SQL_NULL;
743
next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
745
os = rec_2_get_field_start_offs(rec, n);
747
next_os = rec_2_get_field_end_info(rec, n);
749
if (next_os & REC_2BYTE_SQL_NULL_MASK) {
750
*len = UNIV_SQL_NULL;
755
next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
756
| REC_2BYTE_EXTERN_MASK);
761
ut_ad(*len < UNIV_PAGE_SIZE);
766
/**********************************************************//**
767
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
768
@return total size */
771
rec_get_converted_size_comp_prefix(
772
/*===============================*/
773
const dict_index_t* index, /*!< in: record descriptor;
774
dict_table_is_comp() is
775
assumed to hold, even if
777
const dfield_t* fields, /*!< in: array of data fields */
778
ulint n_fields,/*!< in: number of data fields */
779
ulint* extra) /*!< out: extra size */
787
ut_ad(n_fields <= dict_index_get_n_fields(index));
789
extra_size = REC_N_NEW_EXTRA_BYTES
790
+ UT_BITS_IN_BYTES(index->n_nullable);
793
/* read the lengths of fields 0..n */
794
for (i = 0; i < n_fields; i++) {
795
const dict_field_t* field;
797
const dict_col_t* col;
799
field = dict_index_get_nth_field(index, i);
800
len = dfield_get_len(&fields[i]);
801
col = dict_field_get_col(field);
803
ut_ad(dict_col_type_assert_equal(col,
804
dfield_get_type(&fields[i])));
806
if (dfield_is_null(&fields[i])) {
807
/* No length is stored for NULL fields. */
808
ut_ad(!(col->prtype & DATA_NOT_NULL));
812
ut_ad(len <= col->len || col->mtype == DATA_BLOB);
814
/* If the maximum length of a variable-length field
815
is up to 255 bytes, the actual length is always stored
816
in one byte. If the maximum length is more than 255
817
bytes, the actual length is stored in one byte for
818
0..127. The length will be encoded in two bytes when
819
it is 128 or more, or when the field is stored externally. */
821
if (field->fixed_len) {
822
ut_ad(len == field->fixed_len);
823
/* dict_index_add_col() should guarantee this */
824
ut_ad(!field->prefix_len
825
|| field->fixed_len == field->prefix_len);
826
} else if (dfield_is_ext(&fields[i])) {
827
ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
830
|| (col->len < 256 && col->mtype != DATA_BLOB)) {
833
/* For variable-length columns, we look up the
834
maximum length from the column itself. If this
835
is a prefix index column shorter than 256 bytes,
836
this will waste one byte. */
842
if (UNIV_LIKELY_NULL(extra)) {
846
return(extra_size + data_size);
849
/**********************************************************//**
850
Determines the size of a data tuple in ROW_FORMAT=COMPACT.
851
@return total size */
854
rec_get_converted_size_comp(
855
/*========================*/
856
const dict_index_t* index, /*!< in: record descriptor;
857
dict_table_is_comp() is
858
assumed to hold, even if
860
ulint status, /*!< in: status bits of the record */
861
const dfield_t* fields, /*!< in: array of data fields */
862
ulint n_fields,/*!< in: number of data fields */
863
ulint* extra) /*!< out: extra size */
870
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
871
case REC_STATUS_ORDINARY:
872
ut_ad(n_fields == dict_index_get_n_fields(index));
875
case REC_STATUS_NODE_PTR:
877
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
878
ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
879
size = REC_NODE_PTR_SIZE; /* child page number */
881
case REC_STATUS_INFIMUM:
882
case REC_STATUS_SUPREMUM:
883
/* infimum or supremum record, 8 data bytes */
884
if (UNIV_LIKELY_NULL(extra)) {
885
*extra = REC_N_NEW_EXTRA_BYTES;
887
return(REC_N_NEW_EXTRA_BYTES + 8);
890
return(ULINT_UNDEFINED);
893
return(size + rec_get_converted_size_comp_prefix(index, fields,
897
/***********************************************************//**
898
Sets the value of the ith field SQL null bit of an old-style record. */
901
rec_set_nth_field_null_bit(
902
/*=======================*/
903
rec_t* rec, /*!< in: record */
904
ulint i, /*!< in: ith field */
905
ibool val) /*!< in: value to set */
909
if (rec_get_1byte_offs_flag(rec)) {
911
info = rec_1_get_field_end_info(rec, i);
914
info = info | REC_1BYTE_SQL_NULL_MASK;
916
info = info & ~REC_1BYTE_SQL_NULL_MASK;
919
rec_1_set_field_end_info(rec, i, info);
924
info = rec_2_get_field_end_info(rec, i);
927
info = info | REC_2BYTE_SQL_NULL_MASK;
929
info = info & ~REC_2BYTE_SQL_NULL_MASK;
932
rec_2_set_field_end_info(rec, i, info);
935
/***********************************************************//**
936
Sets an old-style record field to SQL null.
937
The physical size of the field is not changed. */
940
rec_set_nth_field_sql_null(
941
/*=======================*/
942
rec_t* rec, /*!< in: record */
943
ulint n) /*!< in: index of the field */
947
offset = rec_get_field_start_offs(rec, n);
949
data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
951
rec_set_nth_field_null_bit(rec, n, TRUE);
954
/*********************************************************//**
955
Builds an old-style physical record out of a data tuple and
956
stores it beginning from the start of the given buffer.
957
@return pointer to the origin of physical record */
960
rec_convert_dtuple_to_rec_old(
961
/*==========================*/
962
byte* buf, /*!< in: start address of the physical record */
963
const dtuple_t* dtuple, /*!< in: data tuple */
964
ulint n_ext) /*!< in: number of externally stored columns */
966
const dfield_t* field;
975
ut_ad(buf && dtuple);
976
ut_ad(dtuple_validate(dtuple));
977
ut_ad(dtuple_check_typed(dtuple));
979
n_fields = dtuple_get_n_fields(dtuple);
980
data_size = dtuple_get_data_size(dtuple, 0);
984
/* Calculate the offset of the origin in the physical record */
986
rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
988
/* Suppress Valgrind warnings of ut_ad()
989
in mach_write_to_1(), mach_write_to_2() et al. */
990
memset(buf, 0xff, rec - buf + data_size);
991
#endif /* UNIV_DEBUG */
992
/* Store the number of fields */
993
rec_set_n_fields_old(rec, n_fields);
995
/* Set the info bits of the record */
996
rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
997
& REC_INFO_BITS_MASK);
999
/* Store the data and the offsets */
1003
if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1005
rec_set_1byte_offs_flag(rec, TRUE);
1007
for (i = 0; i < n_fields; i++) {
1009
field = dtuple_get_nth_field(dtuple, i);
1011
if (dfield_is_null(field)) {
1012
len = dtype_get_sql_null_size(
1013
dfield_get_type(field), 0);
1014
data_write_sql_null(rec + end_offset, len);
1017
ored_offset = end_offset
1018
| REC_1BYTE_SQL_NULL_MASK;
1020
/* If the data is not SQL null, store it */
1021
len = dfield_get_len(field);
1023
memcpy(rec + end_offset,
1024
dfield_get_data(field), len);
1027
ored_offset = end_offset;
1030
rec_1_set_field_end_info(rec, i, ored_offset);
1033
rec_set_1byte_offs_flag(rec, FALSE);
1035
for (i = 0; i < n_fields; i++) {
1037
field = dtuple_get_nth_field(dtuple, i);
1039
if (dfield_is_null(field)) {
1040
len = dtype_get_sql_null_size(
1041
dfield_get_type(field), 0);
1042
data_write_sql_null(rec + end_offset, len);
1045
ored_offset = end_offset
1046
| REC_2BYTE_SQL_NULL_MASK;
1048
/* If the data is not SQL null, store it */
1049
len = dfield_get_len(field);
1051
memcpy(rec + end_offset,
1052
dfield_get_data(field), len);
1055
ored_offset = end_offset;
1057
if (dfield_is_ext(field)) {
1058
ored_offset |= REC_2BYTE_EXTERN_MASK;
1062
rec_2_set_field_end_info(rec, i, ored_offset);
1069
/*********************************************************//**
1070
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1073
rec_convert_dtuple_to_rec_comp(
1074
/*===========================*/
1075
rec_t* rec, /*!< in: origin of record */
1076
ulint extra, /*!< in: number of bytes to
1077
reserve between the record
1078
header and the data payload
1079
(normally REC_N_NEW_EXTRA_BYTES) */
1080
const dict_index_t* index, /*!< in: record descriptor */
1081
ulint status, /*!< in: status bits of the record */
1082
const dfield_t* fields, /*!< in: array of data fields */
1083
ulint n_fields)/*!< in: number of data fields */
1085
const dfield_t* field;
1086
const dtype_t* type;
1092
ulint n_node_ptr_field;
1094
ulint null_mask = 1;
1095
ut_ad(extra == 0 || dict_table_is_comp(index->table));
1096
ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
1097
ut_ad(n_fields > 0);
1099
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1100
case REC_STATUS_ORDINARY:
1101
ut_ad(n_fields <= dict_index_get_n_fields(index));
1102
n_node_ptr_field = ULINT_UNDEFINED;
1104
case REC_STATUS_NODE_PTR:
1105
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1106
n_node_ptr_field = n_fields - 1;
1108
case REC_STATUS_INFIMUM:
1109
case REC_STATUS_SUPREMUM:
1110
ut_ad(n_fields == 1);
1111
n_node_ptr_field = ULINT_UNDEFINED;
1119
nulls = rec - (extra + 1);
1120
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1121
/* clear the SQL-null flags */
1122
memset(lens + 1, 0, nulls - lens);
1124
/* Store the data and the offsets */
1126
for (i = 0, field = fields; i < n_fields; i++, field++) {
1127
const dict_field_t* ifield;
1129
type = dfield_get_type(field);
1130
len = dfield_get_len(field);
1132
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1133
ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1135
memcpy(end, dfield_get_data(field), len);
1140
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1141
/* nullable field */
1142
ut_ad(index->n_nullable > 0);
1144
if (UNIV_UNLIKELY(!(byte) null_mask)) {
1149
ut_ad(*nulls < null_mask);
1151
/* set the null flag if necessary */
1152
if (dfield_is_null(field)) {
1153
*nulls |= null_mask;
1160
/* only nullable fields can be null */
1161
ut_ad(!dfield_is_null(field));
1163
ifield = dict_index_get_nth_field(index, i);
1164
fixed_len = ifield->fixed_len;
1165
/* If the maximum length of a variable-length field
1166
is up to 255 bytes, the actual length is always stored
1167
in one byte. If the maximum length is more than 255
1168
bytes, the actual length is stored in one byte for
1169
0..127. The length will be encoded in two bytes when
1170
it is 128 or more, or when the field is stored externally. */
1172
ut_ad(len == fixed_len);
1173
ut_ad(!dfield_is_ext(field));
1174
} else if (dfield_is_ext(field)) {
1175
ut_ad(ifield->col->len >= 256
1176
|| ifield->col->mtype == DATA_BLOB);
1177
ut_ad(len <= REC_MAX_INDEX_COL_LEN
1178
+ BTR_EXTERN_FIELD_REF_SIZE);
1179
*lens-- = (byte) (len >> 8) | 0xc0;
1180
*lens-- = (byte) len;
1182
ut_ad(len <= dtype_get_len(type)
1183
|| dtype_get_mtype(type) == DATA_BLOB);
1185
|| (dtype_get_len(type) < 256
1186
&& dtype_get_mtype(type) != DATA_BLOB)) {
1188
*lens-- = (byte) len;
1191
*lens-- = (byte) (len >> 8) | 0x80;
1192
*lens-- = (byte) len;
1196
memcpy(end, dfield_get_data(field), len);
1201
/*********************************************************//**
1202
Builds a new-style physical record out of a data tuple and
1203
stores it beginning from the start of the given buffer.
1204
@return pointer to the origin of physical record */
1207
rec_convert_dtuple_to_rec_new(
1208
/*==========================*/
1209
byte* buf, /*!< in: start address of
1210
the physical record */
1211
const dict_index_t* index, /*!< in: record descriptor */
1212
const dtuple_t* dtuple) /*!< in: data tuple */
1218
status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1219
rec_get_converted_size_comp(index, status,
1220
dtuple->fields, dtuple->n_fields,
1222
rec = buf + extra_size;
1224
rec_convert_dtuple_to_rec_comp(
1225
rec, REC_N_NEW_EXTRA_BYTES, index, status,
1226
dtuple->fields, dtuple->n_fields);
1228
/* Set the info bits of the record */
1229
rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1234
/*********************************************************//**
1235
Builds a physical record out of a data tuple and
1236
stores it beginning from the start of the given buffer.
1237
@return pointer to the origin of physical record */
1240
rec_convert_dtuple_to_rec(
1241
/*======================*/
1242
byte* buf, /*!< in: start address of the
1244
const dict_index_t* index, /*!< in: record descriptor */
1245
const dtuple_t* dtuple, /*!< in: data tuple */
1246
ulint n_ext) /*!< in: number of
1247
externally stored columns */
1251
ut_ad(buf && index && dtuple);
1252
ut_ad(dtuple_validate(dtuple));
1253
ut_ad(dtuple_check_typed(dtuple));
1255
if (dict_table_is_comp(index->table)) {
1256
rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1258
rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1263
mem_heap_t* heap = NULL;
1264
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1265
const ulint* offsets;
1267
rec_offs_init(offsets_);
1269
offsets = rec_get_offsets(rec, index,
1270
offsets_, ULINT_UNDEFINED, &heap);
1271
ut_ad(rec_validate(rec, offsets));
1272
ut_ad(dtuple_get_n_fields(dtuple)
1273
== rec_offs_n_fields(offsets));
1275
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1276
ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
1277
== !rec_offs_nth_extern(offsets, i));
1280
if (UNIV_LIKELY_NULL(heap)) {
1281
mem_heap_free(heap);
1284
#endif /* UNIV_DEBUG */
1288
/**************************************************************//**
1289
Copies the first n fields of a physical record to a data tuple. The fields
1290
are copied to the memory heap. */
1293
rec_copy_prefix_to_dtuple(
1294
/*======================*/
1295
dtuple_t* tuple, /*!< out: data tuple */
1296
const rec_t* rec, /*!< in: physical record */
1297
const dict_index_t* index, /*!< in: record descriptor */
1298
ulint n_fields, /*!< in: number of fields
1300
mem_heap_t* heap) /*!< in: memory heap */
1303
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1304
ulint* offsets = offsets_;
1305
rec_offs_init(offsets_);
1307
offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1309
ut_ad(rec_validate(rec, offsets));
1310
ut_ad(dtuple_check_typed(tuple));
1312
dtuple_set_info_bits(tuple, rec_get_info_bits(
1313
rec, dict_table_is_comp(index->table)));
1315
for (i = 0; i < n_fields; i++) {
1320
field = dtuple_get_nth_field(tuple, i);
1321
data = rec_get_nth_field(rec, offsets, i, &len);
1323
if (len != UNIV_SQL_NULL) {
1324
dfield_set_data(field,
1325
mem_heap_dup(heap, data, len), len);
1326
ut_ad(!rec_offs_nth_extern(offsets, i));
1328
dfield_set_null(field);
1333
/**************************************************************//**
1334
Copies the first n fields of an old-style physical record
1335
to a new physical record in a buffer.
1336
@return own: copied record */
1339
rec_copy_prefix_to_buf_old(
1340
/*=======================*/
1341
const rec_t* rec, /*!< in: physical record */
1342
ulint n_fields, /*!< in: number of fields to copy */
1343
ulint area_end, /*!< in: end of the prefix data */
1344
byte** buf, /*!< in/out: memory buffer for
1345
the copied prefix, or NULL */
1346
ulint* buf_size) /*!< in/out: buffer size */
1352
if (rec_get_1byte_offs_flag(rec)) {
1353
area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1355
area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1358
prefix_len = area_start + area_end;
1360
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1365
*buf = mem_alloc2(prefix_len, buf_size);
1368
ut_memcpy(*buf, rec - area_start, prefix_len);
1370
copy_rec = *buf + area_start;
1372
rec_set_n_fields_old(copy_rec, n_fields);
1377
/**************************************************************//**
1378
Copies the first n fields of a physical record to a new physical record in
1380
@return own: copied record */
1383
rec_copy_prefix_to_buf(
1384
/*===================*/
1385
const rec_t* rec, /*!< in: physical record */
1386
const dict_index_t* index, /*!< in: record descriptor */
1387
ulint n_fields, /*!< in: number of fields
1389
byte** buf, /*!< in/out: memory buffer
1390
for the copied prefix,
1392
ulint* buf_size) /*!< in/out: buffer size */
1401
UNIV_PREFETCH_RW(*buf);
1403
if (!dict_table_is_comp(index->table)) {
1404
ut_ad(rec_validate_old(rec));
1405
return(rec_copy_prefix_to_buf_old(
1407
rec_get_field_start_offs(rec, n_fields),
1411
status = rec_get_status(rec);
1414
case REC_STATUS_ORDINARY:
1415
ut_ad(n_fields <= dict_index_get_n_fields(index));
1417
case REC_STATUS_NODE_PTR:
1418
/* it doesn't make sense to copy the child page number field */
1419
ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1421
case REC_STATUS_INFIMUM:
1422
case REC_STATUS_SUPREMUM:
1423
/* infimum or supremum record: no sense to copy anything */
1429
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1430
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1431
UNIV_PREFETCH_R(lens);
1435
/* read the lengths of fields 0..n */
1436
for (i = 0; i < n_fields; i++) {
1437
const dict_field_t* field;
1438
const dict_col_t* col;
1440
field = dict_index_get_nth_field(index, i);
1441
col = dict_field_get_col(field);
1443
if (!(col->prtype & DATA_NOT_NULL)) {
1444
/* nullable field => read the null flag */
1445
if (UNIV_UNLIKELY(!(byte) null_mask)) {
1450
if (*nulls & null_mask) {
1458
if (field->fixed_len) {
1459
prefix_len += field->fixed_len;
1461
ulint len = *lens--;
1462
/* If the maximum length of the column is up
1463
to 255 bytes, the actual length is always
1464
stored in one byte. If the maximum length is
1465
more than 255 bytes, the actual length is
1466
stored in one byte for 0..127. The length
1467
will be encoded in two bytes when it is 128 or
1468
more, or when the column is stored externally. */
1469
if (col->len > 255 || col->mtype == DATA_BLOB) {
1475
UNIV_PREFETCH_R(lens);
1482
UNIV_PREFETCH_R(rec + prefix_len);
1484
prefix_len += rec - (lens + 1);
1486
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1491
*buf = mem_alloc2(prefix_len, buf_size);
1494
memcpy(*buf, lens + 1, prefix_len);
1496
return(*buf + (rec - (lens + 1)));
1499
/***************************************************************//**
1500
Validates the consistency of an old-style physical record.
1501
@return TRUE if ok */
1506
const rec_t* rec) /*!< in: physical record */
1516
n_fields = rec_get_n_fields_old(rec);
1518
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1519
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1524
for (i = 0; i < n_fields; i++) {
1525
data = rec_get_nth_field_old(rec, i, &len);
1527
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1529
"InnoDB: Error: record field %lu len %lu\n",
1535
if (len != UNIV_SQL_NULL) {
1537
sum += *(data + len -1); /* dereference the
1542
len_sum += rec_get_nth_field_size(rec, i);
1546
if (len_sum != rec_get_data_size_old(rec)) {
1548
"InnoDB: Error: record len should be %lu, len %lu\n",
1550
rec_get_data_size_old(rec));
1554
rec_dummy = sum; /* This is here only to fool the compiler */
1559
/***************************************************************//**
1560
Validates the consistency of a physical record.
1561
@return TRUE if ok */
1566
const rec_t* rec, /*!< in: physical record */
1567
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1577
n_fields = rec_offs_n_fields(offsets);
1579
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1580
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1585
ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1587
for (i = 0; i < n_fields; i++) {
1588
data = rec_get_nth_field(rec, offsets, i, &len);
1590
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1592
"InnoDB: Error: record field %lu len %lu\n",
1598
if (len != UNIV_SQL_NULL) {
1600
sum += *(data + len -1); /* dereference the
1604
} else if (!rec_offs_comp(offsets)) {
1605
len_sum += rec_get_nth_field_size(rec, i);
1609
if (len_sum != rec_offs_data_size(offsets)) {
1611
"InnoDB: Error: record len should be %lu, len %lu\n",
1613
(ulong) rec_offs_data_size(offsets));
1617
rec_dummy = sum; /* This is here only to fool the compiler */
1619
if (!rec_offs_comp(offsets)) {
1620
ut_a(rec_validate_old(rec));
1626
/***************************************************************//**
1627
Prints an old-style physical record. */
1632
FILE* file, /*!< in: file where to print */
1633
const rec_t* rec) /*!< in: physical record */
1642
n = rec_get_n_fields_old(rec);
1644
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1645
" %u-byte offsets; info bits %lu\n",
1647
rec_get_1byte_offs_flag(rec) ? 1 : 2,
1648
(ulong) rec_get_info_bits(rec, FALSE));
1650
for (i = 0; i < n; i++) {
1652
data = rec_get_nth_field_old(rec, i, &len);
1654
fprintf(file, " %lu:", (ulong) i);
1656
if (len != UNIV_SQL_NULL) {
1659
ut_print_buf(file, data, len);
1661
ut_print_buf(file, data, 30);
1663
fprintf(file, " (total %lu bytes)",
1667
fprintf(file, " SQL NULL, size %lu ",
1668
rec_get_nth_field_size(rec, i));
1675
rec_validate_old(rec);
1678
#ifndef UNIV_HOTBACKUP
1679
/***************************************************************//**
1680
Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
1686
FILE* file, /*!< in: file where to print */
1687
const rec_t* rec, /*!< in: physical record */
1688
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1692
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1696
data = rec_get_nth_field(rec, offsets, i, &len);
1698
fprintf(file, " %lu:", (ulong) i);
1700
if (len != UNIV_SQL_NULL) {
1703
ut_print_buf(file, data, len);
1705
ut_print_buf(file, data, 30);
1707
fprintf(file, " (total %lu bytes)",
1711
fputs(" SQL NULL", file);
1718
/***************************************************************//**
1719
Prints a physical record. */
1724
FILE* file, /*!< in: file where to print */
1725
const rec_t* rec, /*!< in: physical record */
1726
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1730
ut_ad(rec_offs_validate(rec, NULL, offsets));
1732
if (!rec_offs_comp(offsets)) {
1733
rec_print_old(file, rec);
1737
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1738
" compact format; info bits %lu\n",
1739
(ulong) rec_offs_n_fields(offsets),
1740
(ulong) rec_get_info_bits(rec, TRUE));
1742
rec_print_comp(file, rec, offsets);
1743
rec_validate(rec, offsets);
1746
/***************************************************************//**
1747
Prints a physical record. */
1752
FILE* file, /*!< in: file where to print */
1753
const rec_t* rec, /*!< in: physical record */
1754
dict_index_t* index) /*!< in: record descriptor */
1758
if (!dict_table_is_comp(index->table)) {
1759
rec_print_old(file, rec);
1762
mem_heap_t* heap = NULL;
1763
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1764
rec_offs_init(offsets_);
1766
rec_print_new(file, rec,
1767
rec_get_offsets(rec, index, offsets_,
1768
ULINT_UNDEFINED, &heap));
1769
if (UNIV_LIKELY_NULL(heap)) {
1770
mem_heap_free(heap);
1774
#endif /* !UNIV_HOTBACKUP */