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
/* this is used to fool compiler in rec_validate */
128
UNIV_INTERN ulint rec_dummy;
130
/*******************************************************************
131
Validates the consistency of an old-style physical record. */
136
/* out: TRUE if ok */
137
const rec_t* rec); /* in: physical record */
139
/**********************************************************
140
Determine how many of the first n columns in a compact
141
physical record are stored externally. */
144
rec_get_n_extern_new(
145
/*=================*/
146
/* out: number of externally stored columns */
147
const rec_t* rec, /* in: compact physical record */
148
dict_index_t* index, /* in: record descriptor */
149
ulint n) /* in: number of columns to scan */
158
ut_ad(dict_table_is_comp(index->table));
159
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
160
ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
162
if (n == ULINT_UNDEFINED) {
163
n = dict_index_get_n_fields(index);
166
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
167
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
172
/* read the lengths of fields 0..n */
176
field = dict_index_get_nth_field(index, i);
177
if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
178
/* nullable field => read the null flag */
180
if (UNIV_UNLIKELY(!(byte) null_mask)) {
185
if (*nulls & null_mask) {
187
/* No length is stored for NULL fields. */
193
if (UNIV_UNLIKELY(!field->fixed_len)) {
194
/* Variable-length field: read the length */
195
const dict_col_t* col
196
= dict_field_get_col(field);
198
if (UNIV_UNLIKELY(col->len > 255)
199
|| UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
201
/* 1exxxxxxx xxxxxxxx */
214
/**********************************************************
215
Determine the offset to each field in a leaf-page record
216
in ROW_FORMAT=COMPACT. This is a special case of
217
rec_init_offsets() and rec_get_offsets_func(). */
220
rec_init_offsets_comp_ordinary(
221
/*===========================*/
222
const rec_t* rec, /* in: physical record in
223
ROW_FORMAT=COMPACT */
224
ulint extra, /* in: number of bytes to reserve
225
between the record header and
227
(usually REC_N_NEW_EXTRA_BYTES) */
228
const dict_index_t* index, /* in: record descriptor */
229
ulint* offsets)/* in/out: array of offsets;
230
in: n=rec_offs_n_fields(offsets) */
235
const byte* nulls = rec - (extra + 1);
236
const byte* lens = nulls
237
- UT_BITS_IN_BYTES(index->n_nullable);
242
/* We cannot invoke rec_offs_make_valid() here, because it can hold
243
that extra != REC_N_NEW_EXTRA_BYTES. Similarly, rec_offs_validate()
244
will fail in that case, because it invokes rec_get_status(). */
245
offsets[2] = (ulint) rec;
246
offsets[3] = (ulint) index;
247
#endif /* UNIV_DEBUG */
249
/* read the lengths of fields 0..n */
253
field = dict_index_get_nth_field(index, i);
254
if (!(dict_field_get_col(field)->prtype
256
/* nullable field => read the null flag */
258
if (UNIV_UNLIKELY(!(byte) null_mask)) {
263
if (*nulls & null_mask) {
265
/* No length is stored for NULL fields.
266
We do not advance offs, and we set
267
the length to zero and enable the
268
SQL NULL flag in offsets[]. */
269
len = offs | REC_OFFS_SQL_NULL;
275
if (UNIV_UNLIKELY(!field->fixed_len)) {
276
/* Variable-length field: read the length */
277
const dict_col_t* col
278
= dict_field_get_col(field);
280
if (UNIV_UNLIKELY(col->len > 255)
281
|| UNIV_UNLIKELY(col->mtype
284
/* 1exxxxxxx xxxxxxxx */
288
offs += len & 0x3fff;
289
if (UNIV_UNLIKELY(len
291
ut_ad(dict_index_is_clust
293
any_ext = REC_OFFS_EXTERNAL;
306
len = offs += field->fixed_len;
309
rec_offs_base(offsets)[i + 1] = len;
310
} while (++i < rec_offs_n_fields(offsets));
312
*rec_offs_base(offsets)
313
= (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
316
/**********************************************************
317
The following function determines the offsets to each field in the
318
record. The offsets are written to a previously allocated array of
319
ulint, where rec_offs_n_fields(offsets) has been initialized to the
320
number of fields in the record. The rest of the array will be
321
initialized by this function. rec_offs_base(offsets)[0] will be set
322
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
323
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
324
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
325
offsets past the end of fields 0..n_fields, or to the beginning of
326
fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
327
is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
328
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
329
field i is being stored externally. */
334
const rec_t* rec, /* in: physical record */
335
const dict_index_t* index, /* in: record descriptor */
336
ulint* offsets)/* in/out: array of offsets;
337
in: n=rec_offs_n_fields(offsets) */
342
rec_offs_make_valid(rec, index, offsets);
344
if (dict_table_is_comp(index->table)) {
349
ulint status = rec_get_status(rec);
350
ulint n_node_ptr_field = ULINT_UNDEFINED;
352
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
353
case REC_STATUS_INFIMUM:
354
case REC_STATUS_SUPREMUM:
355
/* the field is 8 bytes long */
356
rec_offs_base(offsets)[0]
357
= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
358
rec_offs_base(offsets)[1] = 8;
360
case REC_STATUS_NODE_PTR:
362
= dict_index_get_n_unique_in_tree(index);
364
case REC_STATUS_ORDINARY:
365
rec_init_offsets_comp_ordinary(rec,
366
REC_N_NEW_EXTRA_BYTES,
371
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
372
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
376
/* read the lengths of fields 0..n */
379
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
384
field = dict_index_get_nth_field(index, i);
385
if (!(dict_field_get_col(field)->prtype
387
/* nullable field => read the null flag */
389
if (UNIV_UNLIKELY(!(byte) null_mask)) {
394
if (*nulls & null_mask) {
396
/* No length is stored for NULL fields.
397
We do not advance offs, and we set
398
the length to zero and enable the
399
SQL NULL flag in offsets[]. */
400
len = offs | REC_OFFS_SQL_NULL;
406
if (UNIV_UNLIKELY(!field->fixed_len)) {
407
/* Variable-length field: read the length */
408
const dict_col_t* col
409
= dict_field_get_col(field);
411
if (UNIV_UNLIKELY(col->len > 255)
412
|| UNIV_UNLIKELY(col->mtype
415
/* 1exxxxxxx xxxxxxxx */
420
/* B-tree node pointers
421
must not contain externally
423
the "e" flag must be 0. */
424
ut_a(!(len & 0x4000));
425
offs += len & 0x3fff;
434
len = offs += field->fixed_len;
437
rec_offs_base(offsets)[i + 1] = len;
438
} while (++i < rec_offs_n_fields(offsets));
440
*rec_offs_base(offsets)
441
= (rec - (lens + 1)) | REC_OFFS_COMPACT;
443
/* Old-style record: determine extra size and end offsets */
444
offs = REC_N_OLD_EXTRA_BYTES;
445
if (rec_get_1byte_offs_flag(rec)) {
446
offs += rec_offs_n_fields(offsets);
447
*rec_offs_base(offsets) = offs;
448
/* Determine offsets to fields */
450
offs = rec_1_get_field_end_info(rec, i);
451
if (offs & REC_1BYTE_SQL_NULL_MASK) {
452
offs &= ~REC_1BYTE_SQL_NULL_MASK;
453
offs |= REC_OFFS_SQL_NULL;
455
rec_offs_base(offsets)[1 + i] = offs;
456
} while (++i < rec_offs_n_fields(offsets));
458
offs += 2 * rec_offs_n_fields(offsets);
459
*rec_offs_base(offsets) = offs;
460
/* Determine offsets to fields */
462
offs = rec_2_get_field_end_info(rec, i);
463
if (offs & REC_2BYTE_SQL_NULL_MASK) {
464
offs &= ~REC_2BYTE_SQL_NULL_MASK;
465
offs |= REC_OFFS_SQL_NULL;
467
if (offs & REC_2BYTE_EXTERN_MASK) {
468
offs &= ~REC_2BYTE_EXTERN_MASK;
469
offs |= REC_OFFS_EXTERNAL;
470
*rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
472
rec_offs_base(offsets)[1 + i] = offs;
473
} while (++i < rec_offs_n_fields(offsets));
478
/**********************************************************
479
The following function determines the offsets to each field
480
in the record. It can reuse a previously returned array. */
483
rec_get_offsets_func(
484
/*=================*/
485
/* out: the new offsets */
486
const rec_t* rec, /* in: physical record */
487
const dict_index_t* index, /* in: record descriptor */
488
ulint* offsets,/* in/out: array consisting of
489
offsets[0] allocated elements,
490
or an array from rec_get_offsets(),
492
ulint n_fields,/* in: maximum number of
494
(ULINT_UNDEFINED if all fields) */
495
mem_heap_t** heap, /* in/out: memory heap */
496
const char* file, /* in: file name where called */
497
ulint line) /* in: line number where called */
506
if (dict_table_is_comp(index->table)) {
507
switch (UNIV_EXPECT(rec_get_status(rec),
508
REC_STATUS_ORDINARY)) {
509
case REC_STATUS_ORDINARY:
510
n = dict_index_get_n_fields(index);
512
case REC_STATUS_NODE_PTR:
513
n = dict_index_get_n_unique_in_tree(index) + 1;
515
case REC_STATUS_INFIMUM:
516
case REC_STATUS_SUPREMUM:
517
/* infimum or supremum record */
525
n = rec_get_n_fields_old(rec);
528
if (UNIV_UNLIKELY(n_fields < n)) {
532
size = n + (1 + REC_OFFS_HEADER_SIZE);
534
if (UNIV_UNLIKELY(!offsets)
535
|| UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
536
if (UNIV_UNLIKELY(!*heap)) {
537
*heap = mem_heap_create_func(size * sizeof(ulint),
541
offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
542
rec_offs_set_n_alloc(offsets, size);
545
rec_offs_set_n_fields(offsets, n);
546
rec_init_offsets(rec, index, offsets);
550
/**********************************************************
551
The following function determines the offsets to each field
552
in the record. It can reuse a previously allocated array. */
555
rec_get_offsets_reverse(
556
/*====================*/
557
const byte* extra, /* in: the extra bytes of a
558
compact record in reverse order,
559
excluding the fixed-size
560
REC_N_NEW_EXTRA_BYTES */
561
const dict_index_t* index, /* in: record descriptor */
562
ulint node_ptr,/* in: nonzero=node pointer,
564
ulint* offsets)/* in/out: array consisting of
565
offsets[0] allocated elements */
575
ulint n_node_ptr_field;
580
ut_ad(dict_table_is_comp(index->table));
582
if (UNIV_UNLIKELY(node_ptr)) {
583
n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
584
n = n_node_ptr_field + 1;
586
n_node_ptr_field = ULINT_UNDEFINED;
587
n = dict_index_get_n_fields(index);
590
ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
591
rec_offs_set_n_fields(offsets, n);
594
lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
599
/* read the lengths of fields 0..n */
602
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
607
field = dict_index_get_nth_field(index, i);
608
if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
609
/* nullable field => read the null flag */
611
if (UNIV_UNLIKELY(!(byte) null_mask)) {
616
if (*nulls & null_mask) {
618
/* No length is stored for NULL fields.
619
We do not advance offs, and we set
620
the length to zero and enable the
621
SQL NULL flag in offsets[]. */
622
len = offs | REC_OFFS_SQL_NULL;
628
if (UNIV_UNLIKELY(!field->fixed_len)) {
629
/* Variable-length field: read the length */
630
const dict_col_t* col
631
= dict_field_get_col(field);
633
if (UNIV_UNLIKELY(col->len > 255)
634
|| UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
636
/* 1exxxxxxx xxxxxxxx */
640
offs += len & 0x3fff;
641
if (UNIV_UNLIKELY(len & 0x4000)) {
642
any_ext = REC_OFFS_EXTERNAL;
643
len = offs | REC_OFFS_EXTERNAL;
654
len = offs += field->fixed_len;
657
rec_offs_base(offsets)[i + 1] = len;
658
} while (++i < rec_offs_n_fields(offsets));
660
ut_ad(lens >= extra);
661
*rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
662
| REC_OFFS_COMPACT | any_ext;
665
/****************************************************************
666
The following function is used to get the offset to the nth
667
data field in an old-style record. */
670
rec_get_nth_field_offs_old(
671
/*=======================*/
672
/* out: offset to the field */
673
const rec_t* rec, /* in: record */
674
ulint n, /* in: index of the field */
675
ulint* len) /* out: length of the field;
676
UNIV_SQL_NULL if SQL null */
682
ut_ad(n < rec_get_n_fields_old(rec));
684
if (n > REC_MAX_N_FIELDS) {
685
fprintf(stderr, "Error: trying to access field %lu in rec\n",
691
fputs("Error: rec is NULL pointer\n", stderr);
695
if (rec_get_1byte_offs_flag(rec)) {
696
os = rec_1_get_field_start_offs(rec, n);
698
next_os = rec_1_get_field_end_info(rec, n);
700
if (next_os & REC_1BYTE_SQL_NULL_MASK) {
701
*len = UNIV_SQL_NULL;
706
next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
708
os = rec_2_get_field_start_offs(rec, n);
710
next_os = rec_2_get_field_end_info(rec, n);
712
if (next_os & REC_2BYTE_SQL_NULL_MASK) {
713
*len = UNIV_SQL_NULL;
718
next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
719
| REC_2BYTE_EXTERN_MASK);
724
ut_ad(*len < UNIV_PAGE_SIZE);
729
/**************************************************************
730
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT. */
733
rec_get_converted_size_comp_prefix(
734
/*===============================*/
735
/* out: total size */
736
const dict_index_t* index, /* in: record descriptor;
737
dict_table_is_comp() is
738
assumed to hold, even if
740
const dfield_t* fields, /* in: array of data fields */
741
ulint n_fields,/* in: number of data fields */
742
ulint* extra) /* out: extra size */
750
ut_ad(n_fields <= dict_index_get_n_fields(index));
752
extra_size = REC_N_NEW_EXTRA_BYTES
753
+ UT_BITS_IN_BYTES(index->n_nullable);
756
/* read the lengths of fields 0..n */
757
for (i = 0; i < n_fields; i++) {
758
const dict_field_t* field;
760
const dict_col_t* col;
762
field = dict_index_get_nth_field(index, i);
763
len = dfield_get_len(&fields[i]);
764
col = dict_field_get_col(field);
766
ut_ad(dict_col_type_assert_equal(col,
767
dfield_get_type(&fields[i])));
769
if (dfield_is_null(&fields[i])) {
770
/* No length is stored for NULL fields. */
771
ut_ad(!(col->prtype & DATA_NOT_NULL));
775
ut_ad(len <= col->len || col->mtype == DATA_BLOB);
777
if (field->fixed_len) {
778
ut_ad(len == field->fixed_len);
779
/* dict_index_add_col() should guarantee this */
780
ut_ad(!field->prefix_len
781
|| field->fixed_len == field->prefix_len);
782
} else if (dfield_is_ext(&fields[i])) {
785
|| (col->len < 256 && col->mtype != DATA_BLOB)) {
788
/* For variable-length columns, we look up the
789
maximum length from the column itself. If this
790
is a prefix index column shorter than 256 bytes,
791
this will waste one byte. */
797
if (UNIV_LIKELY_NULL(extra)) {
801
return(extra_size + data_size);
804
/**************************************************************
805
Determines the size of a data tuple in ROW_FORMAT=COMPACT. */
808
rec_get_converted_size_comp(
809
/*========================*/
810
/* out: total size */
811
const dict_index_t* index, /* in: record descriptor;
812
dict_table_is_comp() is
813
assumed to hold, even if
815
ulint status, /* in: status bits of the record */
816
const dfield_t* fields, /* in: array of data fields */
817
ulint n_fields,/* in: number of data fields */
818
ulint* extra) /* out: extra size */
825
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
826
case REC_STATUS_ORDINARY:
827
ut_ad(n_fields == dict_index_get_n_fields(index));
830
case REC_STATUS_NODE_PTR:
832
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
833
ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
834
size = REC_NODE_PTR_SIZE; /* child page number */
836
case REC_STATUS_INFIMUM:
837
case REC_STATUS_SUPREMUM:
838
/* infimum or supremum record, 8 data bytes */
839
if (UNIV_LIKELY_NULL(extra)) {
840
*extra = REC_N_NEW_EXTRA_BYTES;
842
return(REC_N_NEW_EXTRA_BYTES + 8);
845
return(ULINT_UNDEFINED);
848
return(size + rec_get_converted_size_comp_prefix(index, fields,
852
/***************************************************************
853
Sets the value of the ith field SQL null bit of an old-style record. */
856
rec_set_nth_field_null_bit(
857
/*=======================*/
858
rec_t* rec, /* in: record */
859
ulint i, /* in: ith field */
860
ibool val) /* in: value to set */
864
if (rec_get_1byte_offs_flag(rec)) {
866
info = rec_1_get_field_end_info(rec, i);
869
info = info | REC_1BYTE_SQL_NULL_MASK;
871
info = info & ~REC_1BYTE_SQL_NULL_MASK;
874
rec_1_set_field_end_info(rec, i, info);
879
info = rec_2_get_field_end_info(rec, i);
882
info = info | REC_2BYTE_SQL_NULL_MASK;
884
info = info & ~REC_2BYTE_SQL_NULL_MASK;
887
rec_2_set_field_end_info(rec, i, info);
890
/***************************************************************
891
Sets an old-style record field to SQL null.
892
The physical size of the field is not changed. */
895
rec_set_nth_field_sql_null(
896
/*=======================*/
897
rec_t* rec, /* in: record */
898
ulint n) /* in: index of the field */
902
offset = rec_get_field_start_offs(rec, n);
904
data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
906
rec_set_nth_field_null_bit(rec, n, TRUE);
909
/*************************************************************
910
Builds an old-style physical record out of a data tuple and
911
stores it beginning from the start of the given buffer. */
914
rec_convert_dtuple_to_rec_old(
915
/*==========================*/
916
/* out: pointer to the origin of
918
byte* buf, /* in: start address of the physical record */
919
const dtuple_t* dtuple, /* in: data tuple */
920
ulint n_ext) /* in: number of externally stored columns */
922
const dfield_t* field;
931
ut_ad(buf && dtuple);
932
ut_ad(dtuple_validate(dtuple));
933
ut_ad(dtuple_check_typed(dtuple));
935
n_fields = dtuple_get_n_fields(dtuple);
936
data_size = dtuple_get_data_size(dtuple);
940
/* Calculate the offset of the origin in the physical record */
942
rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
944
/* Suppress Valgrind warnings of ut_ad()
945
in mach_write_to_1(), mach_write_to_2() et al. */
946
memset(buf, 0xff, rec - buf + data_size);
947
#endif /* UNIV_DEBUG */
948
/* Store the number of fields */
949
rec_set_n_fields_old(rec, n_fields);
951
/* Set the info bits of the record */
952
rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
953
& REC_INFO_BITS_MASK);
955
/* Store the data and the offsets */
959
if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
961
rec_set_1byte_offs_flag(rec, TRUE);
963
for (i = 0; i < n_fields; i++) {
965
field = dtuple_get_nth_field(dtuple, i);
967
if (dfield_is_null(field)) {
968
len = dtype_get_sql_null_size(
969
dfield_get_type(field));
970
data_write_sql_null(rec + end_offset, len);
973
ored_offset = end_offset
974
| REC_1BYTE_SQL_NULL_MASK;
976
/* If the data is not SQL null, store it */
977
len = dfield_get_len(field);
979
memcpy(rec + end_offset,
980
dfield_get_data(field), len);
983
ored_offset = end_offset;
986
rec_1_set_field_end_info(rec, i, ored_offset);
989
rec_set_1byte_offs_flag(rec, FALSE);
991
for (i = 0; i < n_fields; i++) {
993
field = dtuple_get_nth_field(dtuple, i);
995
if (dfield_is_null(field)) {
996
len = dtype_get_sql_null_size(
997
dfield_get_type(field));
998
data_write_sql_null(rec + end_offset, len);
1001
ored_offset = end_offset
1002
| REC_2BYTE_SQL_NULL_MASK;
1004
/* If the data is not SQL null, store it */
1005
len = dfield_get_len(field);
1007
memcpy(rec + end_offset,
1008
dfield_get_data(field), len);
1011
ored_offset = end_offset;
1013
if (dfield_is_ext(field)) {
1014
ored_offset |= REC_2BYTE_EXTERN_MASK;
1018
rec_2_set_field_end_info(rec, i, ored_offset);
1025
/*************************************************************
1026
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1029
rec_convert_dtuple_to_rec_comp(
1030
/*===========================*/
1031
rec_t* rec, /* in: origin of record */
1032
ulint extra, /* in: number of bytes to
1033
reserve between the record
1034
header and the data payload
1035
(normally REC_N_NEW_EXTRA_BYTES) */
1036
const dict_index_t* index, /* in: record descriptor */
1037
ulint status, /* in: status bits of the record */
1038
const dfield_t* fields, /* in: array of data fields */
1039
ulint n_fields)/* in: number of data fields */
1041
const dfield_t* field;
1042
const dtype_t* type;
1048
ulint n_node_ptr_field;
1050
ulint null_mask = 1;
1051
ut_ad(extra == 0 || dict_table_is_comp(index->table));
1052
ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
1053
ut_ad(n_fields > 0);
1055
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1056
case REC_STATUS_ORDINARY:
1057
ut_ad(n_fields <= dict_index_get_n_fields(index));
1058
n_node_ptr_field = ULINT_UNDEFINED;
1060
case REC_STATUS_NODE_PTR:
1061
ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1062
n_node_ptr_field = n_fields - 1;
1064
case REC_STATUS_INFIMUM:
1065
case REC_STATUS_SUPREMUM:
1066
ut_ad(n_fields == 1);
1067
n_node_ptr_field = ULINT_UNDEFINED;
1075
nulls = rec - (extra + 1);
1076
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1077
/* clear the SQL-null flags */
1078
memset(lens + 1, 0, nulls - lens);
1080
/* Store the data and the offsets */
1082
for (i = 0, field = fields; i < n_fields; i++, field++) {
1083
type = dfield_get_type(field);
1084
len = dfield_get_len(field);
1086
if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1087
ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1089
memcpy(end, dfield_get_data(field), len);
1094
if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1095
/* nullable field */
1096
ut_ad(index->n_nullable > 0);
1098
if (UNIV_UNLIKELY(!(byte) null_mask)) {
1103
ut_ad(*nulls < null_mask);
1105
/* set the null flag if necessary */
1106
if (dfield_is_null(field)) {
1107
*nulls |= null_mask;
1114
/* only nullable fields can be null */
1115
ut_ad(!dfield_is_null(field));
1117
fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
1120
ut_ad(len == fixed_len);
1121
ut_ad(!dfield_is_ext(field));
1122
} else if (dfield_is_ext(field)) {
1123
ut_ad(len <= REC_MAX_INDEX_COL_LEN
1124
+ BTR_EXTERN_FIELD_REF_SIZE);
1125
*lens-- = (byte) (len >> 8) | 0xc0;
1126
*lens-- = (byte) len;
1128
ut_ad(len <= dtype_get_len(type)
1129
|| dtype_get_mtype(type) == DATA_BLOB);
1131
|| (dtype_get_len(type) < 256
1132
&& dtype_get_mtype(type) != DATA_BLOB)) {
1134
*lens-- = (byte) len;
1137
*lens-- = (byte) (len >> 8) | 0x80;
1138
*lens-- = (byte) len;
1142
memcpy(end, dfield_get_data(field), len);
1147
/*************************************************************
1148
Builds a new-style physical record out of a data tuple and
1149
stores it beginning from the start of the given buffer. */
1152
rec_convert_dtuple_to_rec_new(
1153
/*==========================*/
1154
/* out: pointer to the origin
1155
of physical record */
1156
byte* buf, /* in: start address of
1157
the physical record */
1158
const dict_index_t* index, /* in: record descriptor */
1159
const dtuple_t* dtuple) /* in: data tuple */
1165
status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1166
rec_get_converted_size_comp(index, status,
1167
dtuple->fields, dtuple->n_fields,
1169
rec = buf + extra_size;
1171
rec_convert_dtuple_to_rec_comp(
1172
rec, REC_N_NEW_EXTRA_BYTES, index, status,
1173
dtuple->fields, dtuple->n_fields);
1175
/* Set the info bits of the record */
1176
rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1181
/*************************************************************
1182
Builds a physical record out of a data tuple and
1183
stores it beginning from the start of the given buffer. */
1186
rec_convert_dtuple_to_rec(
1187
/*======================*/
1188
/* out: pointer to the origin
1189
of physical record */
1190
byte* buf, /* in: start address of the
1192
const dict_index_t* index, /* in: record descriptor */
1193
const dtuple_t* dtuple, /* in: data tuple */
1194
ulint n_ext) /* in: number of
1195
externally stored columns */
1199
ut_ad(buf && index && dtuple);
1200
ut_ad(dtuple_validate(dtuple));
1201
ut_ad(dtuple_check_typed(dtuple));
1203
if (dict_table_is_comp(index->table)) {
1204
rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1206
rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1211
mem_heap_t* heap = NULL;
1212
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1213
const ulint* offsets;
1214
rec_offs_init(offsets_);
1216
offsets = rec_get_offsets(rec, index,
1217
offsets_, ULINT_UNDEFINED, &heap);
1218
ut_ad(rec_validate(rec, offsets));
1219
if (UNIV_LIKELY_NULL(heap)) {
1220
mem_heap_free(heap);
1223
#endif /* UNIV_DEBUG */
1227
/******************************************************************
1228
Copies the first n fields of a physical record to a data tuple. The fields
1229
are copied to the memory heap. */
1232
rec_copy_prefix_to_dtuple(
1233
/*======================*/
1234
dtuple_t* tuple, /* out: data tuple */
1235
const rec_t* rec, /* in: physical record */
1236
const dict_index_t* index, /* in: record descriptor */
1237
ulint n_fields, /* in: number of fields
1239
mem_heap_t* heap) /* in: memory heap */
1242
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1243
ulint* offsets = offsets_;
1244
rec_offs_init(offsets_);
1246
offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1248
ut_ad(rec_validate(rec, offsets));
1249
ut_ad(dtuple_check_typed(tuple));
1251
dtuple_set_info_bits(tuple, rec_get_info_bits(
1252
rec, dict_table_is_comp(index->table)));
1254
for (i = 0; i < n_fields; i++) {
1259
field = dtuple_get_nth_field(tuple, i);
1260
data = rec_get_nth_field(rec, offsets, i, &len);
1262
if (len != UNIV_SQL_NULL) {
1263
dfield_set_data(field,
1264
mem_heap_dup(heap, data, len), len);
1265
ut_ad(!rec_offs_nth_extern(offsets, i));
1267
dfield_set_null(field);
1272
/******************************************************************
1273
Copies the first n fields of an old-style physical record
1274
to a new physical record in a buffer. */
1277
rec_copy_prefix_to_buf_old(
1278
/*=======================*/
1279
/* out, own: copied record */
1280
const rec_t* rec, /* in: physical record */
1281
ulint n_fields, /* in: number of fields to copy */
1282
ulint area_end, /* in: end of the prefix data */
1283
byte** buf, /* in/out: memory buffer for
1284
the copied prefix, or NULL */
1285
ulint* buf_size) /* in/out: buffer size */
1291
if (rec_get_1byte_offs_flag(rec)) {
1292
area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1294
area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1297
prefix_len = area_start + area_end;
1299
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1304
*buf = mem_alloc2(prefix_len, buf_size);
1307
ut_memcpy(*buf, rec - area_start, prefix_len);
1309
copy_rec = *buf + area_start;
1311
rec_set_n_fields_old(copy_rec, n_fields);
1316
/******************************************************************
1317
Copies the first n fields of a physical record to a new physical record in
1321
rec_copy_prefix_to_buf(
1322
/*===================*/
1323
/* out, own: copied record */
1324
const rec_t* rec, /* in: physical record */
1325
const dict_index_t* index, /* in: record descriptor */
1326
ulint n_fields, /* in: number of fields
1328
byte** buf, /* in/out: memory buffer
1329
for the copied prefix,
1331
ulint* buf_size) /* in/out: buffer size */
1340
UNIV_PREFETCH_RW(*buf);
1342
if (!dict_table_is_comp(index->table)) {
1343
ut_ad(rec_validate_old(rec));
1344
return(rec_copy_prefix_to_buf_old(
1346
rec_get_field_start_offs(rec, n_fields),
1350
status = rec_get_status(rec);
1353
case REC_STATUS_ORDINARY:
1354
ut_ad(n_fields <= dict_index_get_n_fields(index));
1356
case REC_STATUS_NODE_PTR:
1357
/* it doesn't make sense to copy the child page number field */
1358
ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1360
case REC_STATUS_INFIMUM:
1361
case REC_STATUS_SUPREMUM:
1362
/* infimum or supremum record: no sense to copy anything */
1368
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1369
lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1370
UNIV_PREFETCH_R(lens);
1374
/* read the lengths of fields 0..n */
1375
for (i = 0; i < n_fields; i++) {
1376
const dict_field_t* field;
1377
const dict_col_t* col;
1379
field = dict_index_get_nth_field(index, i);
1380
col = dict_field_get_col(field);
1382
if (!(col->prtype & DATA_NOT_NULL)) {
1383
/* nullable field => read the null flag */
1384
if (UNIV_UNLIKELY(!(byte) null_mask)) {
1389
if (*nulls & null_mask) {
1397
if (field->fixed_len) {
1398
prefix_len += field->fixed_len;
1400
ulint len = *lens--;
1401
if (col->len > 255 || col->mtype == DATA_BLOB) {
1407
UNIV_PREFETCH_R(lens);
1414
UNIV_PREFETCH_R(rec + prefix_len);
1416
prefix_len += rec - (lens + 1);
1418
if ((*buf == NULL) || (*buf_size < prefix_len)) {
1423
*buf = mem_alloc2(prefix_len, buf_size);
1426
memcpy(*buf, lens + 1, prefix_len);
1428
return(*buf + (rec - (lens + 1)));
1431
/*******************************************************************
1432
Validates the consistency of an old-style physical record. */
1437
/* out: TRUE if ok */
1438
const rec_t* rec) /* in: physical record */
1448
n_fields = rec_get_n_fields_old(rec);
1450
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1451
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1456
for (i = 0; i < n_fields; i++) {
1457
data = rec_get_nth_field_old(rec, i, &len);
1459
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1461
"InnoDB: Error: record field %lu len %lu\n",
1467
if (len != UNIV_SQL_NULL) {
1469
sum += *(data + len -1); /* dereference the
1474
len_sum += rec_get_nth_field_size(rec, i);
1478
if (len_sum != rec_get_data_size_old(rec)) {
1480
"InnoDB: Error: record len should be %lu, len %lu\n",
1482
rec_get_data_size_old(rec));
1486
rec_dummy = sum; /* This is here only to fool the compiler */
1491
/*******************************************************************
1492
Validates the consistency of a physical record. */
1497
/* out: TRUE if ok */
1498
const rec_t* rec, /* in: physical record */
1499
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1509
n_fields = rec_offs_n_fields(offsets);
1511
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1512
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1517
ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1519
for (i = 0; i < n_fields; i++) {
1520
data = rec_get_nth_field(rec, offsets, i, &len);
1522
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1524
"InnoDB: Error: record field %lu len %lu\n",
1530
if (len != UNIV_SQL_NULL) {
1532
sum += *(data + len -1); /* dereference the
1536
} else if (!rec_offs_comp(offsets)) {
1537
len_sum += rec_get_nth_field_size(rec, i);
1541
if (len_sum != rec_offs_data_size(offsets)) {
1543
"InnoDB: Error: record len should be %lu, len %lu\n",
1545
(ulong) rec_offs_data_size(offsets));
1549
rec_dummy = sum; /* This is here only to fool the compiler */
1551
if (!rec_offs_comp(offsets)) {
1552
ut_a(rec_validate_old(rec));
1558
/*******************************************************************
1559
Prints an old-style physical record. */
1564
FILE* file, /* in: file where to print */
1565
const rec_t* rec) /* in: physical record */
1574
n = rec_get_n_fields_old(rec);
1576
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1577
" %u-byte offsets; info bits %lu\n",
1579
rec_get_1byte_offs_flag(rec) ? 1 : 2,
1580
(ulong) rec_get_info_bits(rec, FALSE));
1582
for (i = 0; i < n; i++) {
1584
data = rec_get_nth_field_old(rec, i, &len);
1586
fprintf(file, " %lu:", (ulong) i);
1588
if (len != UNIV_SQL_NULL) {
1591
ut_print_buf(file, data, len);
1593
ut_print_buf(file, data, 30);
1595
fprintf(file, " (total %lu bytes)",
1599
fprintf(file, " SQL NULL, size %lu ",
1600
rec_get_nth_field_size(rec, i));
1607
rec_validate_old(rec);
1610
/*******************************************************************
1611
Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
1617
FILE* file, /* in: file where to print */
1618
const rec_t* rec, /* in: physical record */
1619
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1623
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1627
data = rec_get_nth_field(rec, offsets, i, &len);
1629
fprintf(file, " %lu:", (ulong) i);
1631
if (len != UNIV_SQL_NULL) {
1634
ut_print_buf(file, data, len);
1636
ut_print_buf(file, data, 30);
1638
fprintf(file, " (total %lu bytes)",
1642
fputs(" SQL NULL", file);
1650
/*******************************************************************
1651
Prints a physical record. */
1656
FILE* file, /* in: file where to print */
1657
const rec_t* rec, /* in: physical record */
1658
const ulint* offsets)/* in: array returned by rec_get_offsets() */
1662
ut_ad(rec_offs_validate(rec, NULL, offsets));
1664
if (!rec_offs_comp(offsets)) {
1665
rec_print_old(file, rec);
1669
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1670
" compact format; info bits %lu\n",
1671
(ulong) rec_offs_n_fields(offsets),
1672
(ulong) rec_get_info_bits(rec, TRUE));
1674
rec_print_comp(file, rec, offsets);
1675
rec_validate(rec, offsets);
1678
/*******************************************************************
1679
Prints a physical record. */
1684
FILE* file, /* in: file where to print */
1685
const rec_t* rec, /* in: physical record */
1686
dict_index_t* index) /* in: record descriptor */
1690
if (!dict_table_is_comp(index->table)) {
1691
rec_print_old(file, rec);
1694
mem_heap_t* heap = NULL;
1695
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1696
rec_offs_init(offsets_);
1698
rec_print_new(file, rec,
1699
rec_get_offsets(rec, index, offsets_,
1700
ULINT_UNDEFINED, &heap));
1701
if (UNIV_LIKELY_NULL(heap)) {
1702
mem_heap_free(heap);