1
/************************************************************************
4
(c) 1994-2001 Innobase Oy
6
Created 5/30/1994 Heikki Tuuri
7
*************************************************************************/
18
/* PHYSICAL RECORD (OLD STYLE)
19
===========================
21
The physical record, which is the data type of all the records
22
found in index pages of the database, has the following format
23
(lower addresses and more significant bits inside a byte are below
24
represented on a higher text line):
26
| offset of the end of the last field of data, the most significant
27
bit is set to 1 if and only if the field is SQL-null,
28
if the offset is 2-byte, then the second most significant
29
bit is set to 1 if the field is stored on another page:
30
mostly this will occur in the case of big BLOB fields |
32
| offset of the end of the first field of data + the SQL-null bit |
33
| 4 bits used to delete mark a record, and mark a predefined
34
minimum record in alphabetical order |
35
| 4 bits giving the number of records owned by this record
36
(this term is explained in page0page.h) |
37
| 13 bits giving the order number of this record in the
38
heap of the index page |
39
| 10 bits giving the number of fields in this record |
40
| 1 bit which is set to 1 if the offsets above are given in
41
one byte format, 0 if in two byte format |
42
| two bytes giving an absolute pointer to the next record in the page |
44
| first field of data |
46
| last field of data |
48
The origin of the record is the start address of the first field
49
of data. The offsets are given relative to the origin.
50
The offsets of the data fields are stored in an inverted
51
order because then the offset of the first fields are near the
52
origin, giving maybe a better processor cache hit rate in searches.
54
The offsets of the data fields are given as one-byte
55
(if there are less than 127 bytes of data in the record)
56
or two-byte unsigned integers. The most significant bit
57
is not part of the offset, instead it indicates the SQL-null
58
if the bit is set to 1. */
60
/* PHYSICAL RECORD (NEW STYLE)
61
===========================
63
The physical record, which is the data type of all the records
64
found in index pages of the database, has the following format
65
(lower addresses and more significant bits inside a byte are below
66
represented on a higher text line):
68
| length of the last non-null variable-length field of data:
69
if the maximum length is 255, one byte; otherwise,
70
0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
71
length=128..16383, extern storage flag) |
73
| length of first variable-length field of data |
74
| SQL-null flags (1 bit per nullable field), padded to full bytes |
75
| 4 bits used to delete mark a record, and mark a predefined
76
minimum record in alphabetical order |
77
| 4 bits giving the number of records owned by this record
78
(this term is explained in page0page.h) |
79
| 13 bits giving the order number of this record in the
80
heap of the index page |
81
| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
82
010=infimum, 011=supremum, 1xx=reserved |
83
| two bytes giving a relative pointer to the next record in the page |
85
| first field of data |
87
| last field of data |
89
The origin of the record is the start address of the first field
90
of data. The offsets are given relative to the origin.
91
The offsets of the data fields are stored in an inverted
92
order because then the offset of the first fields are near the
93
origin, giving maybe a better processor cache hit rate in searches.
95
The offsets of the data fields are given as one-byte
96
(if there are less than 127 bytes of data in the record)
97
or two-byte unsigned integers. The most significant bit
98
is not part of the offset, instead it indicates the SQL-null
99
if the bit is set to 1. */
101
/* CANONICAL COORDINATES. A record can be seen as a single
102
string of 'characters' in the following way: catenate the bytes
103
in each field, in the order of fields. An SQL-null field
104
is taken to be an empty sequence of bytes. Then after
105
the position of each field insert in the string
106
the 'character' <FIELD-END>, except that after an SQL-null field
107
insert <NULL-FIELD-END>. Now the ordinal position of each
108
byte in this canonical string is its canonical coordinate.
109
So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
110
string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
111
We identify prefixes (= initial segments) of a record
112
with prefixes of the canonical string. The canonical
113
length of the prefix is the length of the corresponding
114
prefix of the canonical string. The canonical length of
115
a record is the length of its canonical string.
117
For example, the maximal common prefix of records
118
("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
119
is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
122
A complete-field prefix of a record is a prefix which ends at the
123
end of some field (containing also <FIELD-END>).
124
A record is a complete-field prefix of another record, if
125
the corresponding canonical strings have the same property. */
127
ulint rec_dummy; /* this is used to fool compiler in
130
/*******************************************************************
131
Validates the consistency of an old-style physical record. */
136
/* out: TRUE if ok */
137
rec_t* rec); /* in: physical record */
139
/**********************************************************
140
The following function determines the offsets to each field in the
141
record. The offsets are written to a previously allocated array of
142
ulint, where rec_offs_n_fields(offsets) has been initialized to the
143
number of fields in the record. The rest of the array will be
144
initialized by this function. rec_offs_base(offsets)[0] will be set
145
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
146
new format), and rec_offs_base(offsets)[1..n_fields] will be set to
147
offsets past the end of fields 0..n_fields, or to the beginning of
148
fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
149
is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
150
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
151
field i is being stored externally. */
156
rec_t* rec, /* in: physical record */
157
dict_index_t* index, /* in: record descriptor */
158
ulint* offsets)/* in/out: array of offsets;
159
in: n=rec_offs_n_fields(offsets) */
164
rec_offs_make_valid(rec, index, offsets);
166
if (dict_table_is_comp(index->table)) {
171
ulint status = rec_get_status(rec);
172
ulint n_node_ptr_field = ULINT_UNDEFINED;
174
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
175
case REC_STATUS_INFIMUM:
176
case REC_STATUS_SUPREMUM:
177
/* the field is 8 bytes long */
178
rec_offs_base(offsets)[0]
179
= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
180
rec_offs_base(offsets)[1] = 8;
182
case REC_STATUS_NODE_PTR:
184
= dict_index_get_n_unique_in_tree(index);
186
case REC_STATUS_ORDINARY:
190
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
191
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
195
/* read the lengths of fields 0..n */
198
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
203
field = dict_index_get_nth_field(index, i);
204
if (!(dict_field_get_col(field)->prtype
206
/* nullable field => read the null flag */
208
if (UNIV_UNLIKELY(!(byte) null_mask)) {
213
if (*nulls & null_mask) {
215
/* No length is stored for NULL fields.
216
We do not advance offs, and we set
217
the length to zero and enable the
218
SQL NULL flag in offsets[]. */
219
len = offs | REC_OFFS_SQL_NULL;
225
if (UNIV_UNLIKELY(!field->fixed_len)) {
226
/* Variable-length field: read the length */
227
const dict_col_t* col
228
= dict_field_get_col(field);
230
if (UNIV_UNLIKELY(col->len > 255)
231
|| UNIV_UNLIKELY(col->mtype
234
/* 1exxxxxxx xxxxxxxx */
238
offs += len & 0x3fff;
239
if (UNIV_UNLIKELY(len
253
len = offs += field->fixed_len;
256
rec_offs_base(offsets)[i + 1] = len;
257
} while (++i < rec_offs_n_fields(offsets));
259
*rec_offs_base(offsets)
260
= (rec - (lens + 1)) | REC_OFFS_COMPACT;
262
/* Old-style record: determine extra size and end offsets */
263
offs = REC_N_OLD_EXTRA_BYTES;
264
if (rec_get_1byte_offs_flag(rec)) {
265
offs += rec_offs_n_fields(offsets);
266
*rec_offs_base(offsets) = offs;
267
/* Determine offsets to fields */
269
offs = rec_1_get_field_end_info(rec, i);
270
if (offs & REC_1BYTE_SQL_NULL_MASK) {
271
offs &= ~REC_1BYTE_SQL_NULL_MASK;
272
offs |= REC_OFFS_SQL_NULL;
274
rec_offs_base(offsets)[1 + i] = offs;
275
} while (++i < rec_offs_n_fields(offsets));
277
offs += 2 * rec_offs_n_fields(offsets);
278
*rec_offs_base(offsets) = offs;
279
/* Determine offsets to fields */
281
offs = rec_2_get_field_end_info(rec, i);
282
if (offs & REC_2BYTE_SQL_NULL_MASK) {
283
offs &= ~REC_2BYTE_SQL_NULL_MASK;
284
offs |= REC_OFFS_SQL_NULL;
286
if (offs & REC_2BYTE_EXTERN_MASK) {
287
offs &= ~REC_2BYTE_EXTERN_MASK;
288
offs |= REC_OFFS_EXTERNAL;
290
rec_offs_base(offsets)[1 + i] = offs;
291
} while (++i < rec_offs_n_fields(offsets));
296
/**********************************************************
297
The following function determines the offsets to each field
298
in the record. It can reuse a previously returned array. */
301
rec_get_offsets_func(
302
/*=================*/
303
/* out: the new offsets */
304
rec_t* rec, /* in: physical record */
305
dict_index_t* index, /* in: record descriptor */
306
ulint* offsets,/* in/out: array consisting of offsets[0]
307
allocated elements, or an array from
308
rec_get_offsets(), or NULL */
309
ulint n_fields,/* in: maximum number of initialized fields
310
(ULINT_UNDEFINED if all fields) */
311
mem_heap_t** heap, /* in/out: memory heap */
312
const char* file, /* in: file name where called */
313
ulint line) /* in: line number where called */
322
if (dict_table_is_comp(index->table)) {
323
switch (UNIV_EXPECT(rec_get_status(rec),
324
REC_STATUS_ORDINARY)) {
325
case REC_STATUS_ORDINARY:
326
n = dict_index_get_n_fields(index);
328
case REC_STATUS_NODE_PTR:
329
n = dict_index_get_n_unique_in_tree(index) + 1;
331
case REC_STATUS_INFIMUM:
332
case REC_STATUS_SUPREMUM:
333
/* infimum or supremum record */
341
n = rec_get_n_fields_old(rec);
344
if (UNIV_UNLIKELY(n_fields < n)) {
348
size = n + (1 + REC_OFFS_HEADER_SIZE);
350
if (UNIV_UNLIKELY(!offsets)
351
|| UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
353
*heap = mem_heap_create_func(size * sizeof(ulint),
354
NULL, MEM_HEAP_DYNAMIC,
357
offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
358
rec_offs_set_n_alloc(offsets, size);
361
rec_offs_set_n_fields(offsets, n);
362
rec_init_offsets(rec, index, offsets);
366
/****************************************************************
367
The following function is used to get a pointer to the nth
368
data field in an old-style record. */
371
rec_get_nth_field_old(
372
/*==================*/
373
/* out: pointer to the field */
374
rec_t* rec, /* in: record */
375
ulint n, /* in: index of the field */
376
ulint* len) /* out: length of the field; UNIV_SQL_NULL if SQL
383
ut_ad(n < rec_get_n_fields_old(rec));
385
if (n > REC_MAX_N_FIELDS) {
386
fprintf(stderr, "Error: trying to access field %lu in rec\n",
392
fputs("Error: rec is NULL pointer\n", stderr);
396
if (rec_get_1byte_offs_flag(rec)) {
397
os = rec_1_get_field_start_offs(rec, n);
399
next_os = rec_1_get_field_end_info(rec, n);
401
if (next_os & REC_1BYTE_SQL_NULL_MASK) {
402
*len = UNIV_SQL_NULL;
407
next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
409
os = rec_2_get_field_start_offs(rec, n);
411
next_os = rec_2_get_field_end_info(rec, n);
413
if (next_os & REC_2BYTE_SQL_NULL_MASK) {
414
*len = UNIV_SQL_NULL;
419
next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
420
| REC_2BYTE_EXTERN_MASK);
425
ut_ad(*len < UNIV_PAGE_SIZE);
430
/**************************************************************
431
The following function returns the size of a data tuple when converted to
432
a new-style physical record. */
435
rec_get_converted_size_new(
436
/*=======================*/
438
dict_index_t* index, /* in: record descriptor */
439
dtuple_t* dtuple) /* in: data tuple */
441
ulint size = REC_N_NEW_EXTRA_BYTES
442
+ UT_BITS_IN_BYTES(index->n_nullable);
445
ut_ad(index && dtuple);
446
ut_ad(dict_table_is_comp(index->table));
448
switch (dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK) {
449
case REC_STATUS_ORDINARY:
450
n_fields = dict_index_get_n_fields(index);
451
ut_ad(n_fields == dtuple_get_n_fields(dtuple));
453
case REC_STATUS_NODE_PTR:
454
n_fields = dict_index_get_n_unique_in_tree(index);
455
ut_ad(n_fields + 1 == dtuple_get_n_fields(dtuple));
456
ut_ad(dtuple_get_nth_field(dtuple, n_fields)->len == 4);
457
size += 4; /* child page number */
459
case REC_STATUS_INFIMUM:
460
case REC_STATUS_SUPREMUM:
461
/* infimum or supremum record, 8 data bytes */
462
return(REC_N_NEW_EXTRA_BYTES + 8);
465
return(ULINT_UNDEFINED);
468
/* read the lengths of fields 0..n */
469
for (i = 0; i < n_fields; i++) {
472
const dict_col_t* col;
474
field = dict_index_get_nth_field(index, i);
475
len = dtuple_get_nth_field(dtuple, i)->len;
476
col = dict_field_get_col(field);
478
ut_ad(dict_col_type_assert_equal(
479
col, dfield_get_type(dtuple_get_nth_field(
482
if (len == UNIV_SQL_NULL) {
483
/* No length is stored for NULL fields. */
484
ut_ad(!(col->prtype & DATA_NOT_NULL));
488
ut_ad(len <= col->len || col->mtype == DATA_BLOB);
490
if (field->fixed_len) {
491
ut_ad(len == field->fixed_len);
492
/* dict_index_add_col() should guarantee this */
493
ut_ad(!field->prefix_len
494
|| field->fixed_len == field->prefix_len);
496
|| (col->len < 256 && col->mtype != DATA_BLOB)) {
499
/* For variable-length columns, we look up the
500
maximum length from the column itself. If this
501
is a prefix index column shorter than 256 bytes,
502
this will waste one byte. */
511
/***************************************************************
512
Sets the value of the ith field SQL null bit of an old-style record. */
515
rec_set_nth_field_null_bit(
516
/*=======================*/
517
rec_t* rec, /* in: record */
518
ulint i, /* in: ith field */
519
ibool val) /* in: value to set */
523
if (rec_get_1byte_offs_flag(rec)) {
525
info = rec_1_get_field_end_info(rec, i);
528
info = info | REC_1BYTE_SQL_NULL_MASK;
530
info = info & ~REC_1BYTE_SQL_NULL_MASK;
533
rec_1_set_field_end_info(rec, i, info);
538
info = rec_2_get_field_end_info(rec, i);
541
info = info | REC_2BYTE_SQL_NULL_MASK;
543
info = info & ~REC_2BYTE_SQL_NULL_MASK;
546
rec_2_set_field_end_info(rec, i, info);
549
/***************************************************************
550
Sets the value of the ith field extern storage bit of an old-style record. */
553
rec_set_nth_field_extern_bit_old(
554
/*=============================*/
555
rec_t* rec, /* in: old-style record */
556
ulint i, /* in: ith field */
557
ibool val, /* in: value to set */
558
mtr_t* mtr) /* in: mtr holding an X-latch to the page where
559
rec is, or NULL; in the NULL case we do not
560
write to log about the change */
564
ut_a(!rec_get_1byte_offs_flag(rec));
565
ut_a(i < rec_get_n_fields_old(rec));
567
info = rec_2_get_field_end_info(rec, i);
570
info = info | REC_2BYTE_EXTERN_MASK;
572
info = info & ~REC_2BYTE_EXTERN_MASK;
576
mlog_write_ulint(rec - REC_N_OLD_EXTRA_BYTES - 2 * (i + 1),
577
info, MLOG_2BYTES, mtr);
579
rec_2_set_field_end_info(rec, i, info);
583
/***************************************************************
584
Sets the value of the ith field extern storage bit of a new-style record. */
587
rec_set_nth_field_extern_bit_new(
588
/*=============================*/
589
rec_t* rec, /* in: record */
590
dict_index_t* index, /* in: record descriptor */
591
ulint ith, /* in: ith field */
592
ibool val, /* in: value to set */
593
mtr_t* mtr) /* in: mtr holding an X-latch to the page
594
where rec is, or NULL; in the NULL case
595
we do not write to log about the change */
597
byte* nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
598
byte* lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
603
ut_ad(dict_table_is_comp(index->table));
604
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
606
n_fields = dict_index_get_n_fields(index);
608
ut_ad(ith < n_fields);
610
/* read the lengths of fields 0..n */
611
for (i = 0; i < n_fields; i++) {
612
const dict_field_t* field;
613
const dict_col_t* col;
615
field = dict_index_get_nth_field(index, i);
616
col = dict_field_get_col(field);
618
if (!(col->prtype & DATA_NOT_NULL)) {
619
if (UNIV_UNLIKELY(!(byte) null_mask)) {
624
if (*nulls & null_mask) {
626
/* NULL fields cannot be external. */
633
if (field->fixed_len) {
634
/* fixed-length fields cannot be external
635
(Fixed-length fields longer than
636
DICT_MAX_INDEX_COL_LEN will be treated as
637
variable-length ones in dict_index_add_col().) */
642
if (col->len > 255 || col->mtype == DATA_BLOB) {
644
if (len & 0x80) { /* 1exxxxxx: 2-byte length */
646
if (!val == !(len & 0x40)) {
647
return; /* no change */
649
/* toggle the extern bit */
652
mlog_write_ulint(lens + 1,
657
lens[1] = (byte) len;
663
/* short fields cannot be external */
667
/* short fields cannot be external */
673
/***************************************************************
674
Sets TRUE the extern storage bits of fields mentioned in an array. */
677
rec_set_field_extern_bits(
678
/*======================*/
679
rec_t* rec, /* in: record */
680
dict_index_t* index, /* in: record descriptor */
681
const ulint* vec, /* in: array of field numbers */
682
ulint n_fields,/* in: number of fields numbers */
683
mtr_t* mtr) /* in: mtr holding an X-latch to the
684
page where rec is, or NULL;
685
in the NULL case we do not write
686
to log about the change */
690
if (dict_table_is_comp(index->table)) {
691
for (i = 0; i < n_fields; i++) {
692
rec_set_nth_field_extern_bit_new(rec, index, vec[i],
696
for (i = 0; i < n_fields; i++) {
697
rec_set_nth_field_extern_bit_old(rec, vec[i],
703
/***************************************************************
704
Sets an old-style record field to SQL null.
705
The physical size of the field is not changed. */
708
rec_set_nth_field_sql_null(
709
/*=======================*/
710
rec_t* rec, /* in: record */
711
ulint n) /* in: index of the field */
715
offset = rec_get_field_start_offs(rec, n);
717
data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
719
rec_set_nth_field_null_bit(rec, n, TRUE);
722
/*************************************************************
723
Builds an old-style physical record out of a data tuple and
724
stores it beginning from the start of the given buffer. */
727
rec_convert_dtuple_to_rec_old(
728
/*==========================*/
729
/* out: pointer to the origin of
731
byte* buf, /* in: start address of the physical record */
732
dtuple_t* dtuple)/* in: data tuple */
744
ut_ad(buf && dtuple);
745
ut_ad(dtuple_validate(dtuple));
746
ut_ad(dtuple_check_typed(dtuple));
748
n_fields = dtuple_get_n_fields(dtuple);
749
data_size = dtuple_get_data_size(dtuple);
753
/* Calculate the offset of the origin in the physical record */
755
rec = buf + rec_get_converted_extra_size(data_size, n_fields);
757
/* Suppress Valgrind warnings of ut_ad()
758
in mach_write_to_1(), mach_write_to_2() et al. */
759
memset(buf, 0xff, rec - buf + data_size);
760
#endif /* UNIV_DEBUG */
761
/* Store the number of fields */
762
rec_set_n_fields_old(rec, n_fields);
764
/* Set the info bits of the record */
765
rec_set_info_bits(rec, FALSE,
766
dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
768
/* Store the data and the offsets */
772
if (data_size <= REC_1BYTE_OFFS_LIMIT) {
774
rec_set_1byte_offs_flag(rec, TRUE);
776
for (i = 0; i < n_fields; i++) {
778
field = dtuple_get_nth_field(dtuple, i);
780
data = dfield_get_data(field);
781
len = dfield_get_len(field);
783
if (len == UNIV_SQL_NULL) {
784
len = dtype_get_sql_null_size(
785
dfield_get_type(field));
786
data_write_sql_null(rec + end_offset, len);
789
ored_offset = end_offset
790
| REC_1BYTE_SQL_NULL_MASK;
792
/* If the data is not SQL null, store it */
793
ut_memcpy(rec + end_offset, data, len);
796
ored_offset = end_offset;
799
rec_1_set_field_end_info(rec, i, ored_offset);
802
rec_set_1byte_offs_flag(rec, FALSE);
804
for (i = 0; i < n_fields; i++) {
806
field = dtuple_get_nth_field(dtuple, i);
808
data = dfield_get_data(field);
809
len = dfield_get_len(field);
811
if (len == UNIV_SQL_NULL) {
812
len = dtype_get_sql_null_size(
813
dfield_get_type(field));
814
data_write_sql_null(rec + end_offset, len);
817
ored_offset = end_offset
818
| REC_2BYTE_SQL_NULL_MASK;
820
/* If the data is not SQL null, store it */
821
ut_memcpy(rec + end_offset, data, len);
824
ored_offset = end_offset;
827
rec_2_set_field_end_info(rec, i, ored_offset);
834
/*************************************************************
835
Builds a new-style physical record out of a data tuple and
836
stores it beginning from the start of the given buffer. */
839
rec_convert_dtuple_to_rec_new(
840
/*==========================*/
841
/* out: pointer to the origin
842
of physical record */
843
byte* buf, /* in: start address of the physical record */
844
dict_index_t* index, /* in: record descriptor */
845
dtuple_t* dtuple) /* in: data tuple */
849
rec_t* rec = buf + REC_N_NEW_EXTRA_BYTES;
855
ulint n_node_ptr_field;
858
const ulint n_fields = dtuple_get_n_fields(dtuple);
859
const ulint status = dtuple_get_info_bits(dtuple)
860
& REC_NEW_STATUS_MASK;
861
ut_ad(dict_table_is_comp(index->table));
864
/* Try to ensure that the memset() between the for() loops
865
completes fast. The address is not exact, but UNIV_PREFETCH
866
should never generate a memory fault. */
867
UNIV_PREFETCH_RW(rec - REC_N_NEW_EXTRA_BYTES - n_fields);
868
UNIV_PREFETCH_RW(rec);
870
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
871
case REC_STATUS_ORDINARY:
872
ut_ad(n_fields <= dict_index_get_n_fields(index));
873
n_node_ptr_field = ULINT_UNDEFINED;
875
case REC_STATUS_NODE_PTR:
876
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
877
n_node_ptr_field = n_fields - 1;
879
case REC_STATUS_INFIMUM:
880
case REC_STATUS_SUPREMUM:
881
ut_ad(n_fields == 1);
882
n_node_ptr_field = ULINT_UNDEFINED;
889
/* Calculate the offset of the origin in the physical record.
890
We must loop over all fields to do this. */
891
rec += UT_BITS_IN_BYTES(index->n_nullable);
893
for (i = 0; i < n_fields; i++) {
894
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
896
field = dtuple_get_nth_field(dtuple, i);
897
type = dfield_get_type(field);
898
ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
899
ut_ad(dfield_get_len(field) == 4);
900
#endif /* UNIV_DEBUG */
903
field = dtuple_get_nth_field(dtuple, i);
904
type = dfield_get_type(field);
905
len = dfield_get_len(field);
906
fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
908
ut_ad(dict_col_type_assert_equal(
909
dict_field_get_col(dict_index_get_nth_field(
911
dfield_get_type(field)));
913
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
914
if (len == UNIV_SQL_NULL)
917
/* only nullable fields can be null */
918
ut_ad(len != UNIV_SQL_NULL);
920
ut_ad(len == fixed_len);
922
ut_ad(len <= dtype_get_len(type)
923
|| dtype_get_mtype(type) == DATA_BLOB);
926
&& (dtype_get_len(type) >= 256
927
|| dtype_get_mtype(type) == DATA_BLOB)) {
935
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
936
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
937
/* clear the SQL-null flags */
938
memset (lens + 1, 0, nulls - lens);
940
/* Set the info bits of the record */
941
rec_set_status(rec, status);
943
rec_set_info_bits(rec, TRUE,
944
dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
946
/* Store the data and the offsets */
948
for (i = 0; i < n_fields; i++) {
949
field = dtuple_get_nth_field(dtuple, i);
950
type = dfield_get_type(field);
951
len = dfield_get_len(field);
953
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
954
ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
956
memcpy(end, dfield_get_data(field), len);
959
fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
961
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
963
ut_ad(index->n_nullable > 0);
965
if (UNIV_UNLIKELY(!(byte) null_mask)) {
970
ut_ad(*nulls < null_mask);
972
/* set the null flag if necessary */
973
if (len == UNIV_SQL_NULL) {
981
/* only nullable fields can be null */
982
ut_ad(len != UNIV_SQL_NULL);
984
ut_ad(len == fixed_len);
986
ut_ad(len <= dtype_get_len(type)
987
|| dtype_get_mtype(type) == DATA_BLOB);
989
|| (dtype_get_len(type) < 256
990
&& dtype_get_mtype(type) != DATA_BLOB)) {
992
*lens-- = (byte) len;
994
/* the extern bits will be set later */
996
*lens-- = (byte) (len >> 8) | 0x80;
997
*lens-- = (byte) len;
1001
memcpy(end, dfield_get_data(field), len);
1008
/*************************************************************
1009
Builds a physical record out of a data tuple and
1010
stores it beginning from the start of the given buffer. */
1013
rec_convert_dtuple_to_rec(
1014
/*======================*/
1015
/* out: pointer to the origin
1016
of physical record */
1017
byte* buf, /* in: start address of the
1019
dict_index_t* index, /* in: record descriptor */
1020
dtuple_t* dtuple) /* in: data tuple */
1024
ut_ad(buf && index && dtuple);
1025
ut_ad(dtuple_validate(dtuple));
1026
ut_ad(dtuple_check_typed(dtuple));
1028
if (dict_table_is_comp(index->table)) {
1029
rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1031
rec = rec_convert_dtuple_to_rec_old(buf, dtuple);
1036
mem_heap_t* heap = NULL;
1037
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1038
const ulint* offsets;
1039
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
1041
offsets = rec_get_offsets(rec, index,
1042
offsets_, ULINT_UNDEFINED, &heap);
1043
ut_ad(rec_validate(rec, offsets));
1044
if (UNIV_LIKELY_NULL(heap)) {
1045
mem_heap_free(heap);
1048
#endif /* UNIV_DEBUG */
1052
/******************************************************************
1053
Copies the first n fields of a physical record to a data tuple. The fields
1054
are copied to the memory heap. */
1057
rec_copy_prefix_to_dtuple(
1058
/*======================*/
1059
dtuple_t* tuple, /* in: data tuple */
1060
rec_t* rec, /* in: physical record */
1061
dict_index_t* index, /* in: record descriptor */
1062
ulint n_fields, /* in: number of fields to copy */
1063
mem_heap_t* heap) /* in: memory heap */
1070
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1071
ulint* offsets = offsets_;
1072
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
1074
offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1076
ut_ad(rec_validate(rec, offsets));
1077
ut_ad(dtuple_check_typed(tuple));
1079
dtuple_set_info_bits(tuple, rec_get_info_bits(
1080
rec, dict_table_is_comp(index->table)));
1082
for (i = 0; i < n_fields; i++) {
1084
field = dtuple_get_nth_field(tuple, i);
1085
data = rec_get_nth_field(rec, offsets, i, &len);
1087
if (len != UNIV_SQL_NULL) {
1088
buf = mem_heap_alloc(heap, len);
1090
ut_memcpy(buf, data, len);
1093
dfield_set_data(field, buf, len);
1097
/******************************************************************
1098
Copies the first n fields of an old-style physical record
1099
to a new physical record in a buffer. */
1102
rec_copy_prefix_to_buf_old(
1103
/*=======================*/
1104
/* out, own: copied record */
1105
rec_t* rec, /* in: physical record */
1106
ulint n_fields, /* in: number of fields to copy */
1107
ulint area_end, /* in: end of the prefix data */
1108
byte** buf, /* in/out: memory buffer for the copied prefix,
1110
ulint* buf_size) /* in/out: buffer size */
1116
if (rec_get_1byte_offs_flag(rec)) {
1117
area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1119
area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1122
prefix_len = area_start + area_end;
1124
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1129
*buf = mem_alloc(prefix_len);
1130
*buf_size = prefix_len;
1133
ut_memcpy(*buf, rec - area_start, prefix_len);
1135
copy_rec = *buf + area_start;
1137
rec_set_n_fields_old(copy_rec, n_fields);
1142
/******************************************************************
1143
Copies the first n fields of a physical record to a new physical record in
1147
rec_copy_prefix_to_buf(
1148
/*===================*/
1149
/* out, own: copied record */
1150
rec_t* rec, /* in: physical record */
1151
dict_index_t* index, /* in: record descriptor */
1152
ulint n_fields, /* in: number of fields to copy */
1153
byte** buf, /* in/out: memory buffer
1154
for the copied prefix, or NULL */
1155
ulint* buf_size) /* in/out: buffer size */
1164
UNIV_PREFETCH_RW(*buf);
1166
if (!dict_table_is_comp(index->table)) {
1167
ut_ad(rec_validate_old(rec));
1168
return(rec_copy_prefix_to_buf_old(
1170
rec_get_field_start_offs(rec, n_fields),
1174
status = rec_get_status(rec);
1177
case REC_STATUS_ORDINARY:
1178
ut_ad(n_fields <= dict_index_get_n_fields(index));
1180
case REC_STATUS_NODE_PTR:
1181
/* it doesn't make sense to copy the child page number field */
1182
ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1184
case REC_STATUS_INFIMUM:
1185
case REC_STATUS_SUPREMUM:
1186
/* infimum or supremum record: no sense to copy anything */
1192
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1193
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1194
UNIV_PREFETCH_R(lens);
1198
/* read the lengths of fields 0..n */
1199
for (i = 0; i < n_fields; i++) {
1200
const dict_field_t* field;
1201
const dict_col_t* col;
1203
field = dict_index_get_nth_field(index, i);
1204
col = dict_field_get_col(field);
1206
if (!(col->prtype & DATA_NOT_NULL)) {
1207
/* nullable field => read the null flag */
1208
if (UNIV_UNLIKELY(!(byte) null_mask)) {
1213
if (*nulls & null_mask) {
1221
if (field->fixed_len) {
1222
prefix_len += field->fixed_len;
1224
ulint len = *lens--;
1225
if (col->len > 255 || col->mtype == DATA_BLOB) {
1231
UNIV_PREFETCH_R(lens);
1238
UNIV_PREFETCH_R(rec + prefix_len);
1240
prefix_len += rec - (lens + 1);
1242
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1247
*buf = mem_alloc(prefix_len);
1248
*buf_size = prefix_len;
1251
memcpy(*buf, lens + 1, prefix_len);
1253
return(*buf + (rec - (lens + 1)));
1256
/*******************************************************************
1257
Validates the consistency of an old-style physical record. */
1262
/* out: TRUE if ok */
1263
rec_t* rec) /* in: physical record */
1273
n_fields = rec_get_n_fields_old(rec);
1275
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1276
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1281
for (i = 0; i < n_fields; i++) {
1282
data = rec_get_nth_field_old(rec, i, &len);
1284
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1286
"InnoDB: Error: record field %lu len %lu\n",
1292
if (len != UNIV_SQL_NULL) {
1294
sum += *(data + len -1); /* dereference the
1299
len_sum += rec_get_nth_field_size(rec, i);
1303
if (len_sum != rec_get_data_size_old(rec)) {
1305
"InnoDB: Error: record len should be %lu, len %lu\n",
1307
rec_get_data_size_old(rec));
1311
rec_dummy = sum; /* This is here only to fool the compiler */
1316
/*******************************************************************
1317
Validates the consistency of a physical record. */
1322
/* out: TRUE if ok */
1323
rec_t* rec, /* in: physical record */
1324
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1334
n_fields = rec_offs_n_fields(offsets);
1336
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1337
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1342
ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1344
for (i = 0; i < n_fields; i++) {
1345
data = rec_get_nth_field(rec, offsets, i, &len);
1347
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1349
"InnoDB: Error: record field %lu len %lu\n",
1355
if (len != UNIV_SQL_NULL) {
1357
sum += *(data + len -1); /* dereference the
1361
} else if (!rec_offs_comp(offsets)) {
1362
len_sum += rec_get_nth_field_size(rec, i);
1366
if (len_sum != (ulint)(rec_get_end(rec, offsets) - rec)) {
1368
"InnoDB: Error: record len should be %lu, len %lu\n",
1370
(ulong) (rec_get_end(rec, offsets) - rec));
1374
rec_dummy = sum; /* This is here only to fool the compiler */
1376
if (!rec_offs_comp(offsets)) {
1377
ut_a(rec_validate_old(rec));
1383
/*******************************************************************
1384
Prints an old-style physical record. */
1389
FILE* file, /* in: file where to print */
1390
rec_t* rec) /* in: physical record */
1399
n = rec_get_n_fields_old(rec);
1401
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1402
" %u-byte offsets; info bits %lu\n",
1404
rec_get_1byte_offs_flag(rec) ? 1 : 2,
1405
(ulong) rec_get_info_bits(rec, FALSE));
1407
for (i = 0; i < n; i++) {
1409
data = rec_get_nth_field_old(rec, i, &len);
1411
fprintf(file, " %lu:", (ulong) i);
1413
if (len != UNIV_SQL_NULL) {
1416
ut_print_buf(file, data, len);
1418
ut_print_buf(file, data, 30);
1420
fputs("...(truncated)", file);
1423
fprintf(file, " SQL NULL, size %lu ",
1424
rec_get_nth_field_size(rec, i));
1431
rec_validate_old(rec);
1434
/*******************************************************************
1435
Prints a physical record. */
1440
FILE* file, /* in: file where to print */
1441
rec_t* rec, /* in: physical record */
1442
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1448
ut_ad(rec_offs_validate(rec, NULL, offsets));
1450
if (!rec_offs_comp(offsets)) {
1451
rec_print_old(file, rec);
1457
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1458
" compact format; info bits %lu\n",
1459
(ulong) rec_offs_n_fields(offsets),
1460
(ulong) rec_get_info_bits(rec, TRUE));
1462
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1464
data = rec_get_nth_field(rec, offsets, i, &len);
1466
fprintf(file, " %lu:", (ulong) i);
1468
if (len != UNIV_SQL_NULL) {
1471
ut_print_buf(file, data, len);
1473
ut_print_buf(file, data, 30);
1475
fputs("...(truncated)", file);
1478
fputs(" SQL NULL", file);
1485
rec_validate(rec, offsets);
1488
/*******************************************************************
1489
Prints a physical record. */
1494
FILE* file, /* in: file where to print */
1495
rec_t* rec, /* in: physical record */
1496
dict_index_t* index) /* in: record descriptor */
1500
if (!dict_table_is_comp(index->table)) {
1501
rec_print_old(file, rec);
1504
mem_heap_t* heap = NULL;
1505
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1506
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
1508
rec_print_new(file, rec,
1509
rec_get_offsets(rec, index, offsets_,
1510
ULINT_UNDEFINED, &heap));
1511
if (UNIV_LIKELY_NULL(heap)) {
1512
mem_heap_free(heap);