1 /*****************************************************************************
2
3 Copyright (c) 1994, 2021, Oracle and/or its affiliates.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25 *****************************************************************************/
26
27 /********************************************************************//**
28 @file rem/rem0rec.cc
29 Record manager
30
31 Created 5/30/1994 Heikki Tuuri
32 *************************************************************************/
33
34 #include "rem0rec.h"
35
36 #ifdef UNIV_NONINL
37 #include "rem0rec.ic"
38 #endif
39
40 #include "page0page.h"
41 #include "mtr0mtr.h"
42 #include "mtr0log.h"
43 #include "fts0fts.h"
44 #include "gis0geo.h"
45 #include "trx0sys.h"
46 #ifdef WITH_WSREP
47 #include <ha_prototypes.h>
48 #endif /* WITH_WSREP */
49 #include "mach0data.h"
50
51 /* PHYSICAL RECORD (OLD STYLE)
52 ===========================
53
54 The physical record, which is the data type of all the records
55 found in index pages of the database, has the following format
56 (lower addresses and more significant bits inside a byte are below
57 represented on a higher text line):
58
59 | offset of the end of the last field of data, the most significant
60 bit is set to 1 if and only if the field is SQL-null,
61 if the offset is 2-byte, then the second most significant
62 bit is set to 1 if the field is stored on another page:
63 mostly this will occur in the case of big BLOB fields |
64 ...
65 | offset of the end of the first field of data + the SQL-null bit |
66 | 4 bits used to delete mark a record, and mark a predefined
67 minimum record in alphabetical order |
68 | 4 bits giving the number of records owned by this record
69 (this term is explained in page0page.h) |
70 | 13 bits giving the order number of this record in the
71 heap of the index page |
72 | 10 bits giving the number of fields in this record |
73 | 1 bit which is set to 1 if the offsets above are given in
74 one byte format, 0 if in two byte format |
75 | two bytes giving an absolute pointer to the next record in the page |
76 ORIGIN of the record
77 | first field of data |
78 ...
79 | last field of data |
80
81 The origin of the record is the start address of the first field
82 of data. The offsets are given relative to the origin.
83 The offsets of the data fields are stored in an inverted
84 order because then the offset of the first fields are near the
85 origin, giving maybe a better processor cache hit rate in searches.
86
87 The offsets of the data fields are given as one-byte
88 (if there are less than 127 bytes of data in the record)
89 or two-byte unsigned integers. The most significant bit
90 is not part of the offset, instead it indicates the SQL-null
91 if the bit is set to 1. */
92
93 /* PHYSICAL RECORD (NEW STYLE)
94 ===========================
95
96 The physical record, which is the data type of all the records
97 found in index pages of the database, has the following format
98 (lower addresses and more significant bits inside a byte are below
99 represented on a higher text line):
100
101 | length of the last non-null variable-length field of data:
102 if the maximum length is 255, one byte; otherwise,
103 0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
104 length=128..16383, extern storage flag) |
105 ...
106 | length of first variable-length field of data |
107 | SQL-null flags (1 bit per nullable field), padded to full bytes |
108 | 4 bits used to delete mark a record, and mark a predefined
109 minimum record in alphabetical order |
110 | 4 bits giving the number of records owned by this record
111 (this term is explained in page0page.h) |
112 | 13 bits giving the order number of this record in the
113 heap of the index page |
114 | 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
115 010=infimum, 011=supremum, 1xx=reserved |
116 | two bytes giving a relative pointer to the next record in the page |
117 ORIGIN of the record
118 | first field of data |
119 ...
120 | last field of data |
121
122 The origin of the record is the start address of the first field
123 of data. The offsets are given relative to the origin.
124 The offsets of the data fields are stored in an inverted
125 order because then the offset of the first fields are near the
126 origin, giving maybe a better processor cache hit rate in searches.
127
128 The offsets of the data fields are given as one-byte
129 (if there are less than 127 bytes of data in the record)
130 or two-byte unsigned integers. The most significant bit
131 is not part of the offset, instead it indicates the SQL-null
132 if the bit is set to 1. */
133
134 /* CANONICAL COORDINATES. A record can be seen as a single
135 string of 'characters' in the following way: catenate the bytes
136 in each field, in the order of fields. An SQL-null field
137 is taken to be an empty sequence of bytes. Then after
138 the position of each field insert in the string
139 the 'character' <FIELD-END>, except that after an SQL-null field
140 insert <NULL-FIELD-END>. Now the ordinal position of each
141 byte in this canonical string is its canonical coordinate.
142 So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
143 string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
144 We identify prefixes (= initial segments) of a record
145 with prefixes of the canonical string. The canonical
146 length of the prefix is the length of the corresponding
147 prefix of the canonical string. The canonical length of
148 a record is the length of its canonical string.
149
150 For example, the maximal common prefix of records
151 ("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
152 is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
153 length is 5.
154
155 A complete-field prefix of a record is a prefix which ends at the
156 end of some field (containing also <FIELD-END>).
157 A record is a complete-field prefix of another record, if
158 the corresponding canonical strings have the same property. */
159
160 /* this is used to fool compiler in rec_validate */
161 ulint rec_dummy;
162
163 /***************************************************************//**
164 Validates the consistency of an old-style physical record.
165 @return TRUE if ok */
166 static
167 ibool
168 rec_validate_old(
169 /*=============*/
170 const rec_t* rec); /*!< in: physical record */
171
172 /******************************************************//**
173 Determine how many of the first n columns in a compact
174 physical record are stored externally.
175 @return number of externally stored columns */
176 ulint
rec_get_n_extern_new(const rec_t * rec,const dict_index_t * index,ulint n)177 rec_get_n_extern_new(
178 /*=================*/
179 const rec_t* rec, /*!< in: compact physical record */
180 const dict_index_t* index, /*!< in: record descriptor */
181 ulint n) /*!< in: number of columns to scan */
182 {
183 const byte* nulls;
184 const byte* lens;
185 ulint null_mask;
186 ulint n_extern;
187 ulint i;
188
189 ut_ad(dict_table_is_comp(index->table));
190 ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
191 ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
192
193 if (n == ULINT_UNDEFINED) {
194 n = dict_index_get_n_fields(index);
195 }
196
197 nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
198 lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
199 null_mask = 1;
200 n_extern = 0;
201 i = 0;
202
203 /* read the lengths of fields 0..n */
204 do {
205 const dict_field_t* field
206 = dict_index_get_nth_field(index, i);
207 const dict_col_t* col
208 = dict_field_get_col(field);
209 ulint len;
210
211 if (!(col->prtype & DATA_NOT_NULL)) {
212 /* nullable field => read the null flag */
213
214 if (UNIV_UNLIKELY(!(byte) null_mask)) {
215 nulls--;
216 null_mask = 1;
217 }
218
219 if (*nulls & null_mask) {
220 null_mask <<= 1;
221 /* No length is stored for NULL fields. */
222 continue;
223 }
224 null_mask <<= 1;
225 }
226
227 if (UNIV_UNLIKELY(!field->fixed_len)) {
228 /* Variable-length field: read the length */
229 len = *lens--;
230 /* If the maximum length of the field is up
231 to 255 bytes, the actual length is always
232 stored in one byte. If the maximum length is
233 more than 255 bytes, the actual length is
234 stored in one byte for 0..127. The length
235 will be encoded in two bytes when it is 128 or
236 more, or when the field is stored externally. */
237 if (DATA_BIG_COL(col)) {
238 if (len & 0x80) {
239 /* 1exxxxxxx xxxxxxxx */
240 if (len & 0x40) {
241 n_extern++;
242 }
243 lens--;
244 }
245 }
246 }
247 } while (++i < n);
248
249 return(n_extern);
250 }
251
252 /******************************************************//**
253 Determine the offset to each field in a leaf-page record
254 in ROW_FORMAT=COMPACT. This is a special case of
255 rec_init_offsets() and rec_get_offsets_func(). */
UNIV_INLINE(nonnull)256 UNIV_INLINE MY_ATTRIBUTE((nonnull))
257 void
258 rec_init_offsets_comp_ordinary(
259 /*===========================*/
260 const rec_t* rec, /*!< in: physical record in
261 ROW_FORMAT=COMPACT */
262 bool temp, /*!< in: whether to use the
263 format for temporary files in
264 index creation */
265 const dict_index_t* index, /*!< in: record descriptor */
266 ulint* offsets)/*!< in/out: array of offsets;
267 in: n=rec_offs_n_fields(offsets) */
268 {
269 ulint i = 0;
270 ulint offs = 0;
271 ulint any_ext = 0;
272 ulint n_null = index->n_nullable;
273 const byte* nulls = temp
274 ? rec - 1
275 : rec - (1 + REC_N_NEW_EXTRA_BYTES);
276 const byte* lens = nulls - UT_BITS_IN_BYTES(n_null);
277 ulint null_mask = 1;
278
279 #ifdef UNIV_DEBUG
280 /* We cannot invoke rec_offs_make_valid() here if temp=true.
281 Similarly, rec_offs_validate() will fail in that case, because
282 it invokes rec_get_status(). */
283 offsets[2] = (ulint) rec;
284 offsets[3] = (ulint) index;
285 #endif /* UNIV_DEBUG */
286
287 ut_ad(temp || dict_table_is_comp(index->table));
288
289 if (temp && dict_table_is_comp(index->table)) {
290 /* No need to do adjust fixed_len=0. We only need to
291 adjust it for ROW_FORMAT=REDUNDANT. */
292 temp = false;
293 }
294
295 /* read the lengths of fields 0..n */
296 do {
297 const dict_field_t* field
298 = dict_index_get_nth_field(index, i);
299 const dict_col_t* col
300 = dict_field_get_col(field);
301 ulint len;
302
303 if (!(col->prtype & DATA_NOT_NULL)) {
304 /* nullable field => read the null flag */
305 ut_ad(n_null--);
306
307 if (UNIV_UNLIKELY(!(byte) null_mask)) {
308 nulls--;
309 null_mask = 1;
310 }
311
312 if (*nulls & null_mask) {
313 null_mask <<= 1;
314 /* No length is stored for NULL fields.
315 We do not advance offs, and we set
316 the length to zero and enable the
317 SQL NULL flag in offsets[]. */
318 len = offs | REC_OFFS_SQL_NULL;
319 goto resolved;
320 }
321 null_mask <<= 1;
322 }
323
324 if (!field->fixed_len
325 || (temp && !dict_col_get_fixed_size(col, temp))) {
326 ut_ad(col->mtype != DATA_POINT);
327 /* Variable-length field: read the length */
328 len = *lens--;
329 /* If the maximum length of the field is up
330 to 255 bytes, the actual length is always
331 stored in one byte. If the maximum length is
332 more than 255 bytes, the actual length is
333 stored in one byte for 0..127. The length
334 will be encoded in two bytes when it is 128 or
335 more, or when the field is stored externally. */
336 if (DATA_BIG_COL(col)) {
337 if (len & 0x80) {
338 /* 1exxxxxxx xxxxxxxx */
339 len <<= 8;
340 len |= *lens--;
341
342 offs += len & 0x3fff;
343 if (UNIV_UNLIKELY(len
344 & 0x4000)) {
345 ut_ad(dict_index_is_clust
346 (index));
347 any_ext = REC_OFFS_EXTERNAL;
348 len = offs
349 | REC_OFFS_EXTERNAL;
350 } else {
351 len = offs;
352 }
353
354 goto resolved;
355 }
356 }
357
358 len = offs += len;
359 } else {
360 len = offs += field->fixed_len;
361 }
362 resolved:
363 rec_offs_base(offsets)[i + 1] = len;
364 } while (++i < rec_offs_n_fields(offsets));
365
366 *rec_offs_base(offsets)
367 = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
368 }
369
370 /******************************************************//**
371 The following function determines the offsets to each field in the
372 record. The offsets are written to a previously allocated array of
373 ulint, where rec_offs_n_fields(offsets) has been initialized to the
374 number of fields in the record. The rest of the array will be
375 initialized by this function. rec_offs_base(offsets)[0] will be set
376 to the extra size (if REC_OFFS_COMPACT is set, the record is in the
377 new format; if REC_OFFS_EXTERNAL is set, the record contains externally
378 stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
379 offsets past the end of fields 0..n_fields, or to the beginning of
380 fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
381 is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
382 high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
383 field i is being stored externally. */
384 static
385 void
rec_init_offsets(const rec_t * rec,const dict_index_t * index,ulint * offsets)386 rec_init_offsets(
387 /*=============*/
388 const rec_t* rec, /*!< in: physical record */
389 const dict_index_t* index, /*!< in: record descriptor */
390 ulint* offsets)/*!< in/out: array of offsets;
391 in: n=rec_offs_n_fields(offsets) */
392 {
393 ulint i = 0;
394 ulint offs;
395
396 rec_offs_make_valid(rec, index, offsets);
397
398 if (dict_table_is_comp(index->table)) {
399 const byte* nulls;
400 const byte* lens;
401 dict_field_t* field;
402 ulint null_mask;
403 ulint status = rec_get_status(rec);
404 ulint n_node_ptr_field = ULINT_UNDEFINED;
405
406 switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
407 case REC_STATUS_INFIMUM:
408 case REC_STATUS_SUPREMUM:
409 /* the field is 8 bytes long */
410 rec_offs_base(offsets)[0]
411 = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
412 rec_offs_base(offsets)[1] = 8;
413 return;
414 case REC_STATUS_NODE_PTR:
415 n_node_ptr_field
416 = dict_index_get_n_unique_in_tree_nonleaf(
417 index);
418 break;
419 case REC_STATUS_ORDINARY:
420 rec_init_offsets_comp_ordinary(
421 rec, false, index, offsets);
422 return;
423 }
424
425 nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
426 lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
427 offs = 0;
428 null_mask = 1;
429
430 /* read the lengths of fields 0..n */
431 do {
432 ulint len;
433 if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
434 len = offs += REC_NODE_PTR_SIZE;
435 goto resolved;
436 }
437
438 field = dict_index_get_nth_field(index, i);
439 if (!(dict_field_get_col(field)->prtype
440 & DATA_NOT_NULL)) {
441 /* nullable field => read the null flag */
442
443 if (UNIV_UNLIKELY(!(byte) null_mask)) {
444 nulls--;
445 null_mask = 1;
446 }
447
448 if (*nulls & null_mask) {
449 null_mask <<= 1;
450 /* No length is stored for NULL fields.
451 We do not advance offs, and we set
452 the length to zero and enable the
453 SQL NULL flag in offsets[]. */
454 len = offs | REC_OFFS_SQL_NULL;
455 goto resolved;
456 }
457 null_mask <<= 1;
458 }
459
460 if (UNIV_UNLIKELY(!field->fixed_len)) {
461 const dict_col_t* col
462 = dict_field_get_col(field);
463 /* DATA_POINT should always be a fixed
464 length column. */
465 ut_ad(col->mtype != DATA_POINT);
466 /* Variable-length field: read the length */
467 len = *lens--;
468 /* If the maximum length of the field
469 is up to 255 bytes, the actual length
470 is always stored in one byte. If the
471 maximum length is more than 255 bytes,
472 the actual length is stored in one
473 byte for 0..127. The length will be
474 encoded in two bytes when it is 128 or
475 more, or when the field is stored
476 externally. */
477 if (DATA_BIG_COL(col)) {
478 if (len & 0x80) {
479 /* 1exxxxxxx xxxxxxxx */
480
481 len <<= 8;
482 len |= *lens--;
483
484 /* B-tree node pointers
485 must not contain externally
486 stored columns. Thus
487 the "e" flag must be 0. */
488 ut_a(!(len & 0x4000));
489 offs += len & 0x3fff;
490 len = offs;
491
492 goto resolved;
493 }
494 }
495
496 len = offs += len;
497 } else {
498 len = offs += field->fixed_len;
499 }
500 resolved:
501 rec_offs_base(offsets)[i + 1] = len;
502 } while (++i < rec_offs_n_fields(offsets));
503
504 *rec_offs_base(offsets)
505 = (rec - (lens + 1)) | REC_OFFS_COMPACT;
506 } else {
507 /* Old-style record: determine extra size and end offsets */
508 offs = REC_N_OLD_EXTRA_BYTES;
509 if (rec_get_1byte_offs_flag(rec)) {
510 offs += rec_offs_n_fields(offsets);
511 *rec_offs_base(offsets) = offs;
512 /* Determine offsets to fields */
513 do {
514 offs = rec_1_get_field_end_info(rec, i);
515 if (offs & REC_1BYTE_SQL_NULL_MASK) {
516 offs &= ~REC_1BYTE_SQL_NULL_MASK;
517 offs |= REC_OFFS_SQL_NULL;
518 }
519 rec_offs_base(offsets)[1 + i] = offs;
520 } while (++i < rec_offs_n_fields(offsets));
521 } else {
522 offs += 2 * rec_offs_n_fields(offsets);
523 *rec_offs_base(offsets) = offs;
524 /* Determine offsets to fields */
525 do {
526 offs = rec_2_get_field_end_info(rec, i);
527 if (offs & REC_2BYTE_SQL_NULL_MASK) {
528 offs &= ~REC_2BYTE_SQL_NULL_MASK;
529 offs |= REC_OFFS_SQL_NULL;
530 }
531 if (offs & REC_2BYTE_EXTERN_MASK) {
532 offs &= ~REC_2BYTE_EXTERN_MASK;
533 offs |= REC_OFFS_EXTERNAL;
534 *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
535 }
536 rec_offs_base(offsets)[1 + i] = offs;
537 } while (++i < rec_offs_n_fields(offsets));
538 }
539 }
540 }
541
542 /******************************************************//**
543 The following function determines the offsets to each field
544 in the record. It can reuse a previously returned array.
545 @return the new offsets */
546 ulint*
rec_get_offsets_func(const rec_t * rec,const dict_index_t * index,ulint * offsets,ulint n_fields,const char * file,ulint line,mem_heap_t ** heap)547 rec_get_offsets_func(
548 /*=================*/
549 const rec_t* rec, /*!< in: physical record */
550 const dict_index_t* index, /*!< in: record descriptor */
551 ulint* offsets,/*!< in/out: array consisting of
552 offsets[0] allocated elements,
553 or an array from rec_get_offsets(),
554 or NULL */
555 ulint n_fields,/*!< in: maximum number of
556 initialized fields
557 (ULINT_UNDEFINED if all fields) */
558 #ifdef UNIV_DEBUG
559 const char* file, /*!< in: file name where called */
560 ulint line, /*!< in: line number where called */
561 #endif /* UNIV_DEBUG */
562 mem_heap_t** heap) /*!< in/out: memory heap */
563 {
564 ulint n;
565 ulint size;
566
567 ut_ad(rec);
568 ut_ad(index);
569 ut_ad(heap);
570
571 if (dict_table_is_comp(index->table)) {
572 switch (UNIV_EXPECT(rec_get_status(rec),
573 REC_STATUS_ORDINARY)) {
574 case REC_STATUS_ORDINARY:
575 n = dict_index_get_n_fields(index);
576 break;
577 case REC_STATUS_NODE_PTR:
578 /* Node pointer records consist of the
579 uniquely identifying fields of the record
580 followed by a child page number field. */
581 n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1;
582 break;
583 case REC_STATUS_INFIMUM:
584 case REC_STATUS_SUPREMUM:
585 /* infimum or supremum record */
586 n = 1;
587 break;
588 default:
589 ut_error;
590 return(NULL);
591 }
592 } else {
593 n = rec_get_n_fields_old(rec);
594 }
595
596 if (UNIV_UNLIKELY(n_fields < n)) {
597 n = n_fields;
598 }
599
600 /* The offsets header consists of the allocation size at
601 offsets[0] and the REC_OFFS_HEADER_SIZE bytes. */
602 size = n + (1 + REC_OFFS_HEADER_SIZE);
603
604 if (UNIV_UNLIKELY(!offsets)
605 || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
606 if (UNIV_UNLIKELY(!*heap)) {
607 *heap = mem_heap_create_at(size * sizeof(ulint),
608 file, line);
609 }
610 offsets = static_cast<ulint*>(
611 mem_heap_alloc(*heap, size * sizeof(ulint)));
612
613 rec_offs_set_n_alloc(offsets, size);
614 }
615
616 rec_offs_set_n_fields(offsets, n);
617 rec_init_offsets(rec, index, offsets);
618 return(offsets);
619 }
620
621 /******************************************************//**
622 The following function determines the offsets to each field
623 in the record. It can reuse a previously allocated array. */
624 void
rec_get_offsets_reverse(const byte * extra,const dict_index_t * index,ulint node_ptr,ulint * offsets)625 rec_get_offsets_reverse(
626 /*====================*/
627 const byte* extra, /*!< in: the extra bytes of a
628 compact record in reverse order,
629 excluding the fixed-size
630 REC_N_NEW_EXTRA_BYTES */
631 const dict_index_t* index, /*!< in: record descriptor */
632 ulint node_ptr,/*!< in: nonzero=node pointer,
633 0=leaf node */
634 ulint* offsets)/*!< in/out: array consisting of
635 offsets[0] allocated elements */
636 {
637 ulint n;
638 ulint i;
639 ulint offs;
640 ulint any_ext;
641 const byte* nulls;
642 const byte* lens;
643 dict_field_t* field;
644 ulint null_mask;
645 ulint n_node_ptr_field;
646
647 ut_ad(extra);
648 ut_ad(index);
649 ut_ad(offsets);
650 ut_ad(dict_table_is_comp(index->table));
651
652 if (UNIV_UNLIKELY(node_ptr)) {
653 n_node_ptr_field =
654 dict_index_get_n_unique_in_tree_nonleaf(index);
655 n = n_node_ptr_field + 1;
656 } else {
657 n_node_ptr_field = ULINT_UNDEFINED;
658 n = dict_index_get_n_fields(index);
659 }
660
661 ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
662 rec_offs_set_n_fields(offsets, n);
663
664 nulls = extra;
665 lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
666 i = offs = 0;
667 null_mask = 1;
668 any_ext = 0;
669
670 /* read the lengths of fields 0..n */
671 do {
672 ulint len;
673 if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
674 len = offs += REC_NODE_PTR_SIZE;
675 goto resolved;
676 }
677
678 field = dict_index_get_nth_field(index, i);
679 if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
680 /* nullable field => read the null flag */
681
682 if (UNIV_UNLIKELY(!(byte) null_mask)) {
683 nulls++;
684 null_mask = 1;
685 }
686
687 if (*nulls & null_mask) {
688 null_mask <<= 1;
689 /* No length is stored for NULL fields.
690 We do not advance offs, and we set
691 the length to zero and enable the
692 SQL NULL flag in offsets[]. */
693 len = offs | REC_OFFS_SQL_NULL;
694 goto resolved;
695 }
696 null_mask <<= 1;
697 }
698
699 if (UNIV_UNLIKELY(!field->fixed_len)) {
700 /* Variable-length field: read the length */
701 const dict_col_t* col
702 = dict_field_get_col(field);
703 len = *lens++;
704 /* If the maximum length of the field is up
705 to 255 bytes, the actual length is always
706 stored in one byte. If the maximum length is
707 more than 255 bytes, the actual length is
708 stored in one byte for 0..127. The length
709 will be encoded in two bytes when it is 128 or
710 more, or when the field is stored externally. */
711 if (DATA_BIG_COL(col)) {
712 if (len & 0x80) {
713 /* 1exxxxxxx xxxxxxxx */
714 len <<= 8;
715 len |= *lens++;
716
717 offs += len & 0x3fff;
718 if (UNIV_UNLIKELY(len & 0x4000)) {
719 any_ext = REC_OFFS_EXTERNAL;
720 len = offs | REC_OFFS_EXTERNAL;
721 } else {
722 len = offs;
723 }
724
725 goto resolved;
726 }
727 }
728
729 len = offs += len;
730 } else {
731 len = offs += field->fixed_len;
732 }
733 resolved:
734 rec_offs_base(offsets)[i + 1] = len;
735 } while (++i < rec_offs_n_fields(offsets));
736
737 ut_ad(lens >= extra);
738 *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
739 | REC_OFFS_COMPACT | any_ext;
740 }
741
742 /************************************************************//**
743 The following function is used to get the offset to the nth
744 data field in an old-style record.
745 @return offset to the field */
746 ulint
rec_get_nth_field_offs_old(const rec_t * rec,ulint n,ulint * len)747 rec_get_nth_field_offs_old(
748 /*=======================*/
749 const rec_t* rec, /*!< in: record */
750 ulint n, /*!< in: index of the field */
751 ulint* len) /*!< out: length of the field;
752 UNIV_SQL_NULL if SQL null */
753 {
754 ulint os;
755 ulint next_os;
756
757 ut_ad(len);
758 ut_a(rec);
759 ut_a(n < rec_get_n_fields_old(rec));
760
761 if (rec_get_1byte_offs_flag(rec)) {
762 os = rec_1_get_field_start_offs(rec, n);
763
764 next_os = rec_1_get_field_end_info(rec, n);
765
766 if (next_os & REC_1BYTE_SQL_NULL_MASK) {
767 *len = UNIV_SQL_NULL;
768
769 return(os);
770 }
771
772 next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
773 } else {
774 os = rec_2_get_field_start_offs(rec, n);
775
776 next_os = rec_2_get_field_end_info(rec, n);
777
778 if (next_os & REC_2BYTE_SQL_NULL_MASK) {
779 *len = UNIV_SQL_NULL;
780
781 return(os);
782 }
783
784 next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
785 | REC_2BYTE_EXTERN_MASK);
786 }
787
788 *len = next_os - os;
789
790 ut_ad(*len < UNIV_PAGE_SIZE);
791
792 return(os);
793 }
794
795 /**********************************************************//**
796 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
797 @return total size */
798 UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(1,2)))
799 ulint
rec_get_converted_size_comp_prefix_low(const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint * extra,bool temp)800 rec_get_converted_size_comp_prefix_low(
801 /*===================================*/
802 const dict_index_t* index, /*!< in: record descriptor;
803 dict_table_is_comp() is
804 assumed to hold, even if
805 it does not */
806 const dfield_t* fields, /*!< in: array of data fields */
807 ulint n_fields,/*!< in: number of data fields */
808 const dtuple_t* v_entry,/*!< in: dtuple contains virtual column
809 data */
810 ulint* extra, /*!< out: extra size */
811 bool temp) /*!< in: whether this is a
812 temporary file record */
813 {
814 ulint extra_size;
815 ulint data_size;
816 ulint i;
817 ulint n_null = (n_fields > 0) ? index->n_nullable : 0;
818 ulint n_v_fields;
819 ut_ad(n_fields <= dict_index_get_n_fields(index));
820 ut_ad(!temp || extra);
821
822 /* At the time being, only temp file record could possible
823 store virtual columns */
824 ut_ad(!v_entry || (dict_index_is_clust(index) && temp));
825 n_v_fields = v_entry ? dtuple_get_n_v_fields(v_entry) : 0;
826
827 extra_size = temp
828 ? UT_BITS_IN_BYTES(n_null)
829 : REC_N_NEW_EXTRA_BYTES
830 + UT_BITS_IN_BYTES(n_null);
831 data_size = 0;
832
833 if (temp && dict_table_is_comp(index->table)) {
834 /* No need to do adjust fixed_len=0. We only need to
835 adjust it for ROW_FORMAT=REDUNDANT. */
836 temp = false;
837 }
838
839 /* read the lengths of fields 0..n */
840 for (i = 0; i < n_fields; i++) {
841 const dict_field_t* field;
842 ulint len;
843 ulint fixed_len;
844 const dict_col_t* col;
845
846 field = dict_index_get_nth_field(index, i);
847 len = dfield_get_len(&fields[i]);
848 col = dict_field_get_col(field);
849
850 #ifdef UNIV_DEBUG
851 dtype_t* type;
852
853 type = dfield_get_type(&fields[i]);
854 if (dict_index_is_spatial(index)) {
855 if (DATA_GEOMETRY_MTYPE(col->mtype) && i == 0) {
856 ut_ad(type->prtype & DATA_GIS_MBR);
857 } else {
858 ut_ad(type->mtype == DATA_SYS_CHILD
859 || dict_col_type_assert_equal(col, type));
860 }
861 } else {
862 ut_ad(dict_col_type_assert_equal(col, type));
863 }
864 #endif
865
866 /* All NULLable fields must be included in the n_null count. */
867 ut_ad((col->prtype & DATA_NOT_NULL) || n_null--);
868
869 if (dfield_is_null(&fields[i])) {
870 /* No length is stored for NULL fields. */
871 ut_ad(!(col->prtype & DATA_NOT_NULL));
872 continue;
873 }
874
875 ut_ad(len <= col->len || DATA_LARGE_MTYPE(col->mtype)
876 || (DATA_POINT_MTYPE(col->mtype)
877 && len == DATA_MBR_LEN)
878 || (col->len == 0 && col->mtype == DATA_VARCHAR));
879
880 fixed_len = field->fixed_len;
881 if (temp && fixed_len
882 && !dict_col_get_fixed_size(col, temp)) {
883 fixed_len = 0;
884 }
885 /* If the maximum length of a variable-length field
886 is up to 255 bytes, the actual length is always stored
887 in one byte. If the maximum length is more than 255
888 bytes, the actual length is stored in one byte for
889 0..127. The length will be encoded in two bytes when
890 it is 128 or more, or when the field is stored externally. */
891
892 if (fixed_len) {
893 #ifdef UNIV_DEBUG
894 ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
895 ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
896
897 ut_ad(len <= fixed_len);
898
899 if (dict_index_is_spatial(index)) {
900 ut_ad(type->mtype == DATA_SYS_CHILD
901 || !mbmaxlen
902 || len >= mbminlen * (fixed_len
903 / mbmaxlen));
904 } else {
905 ut_ad(type->mtype != DATA_SYS_CHILD);
906 ut_ad(!mbmaxlen
907 || len >= mbminlen * (fixed_len
908 / mbmaxlen));
909 }
910
911 /* dict_index_add_col() should guarantee this */
912 ut_ad(!field->prefix_len
913 || fixed_len == field->prefix_len);
914 #endif /* UNIV_DEBUG */
915 } else if (dfield_is_ext(&fields[i])) {
916 ut_ad(DATA_BIG_COL(col));
917 extra_size += 2;
918 } else if (len < 128 || !DATA_BIG_COL(col)) {
919 extra_size++;
920 } else {
921 /* For variable-length columns, we look up the
922 maximum length from the column itself. If this
923 is a prefix index column shorter than 256 bytes,
924 this will waste one byte. */
925 extra_size += 2;
926 }
927 data_size += len;
928 }
929
930 if (extra) {
931 *extra = extra_size;
932 }
933
934 /* Log virtual columns */
935 if (n_v_fields != 0) {
936 /* length marker */
937 data_size += 2;
938
939 for (i = 0; i < n_v_fields; i++) {
940 dfield_t* vfield;
941 ulint flen;
942
943 const dict_v_col_t* col
944 = dict_table_get_nth_v_col(index->table, i);
945
946 /* Only those indexed needs to be logged */
947 if (col->m_col.ord_part) {
948 data_size += mach_get_compressed_size(
949 i + REC_MAX_N_FIELDS);
950 vfield = dtuple_get_nth_v_field(
951 v_entry, col->v_pos);
952
953 flen = vfield->len;
954
955 if (flen != UNIV_SQL_NULL) {
956 flen = ut_min(
957 flen,
958 static_cast<ulint>(
959 DICT_MAX_FIELD_LEN_BY_FORMAT(
960 index->table)));
961 data_size += flen;
962 }
963
964 data_size += mach_get_compressed_size(flen);
965 }
966 }
967 }
968
969 return(extra_size + data_size);
970 }
971
972 /**********************************************************//**
973 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
974 @return total size */
975 ulint
rec_get_converted_size_comp_prefix(const dict_index_t * index,const dfield_t * fields,ulint n_fields,ulint * extra)976 rec_get_converted_size_comp_prefix(
977 /*===============================*/
978 const dict_index_t* index, /*!< in: record descriptor */
979 const dfield_t* fields, /*!< in: array of data fields */
980 ulint n_fields,/*!< in: number of data fields */
981 ulint* extra) /*!< out: extra size */
982 {
983 ut_ad(dict_table_is_comp(index->table));
984 return(rec_get_converted_size_comp_prefix_low(
985 index, fields, n_fields, NULL, extra, false));
986 }
987
988 /**********************************************************//**
989 Determines the size of a data tuple in ROW_FORMAT=COMPACT.
990 @return total size */
991 ulint
rec_get_converted_size_comp(const dict_index_t * index,ulint status,const dfield_t * fields,ulint n_fields,ulint * extra)992 rec_get_converted_size_comp(
993 /*========================*/
994 const dict_index_t* index, /*!< in: record descriptor;
995 dict_table_is_comp() is
996 assumed to hold, even if
997 it does not */
998 ulint status, /*!< in: status bits of the record */
999 const dfield_t* fields, /*!< in: array of data fields */
1000 ulint n_fields,/*!< in: number of data fields */
1001 ulint* extra) /*!< out: extra size */
1002 {
1003 ulint size;
1004 ut_ad(n_fields > 0);
1005
1006 switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1007 case REC_STATUS_ORDINARY:
1008 ut_ad(n_fields == dict_index_get_n_fields(index));
1009 size = 0;
1010 break;
1011 case REC_STATUS_NODE_PTR:
1012 n_fields--;
1013 ut_ad(n_fields == dict_index_get_n_unique_in_tree_nonleaf(
1014 index));
1015 ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
1016 size = REC_NODE_PTR_SIZE; /* child page number */
1017 break;
1018 case REC_STATUS_INFIMUM:
1019 case REC_STATUS_SUPREMUM:
1020 /* infimum or supremum record, 8 data bytes */
1021 if (UNIV_LIKELY_NULL(extra)) {
1022 *extra = REC_N_NEW_EXTRA_BYTES;
1023 }
1024 return(REC_N_NEW_EXTRA_BYTES + 8);
1025 default:
1026 ut_error;
1027 return(ULINT_UNDEFINED);
1028 }
1029
1030 return(size + rec_get_converted_size_comp_prefix_low(
1031 index, fields, n_fields, NULL, extra, false));
1032 }
1033
1034 /***********************************************************//**
1035 Sets the value of the ith field SQL null bit of an old-style record. */
1036 void
rec_set_nth_field_null_bit(rec_t * rec,ulint i,ibool val)1037 rec_set_nth_field_null_bit(
1038 /*=======================*/
1039 rec_t* rec, /*!< in: record */
1040 ulint i, /*!< in: ith field */
1041 ibool val) /*!< in: value to set */
1042 {
1043 ulint info;
1044
1045 if (rec_get_1byte_offs_flag(rec)) {
1046
1047 info = rec_1_get_field_end_info(rec, i);
1048
1049 if (val) {
1050 info = info | REC_1BYTE_SQL_NULL_MASK;
1051 } else {
1052 info = info & ~REC_1BYTE_SQL_NULL_MASK;
1053 }
1054
1055 rec_1_set_field_end_info(rec, i, info);
1056
1057 return;
1058 }
1059
1060 info = rec_2_get_field_end_info(rec, i);
1061
1062 if (val) {
1063 info = info | REC_2BYTE_SQL_NULL_MASK;
1064 } else {
1065 info = info & ~REC_2BYTE_SQL_NULL_MASK;
1066 }
1067
1068 rec_2_set_field_end_info(rec, i, info);
1069 }
1070
1071 /***********************************************************//**
1072 Sets an old-style record field to SQL null.
1073 The physical size of the field is not changed. */
1074 void
rec_set_nth_field_sql_null(rec_t * rec,ulint n)1075 rec_set_nth_field_sql_null(
1076 /*=======================*/
1077 rec_t* rec, /*!< in: record */
1078 ulint n) /*!< in: index of the field */
1079 {
1080 ulint offset;
1081
1082 offset = rec_get_field_start_offs(rec, n);
1083
1084 data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
1085
1086 rec_set_nth_field_null_bit(rec, n, TRUE);
1087 }
1088
1089 /*********************************************************//**
1090 Builds an old-style physical record out of a data tuple and
1091 stores it beginning from the start of the given buffer.
1092 @return pointer to the origin of physical record */
1093 static
1094 rec_t*
rec_convert_dtuple_to_rec_old(byte * buf,const dtuple_t * dtuple,ulint n_ext)1095 rec_convert_dtuple_to_rec_old(
1096 /*==========================*/
1097 byte* buf, /*!< in: start address of the physical record */
1098 const dtuple_t* dtuple, /*!< in: data tuple */
1099 ulint n_ext) /*!< in: number of externally stored columns */
1100 {
1101 const dfield_t* field;
1102 ulint n_fields;
1103 ulint data_size;
1104 rec_t* rec;
1105 ulint end_offset;
1106 ulint ored_offset;
1107 ulint len;
1108 ulint i;
1109
1110 ut_ad(buf && dtuple);
1111 ut_ad(dtuple_validate(dtuple));
1112 ut_ad(dtuple_check_typed(dtuple));
1113
1114 n_fields = dtuple_get_n_fields(dtuple);
1115 data_size = dtuple_get_data_size(dtuple, 0);
1116
1117 ut_ad(n_fields > 0);
1118
1119 /* Calculate the offset of the origin in the physical record */
1120
1121 rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
1122 #ifdef UNIV_DEBUG
1123 /* Suppress Valgrind warnings of ut_ad()
1124 in mach_write_to_1(), mach_write_to_2() et al. */
1125 memset(buf, 0xff, rec - buf + data_size);
1126 #endif /* UNIV_DEBUG */
1127 /* Store the number of fields */
1128 rec_set_n_fields_old(rec, n_fields);
1129
1130 /* Set the info bits of the record */
1131 rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
1132 & REC_INFO_BITS_MASK);
1133
1134 /* Store the data and the offsets */
1135
1136 end_offset = 0;
1137
1138 if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1139
1140 rec_set_1byte_offs_flag(rec, TRUE);
1141
1142 for (i = 0; i < n_fields; i++) {
1143
1144 field = dtuple_get_nth_field(dtuple, i);
1145
1146 if (dfield_is_null(field)) {
1147 len = dtype_get_sql_null_size(
1148 dfield_get_type(field), 0);
1149 data_write_sql_null(rec + end_offset, len);
1150
1151 end_offset += len;
1152 ored_offset = end_offset
1153 | REC_1BYTE_SQL_NULL_MASK;
1154 } else {
1155 /* If the data is not SQL null, store it */
1156 len = dfield_get_len(field);
1157
1158 memcpy(rec + end_offset,
1159 dfield_get_data(field), len);
1160
1161 end_offset += len;
1162 ored_offset = end_offset;
1163 }
1164
1165 rec_1_set_field_end_info(rec, i, ored_offset);
1166 }
1167 } else {
1168 rec_set_1byte_offs_flag(rec, FALSE);
1169
1170 for (i = 0; i < n_fields; i++) {
1171
1172 field = dtuple_get_nth_field(dtuple, i);
1173
1174 if (dfield_is_null(field)) {
1175 len = dtype_get_sql_null_size(
1176 dfield_get_type(field), 0);
1177 data_write_sql_null(rec + end_offset, len);
1178
1179 end_offset += len;
1180 ored_offset = end_offset
1181 | REC_2BYTE_SQL_NULL_MASK;
1182 } else {
1183 /* If the data is not SQL null, store it */
1184 len = dfield_get_len(field);
1185
1186 memcpy(rec + end_offset,
1187 dfield_get_data(field), len);
1188
1189 end_offset += len;
1190 ored_offset = end_offset;
1191
1192 if (dfield_is_ext(field)) {
1193 ored_offset |= REC_2BYTE_EXTERN_MASK;
1194 }
1195 }
1196
1197 rec_2_set_field_end_info(rec, i, ored_offset);
1198 }
1199 }
1200
1201 return(rec);
1202 }
1203
1204 /*********************************************************//**
1205 Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1206 UNIV_INLINE
1207 void
rec_convert_dtuple_to_rec_comp(rec_t * rec,const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint status,bool temp)1208 rec_convert_dtuple_to_rec_comp(
1209 /*===========================*/
1210 rec_t* rec, /*!< in: origin of record */
1211 const dict_index_t* index, /*!< in: record descriptor */
1212 const dfield_t* fields, /*!< in: array of data fields */
1213 ulint n_fields,/*!< in: number of data fields */
1214 const dtuple_t* v_entry,/*!< in: dtuple contains
1215 virtual column data */
1216 ulint status, /*!< in: status bits of the record */
1217 bool temp) /*!< in: whether to use the
1218 format for temporary files in
1219 index creation */
1220 {
1221 const dfield_t* field;
1222 const dtype_t* type;
1223 byte* end;
1224 byte* nulls;
1225 byte* lens;
1226 ulint len;
1227 ulint i;
1228 ulint n_node_ptr_field;
1229 ulint fixed_len;
1230 ulint null_mask = 1;
1231 ulint n_null;
1232 ulint num_v = v_entry ? dtuple_get_n_v_fields(v_entry) : 0;
1233
1234 ut_ad(temp || dict_table_is_comp(index->table));
1235
1236 if (temp) {
1237 ut_ad(status == REC_STATUS_ORDINARY);
1238 ut_ad(n_fields <= dict_index_get_n_fields(index));
1239 n_node_ptr_field = ULINT_UNDEFINED;
1240 nulls = rec - 1;
1241 if (dict_table_is_comp(index->table)) {
1242 /* No need to do adjust fixed_len=0. We only
1243 need to adjust it for ROW_FORMAT=REDUNDANT. */
1244 temp = false;
1245 }
1246 } else {
1247 ut_ad(v_entry == NULL);
1248 ut_ad(num_v == 0);
1249 nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1250
1251 switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1252 case REC_STATUS_ORDINARY:
1253 ut_ad(n_fields <= dict_index_get_n_fields(index));
1254 n_node_ptr_field = ULINT_UNDEFINED;
1255 break;
1256 case REC_STATUS_NODE_PTR:
1257 ut_ad(n_fields
1258 == dict_index_get_n_unique_in_tree_nonleaf(index)
1259 + 1);
1260 n_node_ptr_field = n_fields - 1;
1261 break;
1262 case REC_STATUS_INFIMUM:
1263 case REC_STATUS_SUPREMUM:
1264 ut_ad(n_fields == 1);
1265 n_node_ptr_field = ULINT_UNDEFINED;
1266 break;
1267 default:
1268 ut_error;
1269 return;
1270 }
1271 }
1272
1273 end = rec;
1274
1275 if (n_fields != 0) {
1276 n_null = index->n_nullable;
1277 lens = nulls - UT_BITS_IN_BYTES(n_null);
1278 /* clear the SQL-null flags */
1279 memset(lens + 1, 0, nulls - lens);
1280 }
1281
1282 /* Store the data and the offsets */
1283
1284 for (i = 0; i < n_fields; i++) {
1285 const dict_field_t* ifield;
1286 dict_col_t* col = NULL;
1287
1288 field = &fields[i];
1289
1290 type = dfield_get_type(field);
1291 len = dfield_get_len(field);
1292
1293 if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1294 ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1295 ut_ad(len == REC_NODE_PTR_SIZE);
1296 memcpy(end, dfield_get_data(field), len);
1297 end += REC_NODE_PTR_SIZE;
1298 break;
1299 }
1300
1301 if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1302 /* nullable field */
1303 ut_ad(n_null--);
1304
1305 if (UNIV_UNLIKELY(!(byte) null_mask)) {
1306 nulls--;
1307 null_mask = 1;
1308 }
1309
1310 ut_ad(*nulls < null_mask);
1311
1312 /* set the null flag if necessary */
1313 if (dfield_is_null(field)) {
1314 *nulls |= null_mask;
1315 null_mask <<= 1;
1316 continue;
1317 }
1318
1319 null_mask <<= 1;
1320 }
1321 /* only nullable fields can be null */
1322 ut_ad(!dfield_is_null(field));
1323
1324 ifield = dict_index_get_nth_field(index, i);
1325 fixed_len = ifield->fixed_len;
1326 col = ifield->col;
1327 if (temp && fixed_len
1328 && !dict_col_get_fixed_size(col, temp)) {
1329 fixed_len = 0;
1330 }
1331
1332 /* If the maximum length of a variable-length field
1333 is up to 255 bytes, the actual length is always stored
1334 in one byte. If the maximum length is more than 255
1335 bytes, the actual length is stored in one byte for
1336 0..127. The length will be encoded in two bytes when
1337 it is 128 or more, or when the field is stored externally. */
1338 if (fixed_len) {
1339 #ifdef UNIV_DEBUG
1340 ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
1341 ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
1342
1343 ut_ad(len <= fixed_len);
1344 ut_ad(!mbmaxlen || len >= mbminlen
1345 * (fixed_len / mbmaxlen));
1346 ut_ad(!dfield_is_ext(field));
1347 #endif /* UNIV_DEBUG */
1348 } else if (dfield_is_ext(field)) {
1349 ut_ad(DATA_BIG_COL(col));
1350 ut_ad(len <= REC_ANTELOPE_MAX_INDEX_COL_LEN
1351 + BTR_EXTERN_FIELD_REF_SIZE);
1352 *lens-- = (byte) (len >> 8) | 0xc0;
1353 *lens-- = (byte) len;
1354 } else {
1355 /* DATA_POINT would have a fixed_len */
1356 ut_ad(dtype_get_mtype(type) != DATA_POINT);
1357 ut_ad(len <= dtype_get_len(type)
1358 || DATA_LARGE_MTYPE(dtype_get_mtype(type))
1359 || !strcmp(index->name,
1360 FTS_INDEX_TABLE_IND_NAME));
1361 if (len < 128 || !DATA_BIG_LEN_MTYPE(
1362 dtype_get_len(type), dtype_get_mtype(type))) {
1363
1364 *lens-- = (byte) len;
1365 } else {
1366 ut_ad(len < 16384);
1367 *lens-- = (byte) (len >> 8) | 0x80;
1368 *lens-- = (byte) len;
1369 }
1370 }
1371
1372 memcpy(end, dfield_get_data(field), len);
1373 end += len;
1374 }
1375
1376 if (!num_v) {
1377 return;
1378 }
1379
1380 /* reserve 2 bytes for writing length */
1381 byte* ptr = end;
1382 ptr += 2;
1383
1384 /* Now log information on indexed virtual columns */
1385 for (ulint col_no = 0; col_no < num_v; col_no++) {
1386 dfield_t* vfield;
1387 ulint flen;
1388
1389 const dict_v_col_t* col
1390 = dict_table_get_nth_v_col(index->table, col_no);
1391
1392 if (col->m_col.ord_part) {
1393 ulint pos = col_no;
1394
1395 pos += REC_MAX_N_FIELDS;
1396
1397 ptr += mach_write_compressed(ptr, pos);
1398
1399 vfield = dtuple_get_nth_v_field(
1400 v_entry, col->v_pos);
1401
1402 flen = vfield->len;
1403
1404 if (flen != UNIV_SQL_NULL) {
1405 /* The virtual column can only be in sec
1406 index, and index key length is bound by
1407 DICT_MAX_FIELD_LEN_BY_FORMAT */
1408 flen = ut_min(
1409 flen,
1410 static_cast<ulint>(
1411 DICT_MAX_FIELD_LEN_BY_FORMAT(
1412 index->table)));
1413 }
1414
1415 ptr += mach_write_compressed(ptr, flen);
1416
1417 if (flen != UNIV_SQL_NULL) {
1418 ut_memcpy(ptr, dfield_get_data(vfield), flen);
1419 ptr += flen;
1420 }
1421 }
1422 }
1423
1424 mach_write_to_2(end, ptr - end);
1425 }
1426
1427 /*********************************************************//**
1428 Builds a new-style physical record out of a data tuple and
1429 stores it beginning from the start of the given buffer.
1430 @return pointer to the origin of physical record */
1431 static
1432 rec_t*
rec_convert_dtuple_to_rec_new(byte * buf,const dict_index_t * index,const dtuple_t * dtuple)1433 rec_convert_dtuple_to_rec_new(
1434 /*==========================*/
1435 byte* buf, /*!< in: start address of
1436 the physical record */
1437 const dict_index_t* index, /*!< in: record descriptor */
1438 const dtuple_t* dtuple) /*!< in: data tuple */
1439 {
1440 ulint extra_size;
1441 ulint status;
1442 rec_t* rec;
1443
1444 status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1445 rec_get_converted_size_comp(
1446 index, status, dtuple->fields, dtuple->n_fields, &extra_size);
1447 rec = buf + extra_size;
1448
1449 rec_convert_dtuple_to_rec_comp(
1450 rec, index, dtuple->fields, dtuple->n_fields, NULL,
1451 status, false);
1452
1453 /* Set the info bits of the record */
1454 rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1455
1456 return(rec);
1457 }
1458
1459 /*********************************************************//**
1460 Builds a physical record out of a data tuple and
1461 stores it beginning from the start of the given buffer.
1462 @return pointer to the origin of physical record */
1463 rec_t*
rec_convert_dtuple_to_rec(byte * buf,const dict_index_t * index,const dtuple_t * dtuple,ulint n_ext)1464 rec_convert_dtuple_to_rec(
1465 /*======================*/
1466 byte* buf, /*!< in: start address of the
1467 physical record */
1468 const dict_index_t* index, /*!< in: record descriptor */
1469 const dtuple_t* dtuple, /*!< in: data tuple */
1470 ulint n_ext) /*!< in: number of
1471 externally stored columns */
1472 {
1473 rec_t* rec;
1474
1475 ut_ad(buf != NULL);
1476 ut_ad(index != NULL);
1477 ut_ad(dtuple != NULL);
1478 ut_ad(dtuple_validate(dtuple));
1479 ut_ad(dtuple_check_typed(dtuple));
1480
1481 if (dict_table_is_comp(index->table)) {
1482 rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1483 } else {
1484 rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1485 }
1486
1487 #ifdef UNIV_DEBUG
1488 {
1489 mem_heap_t* heap = NULL;
1490 ulint offsets_[REC_OFFS_NORMAL_SIZE];
1491 const ulint* offsets;
1492 ulint i;
1493 rec_offs_init(offsets_);
1494
1495 offsets = rec_get_offsets(rec, index,
1496 offsets_, ULINT_UNDEFINED, &heap);
1497 ut_ad(rec_validate(rec, offsets));
1498 ut_ad(dtuple_get_n_fields(dtuple)
1499 == rec_offs_n_fields(offsets));
1500
1501 for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1502 ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
1503 == !rec_offs_nth_extern(offsets, i));
1504 }
1505
1506 if (UNIV_LIKELY_NULL(heap)) {
1507 mem_heap_free(heap);
1508 }
1509 }
1510 #endif /* UNIV_DEBUG */
1511 return(rec);
1512 }
1513
1514 #ifndef UNIV_HOTBACKUP
1515 /**********************************************************//**
1516 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
1517 @return total size */
1518 ulint
rec_get_converted_size_temp(const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint * extra)1519 rec_get_converted_size_temp(
1520 /*========================*/
1521 const dict_index_t* index, /*!< in: record descriptor */
1522 const dfield_t* fields, /*!< in: array of data fields */
1523 ulint n_fields,/*!< in: number of data fields */
1524 const dtuple_t* v_entry,/*!< in: dtuple contains virtual column
1525 data */
1526 ulint* extra) /*!< out: extra size */
1527 {
1528 return(rec_get_converted_size_comp_prefix_low(
1529 index, fields, n_fields, v_entry, extra, true));
1530 }
1531
1532 /******************************************************//**
1533 Determine the offset to each field in temporary file.
1534 @see rec_convert_dtuple_to_temp() */
1535 void
rec_init_offsets_temp(const rec_t * rec,const dict_index_t * index,ulint * offsets)1536 rec_init_offsets_temp(
1537 /*==================*/
1538 const rec_t* rec, /*!< in: temporary file record */
1539 const dict_index_t* index, /*!< in: record descriptor */
1540 ulint* offsets)/*!< in/out: array of offsets;
1541 in: n=rec_offs_n_fields(offsets) */
1542 {
1543 rec_init_offsets_comp_ordinary(rec, true, index, offsets);
1544 }
1545
1546 /*********************************************************//**
1547 Builds a temporary file record out of a data tuple.
1548 @see rec_init_offsets_temp() */
1549 void
rec_convert_dtuple_to_temp(rec_t * rec,const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry)1550 rec_convert_dtuple_to_temp(
1551 /*=======================*/
1552 rec_t* rec, /*!< out: record */
1553 const dict_index_t* index, /*!< in: record descriptor */
1554 const dfield_t* fields, /*!< in: array of data fields */
1555 ulint n_fields, /*!< in: number of fields */
1556 const dtuple_t* v_entry) /*!< in: dtuple contains
1557 virtual column data */
1558 {
1559 rec_convert_dtuple_to_rec_comp(rec, index, fields, n_fields, v_entry,
1560 REC_STATUS_ORDINARY, true);
1561 }
1562
1563 /**************************************************************//**
1564 Copies the first n fields of a physical record to a data tuple. The fields
1565 are copied to the memory heap. */
1566 void
rec_copy_prefix_to_dtuple(dtuple_t * tuple,const rec_t * rec,const dict_index_t * index,ulint n_fields,mem_heap_t * heap)1567 rec_copy_prefix_to_dtuple(
1568 /*======================*/
1569 dtuple_t* tuple, /*!< out: data tuple */
1570 const rec_t* rec, /*!< in: physical record */
1571 const dict_index_t* index, /*!< in: record descriptor */
1572 ulint n_fields, /*!< in: number of fields
1573 to copy */
1574 mem_heap_t* heap) /*!< in: memory heap */
1575 {
1576 ulint i;
1577 ulint offsets_[REC_OFFS_NORMAL_SIZE];
1578 ulint* offsets = offsets_;
1579 rec_offs_init(offsets_);
1580
1581 offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1582
1583 ut_ad(rec_validate(rec, offsets));
1584 ut_ad(dtuple_check_typed(tuple));
1585
1586 dtuple_set_info_bits(tuple, rec_get_info_bits(
1587 rec, dict_table_is_comp(index->table)));
1588
1589 for (i = 0; i < n_fields; i++) {
1590 dfield_t* field;
1591 const byte* data;
1592 ulint len;
1593
1594 field = dtuple_get_nth_field(tuple, i);
1595 data = rec_get_nth_field(rec, offsets, i, &len);
1596
1597 if (len != UNIV_SQL_NULL) {
1598 dfield_set_data(field,
1599 mem_heap_dup(heap, data, len), len);
1600 ut_ad(!rec_offs_nth_extern(offsets, i));
1601 } else {
1602 dfield_set_null(field);
1603 }
1604 }
1605 }
1606
1607 /**************************************************************//**
1608 Copies the first n fields of an old-style physical record
1609 to a new physical record in a buffer.
1610 @return own: copied record */
1611 static
1612 rec_t*
rec_copy_prefix_to_buf_old(const rec_t * rec,ulint n_fields,ulint area_end,byte ** buf,ulint * buf_size)1613 rec_copy_prefix_to_buf_old(
1614 /*=======================*/
1615 const rec_t* rec, /*!< in: physical record */
1616 ulint n_fields, /*!< in: number of fields to copy */
1617 ulint area_end, /*!< in: end of the prefix data */
1618 byte** buf, /*!< in/out: memory buffer for
1619 the copied prefix, or NULL */
1620 ulint* buf_size) /*!< in/out: buffer size */
1621 {
1622 rec_t* copy_rec;
1623 ulint area_start;
1624 ulint prefix_len;
1625
1626 if (rec_get_1byte_offs_flag(rec)) {
1627 area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1628 } else {
1629 area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1630 }
1631
1632 prefix_len = area_start + area_end;
1633
1634 if ((*buf == NULL) || (*buf_size < prefix_len)) {
1635 ut_free(*buf);
1636 *buf_size = prefix_len;
1637 *buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
1638 }
1639
1640 ut_memcpy(*buf, rec - area_start, prefix_len);
1641
1642 copy_rec = *buf + area_start;
1643
1644 rec_set_n_fields_old(copy_rec, n_fields);
1645
1646 return(copy_rec);
1647 }
1648
1649 /**************************************************************//**
1650 Copies the first n fields of a physical record to a new physical record in
1651 a buffer.
1652 @return own: copied record */
1653 rec_t*
rec_copy_prefix_to_buf(const rec_t * rec,const dict_index_t * index,ulint n_fields,byte ** buf,ulint * buf_size)1654 rec_copy_prefix_to_buf(
1655 /*===================*/
1656 const rec_t* rec, /*!< in: physical record */
1657 const dict_index_t* index, /*!< in: record descriptor */
1658 ulint n_fields, /*!< in: number of fields
1659 to copy */
1660 byte** buf, /*!< in/out: memory buffer
1661 for the copied prefix,
1662 or NULL */
1663 ulint* buf_size) /*!< in/out: buffer size */
1664 {
1665 const byte* nulls;
1666 const byte* lens;
1667 ulint i;
1668 ulint prefix_len;
1669 ulint null_mask;
1670 ulint status;
1671 bool is_rtr_node_ptr = false;
1672
1673 UNIV_PREFETCH_RW(*buf);
1674
1675 if (!dict_table_is_comp(index->table)) {
1676 ut_ad(rec_validate_old(rec));
1677 return(rec_copy_prefix_to_buf_old(
1678 rec, n_fields,
1679 rec_get_field_start_offs(rec, n_fields),
1680 buf, buf_size));
1681 }
1682
1683 status = rec_get_status(rec);
1684
1685 switch (status) {
1686 case REC_STATUS_ORDINARY:
1687 ut_ad(n_fields <= dict_index_get_n_fields(index));
1688 break;
1689 case REC_STATUS_NODE_PTR:
1690 /* For R-tree, we need to copy the child page number field. */
1691 if (dict_index_is_spatial(index)) {
1692 ut_ad(n_fields == DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1);
1693 is_rtr_node_ptr = true;
1694 } else {
1695 /* it doesn't make sense to copy the child page number
1696 field */
1697 ut_ad(n_fields <=
1698 dict_index_get_n_unique_in_tree_nonleaf(index));
1699 }
1700 break;
1701 case REC_STATUS_INFIMUM:
1702 case REC_STATUS_SUPREMUM:
1703 /* infimum or supremum record: no sense to copy anything */
1704 default:
1705 ut_error;
1706 return(NULL);
1707 }
1708
1709 nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1710 lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1711 UNIV_PREFETCH_R(lens);
1712 prefix_len = 0;
1713 null_mask = 1;
1714
1715 /* read the lengths of fields 0..n */
1716 for (i = 0; i < n_fields; i++) {
1717 const dict_field_t* field;
1718 const dict_col_t* col;
1719
1720 field = dict_index_get_nth_field(index, i);
1721 col = dict_field_get_col(field);
1722
1723 if (!(col->prtype & DATA_NOT_NULL)) {
1724 /* nullable field => read the null flag */
1725 if (UNIV_UNLIKELY(!(byte) null_mask)) {
1726 nulls--;
1727 null_mask = 1;
1728 }
1729
1730 if (*nulls & null_mask) {
1731 null_mask <<= 1;
1732 continue;
1733 }
1734
1735 null_mask <<= 1;
1736 }
1737
1738 if (is_rtr_node_ptr && i == 1) {
1739 /* For rtree node ptr rec, we need to
1740 copy the page no field with 4 bytes len. */
1741 prefix_len += 4;
1742 } else if (field->fixed_len) {
1743 prefix_len += field->fixed_len;
1744 } else {
1745 ulint len = *lens--;
1746 /* If the maximum length of the column is up
1747 to 255 bytes, the actual length is always
1748 stored in one byte. If the maximum length is
1749 more than 255 bytes, the actual length is
1750 stored in one byte for 0..127. The length
1751 will be encoded in two bytes when it is 128 or
1752 more, or when the column is stored externally. */
1753 if (DATA_BIG_COL(col)) {
1754 if (len & 0x80) {
1755 /* 1exxxxxx */
1756 len &= 0x3f;
1757 len <<= 8;
1758 len |= *lens--;
1759 UNIV_PREFETCH_R(lens);
1760 }
1761 }
1762 prefix_len += len;
1763 }
1764 }
1765
1766 UNIV_PREFETCH_R(rec + prefix_len);
1767
1768 prefix_len += rec - (lens + 1);
1769
1770 if ((*buf == NULL) || (*buf_size < prefix_len)) {
1771 ut_free(*buf);
1772 *buf_size = prefix_len;
1773 *buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
1774 }
1775
1776 memcpy(*buf, lens + 1, prefix_len);
1777
1778 return(*buf + (rec - (lens + 1)));
1779 }
1780 #endif /* UNIV_HOTBACKUP */
1781
1782 /***************************************************************//**
1783 Validates the consistency of an old-style physical record.
1784 @return TRUE if ok */
1785 static
1786 ibool
rec_validate_old(const rec_t * rec)1787 rec_validate_old(
1788 /*=============*/
1789 const rec_t* rec) /*!< in: physical record */
1790 {
1791 const byte* data;
1792 ulint len;
1793 ulint n_fields;
1794 ulint len_sum = 0;
1795 ulint sum = 0;
1796 ulint i;
1797
1798 ut_a(rec);
1799 n_fields = rec_get_n_fields_old(rec);
1800
1801 if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1802 ib::error() << "Record has " << n_fields << " fields";
1803 return(FALSE);
1804 }
1805
1806 for (i = 0; i < n_fields; i++) {
1807 data = rec_get_nth_field_old(rec, i, &len);
1808
1809 if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1810 ib::error() << "Record field " << i << " len " << len;
1811 return(FALSE);
1812 }
1813
1814 if (len != UNIV_SQL_NULL) {
1815 len_sum += len;
1816 sum += *(data + len -1); /* dereference the
1817 end of the field to
1818 cause a memory trap
1819 if possible */
1820 } else {
1821 len_sum += rec_get_nth_field_size(rec, i);
1822 }
1823 }
1824
1825 if (len_sum != rec_get_data_size_old(rec)) {
1826 ib::error() << "Record len should be " << len_sum << ", len "
1827 << rec_get_data_size_old(rec);
1828 return(FALSE);
1829 }
1830
1831 rec_dummy = sum; /* This is here only to fool the compiler */
1832
1833 return(TRUE);
1834 }
1835
1836 /***************************************************************//**
1837 Validates the consistency of a physical record.
1838 @return TRUE if ok */
1839 ibool
rec_validate(const rec_t * rec,const ulint * offsets)1840 rec_validate(
1841 /*=========*/
1842 const rec_t* rec, /*!< in: physical record */
1843 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1844 {
1845 const byte* data;
1846 ulint len;
1847 ulint n_fields;
1848 ulint len_sum = 0;
1849 ulint sum = 0;
1850 ulint i;
1851
1852 ut_a(rec);
1853 n_fields = rec_offs_n_fields(offsets);
1854
1855 if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1856 ib::error() << "Record has " << n_fields << " fields";
1857 return(FALSE);
1858 }
1859
1860 ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1861
1862 for (i = 0; i < n_fields; i++) {
1863 data = rec_get_nth_field(rec, offsets, i, &len);
1864
1865 if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1866 ib::error() << "Record field " << i << " len " << len;
1867 return(FALSE);
1868 }
1869
1870 if (len != UNIV_SQL_NULL) {
1871 len_sum += len;
1872 sum += *(data + len -1); /* dereference the
1873 end of the field to
1874 cause a memory trap
1875 if possible */
1876 } else if (!rec_offs_comp(offsets)) {
1877 len_sum += rec_get_nth_field_size(rec, i);
1878 }
1879 }
1880
1881 if (len_sum != rec_offs_data_size(offsets)) {
1882 ib::error() << "Record len should be " << len_sum << ", len "
1883 << rec_offs_data_size(offsets);
1884 return(FALSE);
1885 }
1886
1887 rec_dummy = sum; /* This is here only to fool the compiler */
1888
1889 if (!rec_offs_comp(offsets)) {
1890 ut_a(rec_validate_old(rec));
1891 }
1892
1893 return(TRUE);
1894 }
1895
1896 /***************************************************************//**
1897 Prints an old-style physical record. */
1898 void
rec_print_old(FILE * file,const rec_t * rec)1899 rec_print_old(
1900 /*==========*/
1901 FILE* file, /*!< in: file where to print */
1902 const rec_t* rec) /*!< in: physical record */
1903 {
1904 const byte* data;
1905 ulint len;
1906 ulint n;
1907 ulint i;
1908
1909 ut_ad(rec);
1910
1911 n = rec_get_n_fields_old(rec);
1912
1913 fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1914 " %u-byte offsets; info bits %lu\n",
1915 (ulong) n,
1916 rec_get_1byte_offs_flag(rec) ? 1 : 2,
1917 (ulong) rec_get_info_bits(rec, FALSE));
1918
1919 for (i = 0; i < n; i++) {
1920
1921 data = rec_get_nth_field_old(rec, i, &len);
1922
1923 fprintf(file, " %lu:", (ulong) i);
1924
1925 if (len != UNIV_SQL_NULL) {
1926 if (len <= 30) {
1927
1928 ut_print_buf(file, data, len);
1929 } else {
1930 ut_print_buf(file, data, 30);
1931
1932 fprintf(file, " (total %lu bytes)",
1933 (ulong) len);
1934 }
1935 } else {
1936 fprintf(file, " SQL NULL, size " ULINTPF " ",
1937 rec_get_nth_field_size(rec, i));
1938 }
1939
1940 putc(';', file);
1941 putc('\n', file);
1942 }
1943
1944 rec_validate_old(rec);
1945 }
1946
1947 #ifndef UNIV_HOTBACKUP
1948 /***************************************************************//**
1949 Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
1950 record header. */
1951 void
rec_print_comp(FILE * file,const rec_t * rec,const ulint * offsets)1952 rec_print_comp(
1953 /*===========*/
1954 FILE* file, /*!< in: file where to print */
1955 const rec_t* rec, /*!< in: physical record */
1956 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1957 {
1958 ulint i;
1959
1960 for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1961 const byte* data;
1962 ulint len;
1963
1964 data = rec_get_nth_field(rec, offsets, i, &len);
1965
1966 fprintf(file, " %lu:", (ulong) i);
1967
1968 if (len != UNIV_SQL_NULL) {
1969 if (len <= 30) {
1970
1971 ut_print_buf(file, data, len);
1972 } else if (rec_offs_nth_extern(offsets, i)) {
1973 ut_print_buf(file, data, 30);
1974 fprintf(file, " (total %lu bytes, external)",
1975 (ulong) len);
1976 ut_print_buf(file, data + len
1977 - BTR_EXTERN_FIELD_REF_SIZE,
1978 BTR_EXTERN_FIELD_REF_SIZE);
1979 } else {
1980 ut_print_buf(file, data, 30);
1981
1982 fprintf(file, " (total %lu bytes)",
1983 (ulong) len);
1984 }
1985 } else {
1986 fputs(" SQL NULL", file);
1987 }
1988 putc(';', file);
1989 putc('\n', file);
1990 }
1991 }
1992
1993 /***************************************************************//**
1994 Prints an old-style spatial index record. */
1995 void
rec_print_mbr_old(FILE * file,const rec_t * rec)1996 rec_print_mbr_old(
1997 /*==============*/
1998 FILE* file, /*!< in: file where to print */
1999 const rec_t* rec) /*!< in: physical record */
2000 {
2001 const byte* data;
2002 ulint len;
2003 ulint n;
2004 ulint i;
2005
2006 ut_ad(rec);
2007
2008 n = rec_get_n_fields_old(rec);
2009
2010 fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
2011 " %u-byte offsets; info bits %lu\n",
2012 (ulong) n,
2013 rec_get_1byte_offs_flag(rec) ? 1 : 2,
2014 (ulong) rec_get_info_bits(rec, FALSE));
2015
2016 for (i = 0; i < n; i++) {
2017
2018 data = rec_get_nth_field_old(rec, i, &len);
2019
2020 fprintf(file, " %lu:", (ulong) i);
2021
2022 if (len != UNIV_SQL_NULL) {
2023 if (i == 0) {
2024 fprintf(file, " MBR:");
2025 for (; len > 0; len -= sizeof(double)) {
2026 double d = mach_double_read(data);
2027
2028 if (len != sizeof(double)) {
2029 fprintf(file, "%.2lf,", d);
2030 } else {
2031 fprintf(file, "%.2lf", d);
2032 }
2033
2034 data += sizeof(double);
2035 }
2036 } else {
2037 if (len <= 30) {
2038
2039 ut_print_buf(file, data, len);
2040 } else {
2041 ut_print_buf(file, data, 30);
2042
2043 fprintf(file, " (total %lu bytes)",
2044 (ulong) len);
2045 }
2046 }
2047 } else {
2048 fprintf(file, " SQL NULL, size " ULINTPF " ",
2049 rec_get_nth_field_size(rec, i));
2050 }
2051
2052 putc(';', file);
2053 putc('\n', file);
2054 }
2055
2056 if (rec_get_deleted_flag(rec, false)) {
2057 fprintf(file, " Deleted");
2058 }
2059
2060 if (rec_get_info_bits(rec, true) & REC_INFO_MIN_REC_FLAG) {
2061 fprintf(file, " First rec");
2062 }
2063
2064 rec_validate_old(rec);
2065 }
2066
2067 /***************************************************************//**
2068 Prints a spatial index record. */
2069 void
rec_print_mbr_rec(FILE * file,const rec_t * rec,const ulint * offsets)2070 rec_print_mbr_rec(
2071 /*==============*/
2072 FILE* file, /*!< in: file where to print */
2073 const rec_t* rec, /*!< in: physical record */
2074 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
2075 {
2076 ut_ad(rec);
2077 ut_ad(offsets);
2078 ut_ad(rec_offs_validate(rec, NULL, offsets));
2079
2080 if (!rec_offs_comp(offsets)) {
2081 rec_print_mbr_old(file, rec);
2082 return;
2083 }
2084
2085 for (ulint i = 0; i < rec_offs_n_fields(offsets); i++) {
2086 const byte* data;
2087 ulint len;
2088
2089 data = rec_get_nth_field(rec, offsets, i, &len);
2090
2091 if (i == 0) {
2092 fprintf(file, " MBR:");
2093 for (; len > 0; len -= sizeof(double)) {
2094 double d = mach_double_read(data);
2095
2096 if (len != sizeof(double)) {
2097 fprintf(file, "%.2lf,", d);
2098 } else {
2099 fprintf(file, "%.2lf", d);
2100 }
2101
2102 data += sizeof(double);
2103 }
2104 } else {
2105 fprintf(file, " %lu:", (ulong) i);
2106
2107 if (len != UNIV_SQL_NULL) {
2108 if (len <= 30) {
2109
2110 ut_print_buf(file, data, len);
2111 } else {
2112 ut_print_buf(file, data, 30);
2113
2114 fprintf(file, " (total %lu bytes)",
2115 (ulong) len);
2116 }
2117 } else {
2118 fputs(" SQL NULL", file);
2119 }
2120 }
2121 putc(';', file);
2122 }
2123
2124 if (rec_get_info_bits(rec, true) & REC_INFO_DELETED_FLAG) {
2125 fprintf(file, " Deleted");
2126 }
2127
2128 if (rec_get_info_bits(rec, true) & REC_INFO_MIN_REC_FLAG) {
2129 fprintf(file, " First rec");
2130 }
2131
2132
2133 rec_validate(rec, offsets);
2134 }
2135
2136 /***************************************************************//**
2137 Prints a physical record. */
2138 /***************************************************************//**
2139 Prints a physical record. */
2140 void
rec_print_new(FILE * file,const rec_t * rec,const ulint * offsets)2141 rec_print_new(
2142 /*==========*/
2143 FILE* file, /*!< in: file where to print */
2144 const rec_t* rec, /*!< in: physical record */
2145 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
2146 {
2147 ut_ad(rec);
2148 ut_ad(offsets);
2149 ut_ad(rec_offs_validate(rec, NULL, offsets));
2150
2151 #ifdef UNIV_DEBUG
2152 if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
2153 DBUG_PRINT("info", ("deleted "));
2154 } else {
2155 DBUG_PRINT("info", ("not-deleted "));
2156 }
2157 #endif /* UNIV_DEBUG */
2158
2159 if (!rec_offs_comp(offsets)) {
2160 rec_print_old(file, rec);
2161 return;
2162 }
2163
2164 fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
2165 " compact format; info bits %lu\n",
2166 (ulong) rec_offs_n_fields(offsets),
2167 (ulong) rec_get_info_bits(rec, TRUE));
2168
2169 rec_print_comp(file, rec, offsets);
2170 rec_validate(rec, offsets);
2171 }
2172
2173 /***************************************************************//**
2174 Prints a physical record. */
2175 void
rec_print(FILE * file,const rec_t * rec,const dict_index_t * index)2176 rec_print(
2177 /*======*/
2178 FILE* file, /*!< in: file where to print */
2179 const rec_t* rec, /*!< in: physical record */
2180 const dict_index_t* index) /*!< in: record descriptor */
2181 {
2182 ut_ad(index);
2183
2184 if (!dict_table_is_comp(index->table)) {
2185 rec_print_old(file, rec);
2186 return;
2187 } else {
2188 mem_heap_t* heap = NULL;
2189 ulint offsets_[REC_OFFS_NORMAL_SIZE];
2190 rec_offs_init(offsets_);
2191
2192 rec_print_new(file, rec,
2193 rec_get_offsets(rec, index, offsets_,
2194 ULINT_UNDEFINED, &heap));
2195 if (UNIV_LIKELY_NULL(heap)) {
2196 mem_heap_free(heap);
2197 }
2198 }
2199 }
2200
2201 /** Pretty-print a record.
2202 @param[in,out] o output stream
2203 @param[in] rec physical record
2204 @param[in] info rec_get_info_bits(rec)
2205 @param[in] offsets rec_get_offsets(rec) */
2206 void
rec_print(std::ostream & o,const rec_t * rec,ulint info,const ulint * offsets)2207 rec_print(
2208 std::ostream& o,
2209 const rec_t* rec,
2210 ulint info,
2211 const ulint* offsets)
2212 {
2213 const ulint comp = rec_offs_comp(offsets);
2214 const ulint n = rec_offs_n_fields(offsets);
2215
2216 ut_ad(rec_offs_validate(rec, NULL, offsets));
2217
2218 o << (comp ? "COMPACT RECORD" : "RECORD")
2219 << "(info_bits=" << info << ", " << n << " fields): {";
2220
2221 for (ulint i = 0; i < n; i++) {
2222 const byte* data;
2223 ulint len;
2224
2225 if (i) {
2226 o << ',';
2227 }
2228
2229 data = rec_get_nth_field(rec, offsets, i, &len);
2230
2231 if (len == UNIV_SQL_NULL) {
2232 o << "NULL";
2233 continue;
2234 }
2235
2236 if (rec_offs_nth_extern(offsets, i)) {
2237 ulint local_len = len - BTR_EXTERN_FIELD_REF_SIZE;
2238 ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
2239
2240 o << '['
2241 << local_len
2242 << '+' << BTR_EXTERN_FIELD_REF_SIZE << ']';
2243 ut_print_buf(o, data, local_len);
2244 ut_print_buf_hex(o, data + local_len,
2245 BTR_EXTERN_FIELD_REF_SIZE);
2246 } else {
2247 o << '[' << len << ']';
2248 ut_print_buf(o, data, len);
2249 }
2250 }
2251
2252 o << "}";
2253 }
2254
2255 /** Display a record.
2256 @param[in,out] o output stream
2257 @param[in] r record to display
2258 @return the output stream */
2259 std::ostream&
operator <<(std::ostream & o,const rec_index_print & r)2260 operator<<(std::ostream& o, const rec_index_print& r)
2261 {
2262 mem_heap_t* heap = NULL;
2263 ulint* offsets = rec_get_offsets(
2264 r.m_rec, r.m_index, NULL, ULINT_UNDEFINED, &heap);
2265 rec_print(o, r.m_rec,
2266 rec_get_info_bits(r.m_rec, rec_offs_comp(offsets)),
2267 offsets);
2268 mem_heap_free(heap);
2269 return(o);
2270 }
2271
2272 /** Display a record.
2273 @param[in,out] o output stream
2274 @param[in] r record to display
2275 @return the output stream */
2276 std::ostream&
operator <<(std::ostream & o,const rec_offsets_print & r)2277 operator<<(std::ostream& o, const rec_offsets_print& r)
2278 {
2279 rec_print(o, r.m_rec,
2280 rec_get_info_bits(r.m_rec, rec_offs_comp(r.m_offsets)),
2281 r.m_offsets);
2282 return(o);
2283 }
2284
2285 # ifdef UNIV_DEBUG
2286 /************************************************************//**
2287 Reads the DB_TRX_ID of a clustered index record.
2288 @return the value of DB_TRX_ID */
2289 trx_id_t
rec_get_trx_id(const rec_t * rec,const dict_index_t * index)2290 rec_get_trx_id(
2291 /*===========*/
2292 const rec_t* rec, /*!< in: record */
2293 const dict_index_t* index) /*!< in: clustered index */
2294 {
2295 const page_t* page
2296 = page_align(rec);
2297 ulint trx_id_col
2298 = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
2299 const byte* trx_id;
2300 ulint len;
2301 mem_heap_t* heap = NULL;
2302 ulint offsets_[REC_OFFS_NORMAL_SIZE];
2303 ulint* offsets = offsets_;
2304 rec_offs_init(offsets_);
2305
2306 ut_ad(fil_page_index_page_check(page));
2307 ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID)
2308 == index->id);
2309 ut_ad(dict_index_is_clust(index));
2310 ut_ad(trx_id_col > 0);
2311 ut_ad(trx_id_col != ULINT_UNDEFINED);
2312
2313 offsets = rec_get_offsets(rec, index, offsets, trx_id_col + 1, &heap);
2314
2315 trx_id = rec_get_nth_field(rec, offsets, trx_id_col, &len);
2316
2317 ut_ad(len == DATA_TRX_ID_LEN);
2318
2319 if (heap) {
2320 mem_heap_free(heap);
2321 }
2322
2323 return(trx_read_trx_id(trx_id));
2324 }
2325 # endif /* UNIV_DEBUG */
2326 #endif /* !UNIV_HOTBACKUP */
2327
2328 /** Mark the nth field as externally stored.
2329 @param[in] offsets array returned by rec_get_offsets()
2330 @param[in] n nth field */
2331 void
rec_offs_make_nth_extern(ulint * offsets,const ulint n)2332 rec_offs_make_nth_extern(
2333 ulint* offsets,
2334 const ulint n)
2335 {
2336 ut_ad(!rec_offs_nth_sql_null(offsets, n));
2337 rec_offs_base(offsets)[1 + n] |= REC_OFFS_EXTERNAL;
2338 }
2339 #ifdef WITH_WSREP
2340 dberr_t
wsrep_rec_get_foreign_key(byte * buf,ulint * buf_len,const rec_t * rec,dict_index_t * index_for,dict_index_t * index_ref,ibool new_protocol)2341 wsrep_rec_get_foreign_key(
2342 byte *buf, /* out: extracted key */
2343 ulint *buf_len, /* in/out: length of buf */
2344 const rec_t* rec, /* in: physical record */
2345 dict_index_t* index_for, /* in: index in foreign table */
2346 dict_index_t* index_ref, /* in: index in referenced table */
2347 ibool new_protocol) /* in: protocol > 1 */
2348 {
2349 const byte* data;
2350 ulint len;
2351 ulint key_len = 0;
2352 ulint i;
2353 uint key_parts;
2354 mem_heap_t* heap = NULL;
2355 ulint offsets_[REC_OFFS_NORMAL_SIZE];
2356 const ulint* offsets;
2357
2358 ut_ad(index_for);
2359 ut_ad(index_ref);
2360
2361 rec_offs_init(offsets_);
2362 offsets = rec_get_offsets(rec, index_for, offsets_,
2363 ULINT_UNDEFINED, &heap);
2364
2365 ut_ad(rec_offs_validate(rec, NULL, offsets));
2366
2367 ut_ad(rec);
2368
2369 key_parts = dict_index_get_n_unique_in_tree(index_for);
2370 for (i = 0;
2371 i < key_parts &&
2372 (index_for->type & DICT_CLUSTERED || i < key_parts - 1);
2373 i++) {
2374 dict_field_t* field_f =
2375 dict_index_get_nth_field(index_for, i);
2376 const dict_col_t* col_f = dict_field_get_col(field_f);
2377 dict_field_t* field_r =
2378 dict_index_get_nth_field(index_ref, i);
2379 const dict_col_t* col_r = dict_field_get_col(field_r);
2380
2381 data = rec_get_nth_field(rec, offsets, i, &len);
2382 if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) >
2383 *buf_len) {
2384 fprintf (stderr,
2385 "WSREP: FK key len exceeded %lu %lu %lu\n",
2386 key_len, len, *buf_len);
2387 goto err_out;
2388 }
2389
2390 if (len == UNIV_SQL_NULL) {
2391 ut_a(!(col_f->prtype & DATA_NOT_NULL));
2392 *buf++ = 1;
2393 key_len++;
2394 } else if (!new_protocol) {
2395 if (!(col_r->prtype & DATA_NOT_NULL)) {
2396 *buf++ = 0;
2397 key_len++;
2398 }
2399 memcpy(buf, data, len);
2400 *buf_len = wsrep_innobase_mysql_sort(
2401 (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK),
2402 (uint)dtype_get_charset_coll(col_f->prtype),
2403 buf, len, *buf_len);
2404 } else { /* new protocol */
2405 if (!(col_r->prtype & DATA_NOT_NULL)) {
2406 *buf++ = 0;
2407 key_len++;
2408 }
2409 switch (col_f->mtype) {
2410 case DATA_INT: {
2411 byte* ptr = buf+len;
2412 for (;;) {
2413 ptr--;
2414 *ptr = *data;
2415 if (ptr == buf) {
2416 break;
2417 }
2418 data++;
2419 }
2420
2421 if (!(col_f->prtype & DATA_UNSIGNED)) {
2422 buf[len-1] = (byte) (buf[len-1] ^ 128);
2423 }
2424
2425 break;
2426 }
2427 case DATA_VARCHAR:
2428 case DATA_VARMYSQL:
2429 case DATA_CHAR:
2430 case DATA_MYSQL:
2431 /* Copy the actual data */
2432 ut_memcpy(buf, data, len);
2433 len = wsrep_innobase_mysql_sort(
2434 (int)
2435 (col_f->prtype & DATA_MYSQL_TYPE_MASK),
2436 (uint)
2437 dtype_get_charset_coll(col_f->prtype),
2438 buf, len, *buf_len);
2439 break;
2440 case DATA_BLOB:
2441 case DATA_BINARY:
2442 memcpy(buf, data, len);
2443 break;
2444 default:
2445 break;
2446 }
2447
2448 key_len += len;
2449 buf += len;
2450 }
2451 }
2452
2453 rec_validate(rec, offsets);
2454
2455 if (UNIV_LIKELY_NULL(heap)) {
2456 mem_heap_free(heap);
2457 }
2458
2459 *buf_len = key_len;
2460 return DB_SUCCESS;
2461
2462 err_out:
2463 if (UNIV_LIKELY_NULL(heap)) {
2464 mem_heap_free(heap);
2465 }
2466 return DB_ERROR;
2467 }
2468 #endif // WITH_WSREP
2469