Drizzled Public API Documentation

rem0rec.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /********************************************************************/
26 #include "rem0rec.h"
27 
28 #ifdef UNIV_NONINL
29 #include "rem0rec.ic"
30 #endif
31 
32 #include "mtr0mtr.h"
33 #include "mtr0log.h"
34 
35 /* PHYSICAL RECORD (OLD STYLE)
36  ===========================
37 
38 The physical record, which is the data type of all the records
39 found in index pages of the database, has the following format
40 (lower addresses and more significant bits inside a byte are below
41 represented on a higher text line):
42 
43 | offset of the end of the last field of data, the most significant
44  bit is set to 1 if and only if the field is SQL-null,
45  if the offset is 2-byte, then the second most significant
46  bit is set to 1 if the field is stored on another page:
47  mostly this will occur in the case of big BLOB fields |
48 ...
49 | offset of the end of the first field of data + the SQL-null bit |
50 | 4 bits used to delete mark a record, and mark a predefined
51  minimum record in alphabetical order |
52 | 4 bits giving the number of records owned by this record
53  (this term is explained in page0page.h) |
54 | 13 bits giving the order number of this record in the
55  heap of the index page |
56 | 10 bits giving the number of fields in this record |
57 | 1 bit which is set to 1 if the offsets above are given in
58  one byte format, 0 if in two byte format |
59 | two bytes giving an absolute pointer to the next record in the page |
60 ORIGIN of the record
61 | first field of data |
62 ...
63 | last field of data |
64 
65 The origin of the record is the start address of the first field
66 of data. The offsets are given relative to the origin.
67 The offsets of the data fields are stored in an inverted
68 order because then the offset of the first fields are near the
69 origin, giving maybe a better processor cache hit rate in searches.
70 
71 The offsets of the data fields are given as one-byte
72 (if there are less than 127 bytes of data in the record)
73 or two-byte unsigned integers. The most significant bit
74 is not part of the offset, instead it indicates the SQL-null
75 if the bit is set to 1. */
76 
77 /* PHYSICAL RECORD (NEW STYLE)
78  ===========================
79 
80 The physical record, which is the data type of all the records
81 found in index pages of the database, has the following format
82 (lower addresses and more significant bits inside a byte are below
83 represented on a higher text line):
84 
85 | length of the last non-null variable-length field of data:
86  if the maximum length is 255, one byte; otherwise,
87  0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
88  length=128..16383, extern storage flag) |
89 ...
90 | length of first variable-length field of data |
91 | SQL-null flags (1 bit per nullable field), padded to full bytes |
92 | 4 bits used to delete mark a record, and mark a predefined
93  minimum record in alphabetical order |
94 | 4 bits giving the number of records owned by this record
95  (this term is explained in page0page.h) |
96 | 13 bits giving the order number of this record in the
97  heap of the index page |
98 | 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
99  010=infimum, 011=supremum, 1xx=reserved |
100 | two bytes giving a relative pointer to the next record in the page |
101 ORIGIN of the record
102 | first field of data |
103 ...
104 | last field of data |
105 
106 The origin of the record is the start address of the first field
107 of data. The offsets are given relative to the origin.
108 The offsets of the data fields are stored in an inverted
109 order because then the offset of the first fields are near the
110 origin, giving maybe a better processor cache hit rate in searches.
111 
112 The offsets of the data fields are given as one-byte
113 (if there are less than 127 bytes of data in the record)
114 or two-byte unsigned integers. The most significant bit
115 is not part of the offset, instead it indicates the SQL-null
116 if the bit is set to 1. */
117 
118 /* CANONICAL COORDINATES. A record can be seen as a single
119 string of 'characters' in the following way: catenate the bytes
120 in each field, in the order of fields. An SQL-null field
121 is taken to be an empty sequence of bytes. Then after
122 the position of each field insert in the string
123 the 'character' <FIELD-END>, except that after an SQL-null field
124 insert <NULL-FIELD-END>. Now the ordinal position of each
125 byte in this canonical string is its canonical coordinate.
126 So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
127 string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
128 We identify prefixes (= initial segments) of a record
129 with prefixes of the canonical string. The canonical
130 length of the prefix is the length of the corresponding
131 prefix of the canonical string. The canonical length of
132 a record is the length of its canonical string.
133 
134 For example, the maximal common prefix of records
135 ("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
136 is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
137 length is 5.
138 
139 A complete-field prefix of a record is a prefix which ends at the
140 end of some field (containing also <FIELD-END>).
141 A record is a complete-field prefix of another record, if
142 the corresponding canonical strings have the same property. */
143 
144 /* this is used to fool compiler in rec_validate */
145 UNIV_INTERN ulint rec_dummy;
146 
147 /***************************************************************/
150 static
151 ibool
152 rec_validate_old(
153 /*=============*/
154  const rec_t* rec);
156 /******************************************************/
160 UNIV_INTERN
161 ulint
163 /*=================*/
164  const rec_t* rec,
165  dict_index_t* index,
166  ulint n)
167 {
168  const byte* nulls;
169  const byte* lens;
170  dict_field_t* field;
171  ulint null_mask;
172  ulint n_extern;
173  ulint i;
174 
175  ut_ad(dict_table_is_comp(index->table));
176  ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
177  ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
178 
179  if (n == ULINT_UNDEFINED) {
180  n = dict_index_get_n_fields(index);
181  }
182 
183  nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
184  lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
185  null_mask = 1;
186  n_extern = 0;
187  i = 0;
188 
189  /* read the lengths of fields 0..n */
190  do {
191  ulint len;
192 
193  field = dict_index_get_nth_field(index, i);
194  if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
195  /* nullable field => read the null flag */
196 
197  if (UNIV_UNLIKELY(!(byte) null_mask)) {
198  nulls--;
199  null_mask = 1;
200  }
201 
202  if (*nulls & null_mask) {
203  null_mask <<= 1;
204  /* No length is stored for NULL fields. */
205  continue;
206  }
207  null_mask <<= 1;
208  }
209 
210  if (UNIV_UNLIKELY(!field->fixed_len)) {
211  /* Variable-length field: read the length */
212  const dict_col_t* col
213  = dict_field_get_col(field);
214  len = *lens--;
215  /* If the maximum length of the field is up
216  to 255 bytes, the actual length is always
217  stored in one byte. If the maximum length is
218  more than 255 bytes, the actual length is
219  stored in one byte for 0..127. The length
220  will be encoded in two bytes when it is 128 or
221  more, or when the field is stored externally. */
222  if (UNIV_UNLIKELY(col->len > 255)
223  || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
224  if (len & 0x80) {
225  /* 1exxxxxxx xxxxxxxx */
226  if (len & 0x40) {
227  n_extern++;
228  }
229  lens--;
230  }
231  }
232  }
233  } while (++i < n);
234 
235  return(n_extern);
236 }
237 
238 /******************************************************/
242 UNIV_INTERN
243 void
245 /*===========================*/
246  const rec_t* rec,
248  ulint extra,
252  const dict_index_t* index,
253  ulint* offsets)
255 {
256  ulint i = 0;
257  ulint offs = 0;
258  ulint any_ext = 0;
259  const byte* nulls = rec - (extra + 1);
260  const byte* lens = nulls
261  - UT_BITS_IN_BYTES(index->n_nullable);
262  dict_field_t* field;
263  ulint null_mask = 1;
264 
265 #ifdef UNIV_DEBUG
266  /* We cannot invoke rec_offs_make_valid() here, because it can hold
267  that extra != REC_N_NEW_EXTRA_BYTES. Similarly, rec_offs_validate()
268  will fail in that case, because it invokes rec_get_status(). */
269  offsets[2] = (ulint) rec;
270  offsets[3] = (ulint) index;
271 #endif /* UNIV_DEBUG */
272 
273  /* read the lengths of fields 0..n */
274  do {
275  ulint len;
276 
277  field = dict_index_get_nth_field(index, i);
278  if (!(dict_field_get_col(field)->prtype
279  & DATA_NOT_NULL)) {
280  /* nullable field => read the null flag */
281 
282  if (UNIV_UNLIKELY(!(byte) null_mask)) {
283  nulls--;
284  null_mask = 1;
285  }
286 
287  if (*nulls & null_mask) {
288  null_mask <<= 1;
289  /* No length is stored for NULL fields.
290  We do not advance offs, and we set
291  the length to zero and enable the
292  SQL NULL flag in offsets[]. */
293  len = offs | REC_OFFS_SQL_NULL;
294  goto resolved;
295  }
296  null_mask <<= 1;
297  }
298 
299  if (UNIV_UNLIKELY(!field->fixed_len)) {
300  /* Variable-length field: read the length */
301  const dict_col_t* col
302  = dict_field_get_col(field);
303  len = *lens--;
304  /* If the maximum length of the field is up
305  to 255 bytes, the actual length is always
306  stored in one byte. If the maximum length is
307  more than 255 bytes, the actual length is
308  stored in one byte for 0..127. The length
309  will be encoded in two bytes when it is 128 or
310  more, or when the field is stored externally. */
311  if (UNIV_UNLIKELY(col->len > 255)
312  || UNIV_UNLIKELY(col->mtype
313  == DATA_BLOB)) {
314  if (len & 0x80) {
315  /* 1exxxxxxx xxxxxxxx */
316  len <<= 8;
317  len |= *lens--;
318 
319  offs += len & 0x3fff;
320  if (UNIV_UNLIKELY(len
321  & 0x4000)) {
323  (index));
324  any_ext = REC_OFFS_EXTERNAL;
325  len = offs
326  | REC_OFFS_EXTERNAL;
327  } else {
328  len = offs;
329  }
330 
331  goto resolved;
332  }
333  }
334 
335  len = offs += len;
336  } else {
337  len = offs += field->fixed_len;
338  }
339 resolved:
340  rec_offs_base(offsets)[i + 1] = len;
341  } while (++i < rec_offs_n_fields(offsets));
342 
343  *rec_offs_base(offsets)
344  = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
345 }
346 
347 /******************************************************/
361 static
362 void
363 rec_init_offsets(
364 /*=============*/
365  const rec_t* rec,
366  const dict_index_t* index,
367  ulint* offsets)
369 {
370  ulint i = 0;
371  ulint offs;
372 
373  rec_offs_make_valid(rec, index, offsets);
374 
375  if (dict_table_is_comp(index->table)) {
376  const byte* nulls;
377  const byte* lens;
378  dict_field_t* field;
379  ulint null_mask;
380  ulint status = rec_get_status(rec);
381  ulint n_node_ptr_field = ULINT_UNDEFINED;
382 
383  switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
384  case REC_STATUS_INFIMUM:
385  case REC_STATUS_SUPREMUM:
386  /* the field is 8 bytes long */
387  rec_offs_base(offsets)[0]
388  = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
389  rec_offs_base(offsets)[1] = 8;
390  return;
391  case REC_STATUS_NODE_PTR:
392  n_node_ptr_field
394  break;
395  case REC_STATUS_ORDINARY:
397  REC_N_NEW_EXTRA_BYTES,
398  index, offsets);
399  return;
400  }
401 
402  nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
403  lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
404  offs = 0;
405  null_mask = 1;
406 
407  /* read the lengths of fields 0..n */
408  do {
409  ulint len;
410  if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
411  len = offs += 4;
412  goto resolved;
413  }
414 
415  field = dict_index_get_nth_field(index, i);
416  if (!(dict_field_get_col(field)->prtype
417  & DATA_NOT_NULL)) {
418  /* nullable field => read the null flag */
419 
420  if (UNIV_UNLIKELY(!(byte) null_mask)) {
421  nulls--;
422  null_mask = 1;
423  }
424 
425  if (*nulls & null_mask) {
426  null_mask <<= 1;
427  /* No length is stored for NULL fields.
428  We do not advance offs, and we set
429  the length to zero and enable the
430  SQL NULL flag in offsets[]. */
431  len = offs | REC_OFFS_SQL_NULL;
432  goto resolved;
433  }
434  null_mask <<= 1;
435  }
436 
437  if (UNIV_UNLIKELY(!field->fixed_len)) {
438  /* Variable-length field: read the length */
439  const dict_col_t* col
440  = dict_field_get_col(field);
441  len = *lens--;
442  /* If the maximum length of the field
443  is up to 255 bytes, the actual length
444  is always stored in one byte. If the
445  maximum length is more than 255 bytes,
446  the actual length is stored in one
447  byte for 0..127. The length will be
448  encoded in two bytes when it is 128 or
449  more, or when the field is stored
450  externally. */
451  if (UNIV_UNLIKELY(col->len > 255)
452  || UNIV_UNLIKELY(col->mtype
453  == DATA_BLOB)) {
454  if (len & 0x80) {
455  /* 1exxxxxxx xxxxxxxx */
456 
457  len <<= 8;
458  len |= *lens--;
459 
460  /* B-tree node pointers
461  must not contain externally
462  stored columns. Thus
463  the "e" flag must be 0. */
464  ut_a(!(len & 0x4000));
465  offs += len & 0x3fff;
466  len = offs;
467 
468  goto resolved;
469  }
470  }
471 
472  len = offs += len;
473  } else {
474  len = offs += field->fixed_len;
475  }
476 resolved:
477  rec_offs_base(offsets)[i + 1] = len;
478  } while (++i < rec_offs_n_fields(offsets));
479 
480  *rec_offs_base(offsets)
481  = (rec - (lens + 1)) | REC_OFFS_COMPACT;
482  } else {
483  /* Old-style record: determine extra size and end offsets */
484  offs = REC_N_OLD_EXTRA_BYTES;
485  if (rec_get_1byte_offs_flag(rec)) {
486  offs += rec_offs_n_fields(offsets);
487  *rec_offs_base(offsets) = offs;
488  /* Determine offsets to fields */
489  do {
490  offs = rec_1_get_field_end_info(rec, i);
491  if (offs & REC_1BYTE_SQL_NULL_MASK) {
492  offs &= ~REC_1BYTE_SQL_NULL_MASK;
493  offs |= REC_OFFS_SQL_NULL;
494  }
495  rec_offs_base(offsets)[1 + i] = offs;
496  } while (++i < rec_offs_n_fields(offsets));
497  } else {
498  offs += 2 * rec_offs_n_fields(offsets);
499  *rec_offs_base(offsets) = offs;
500  /* Determine offsets to fields */
501  do {
502  offs = rec_2_get_field_end_info(rec, i);
503  if (offs & REC_2BYTE_SQL_NULL_MASK) {
504  offs &= ~REC_2BYTE_SQL_NULL_MASK;
505  offs |= REC_OFFS_SQL_NULL;
506  }
507  if (offs & REC_2BYTE_EXTERN_MASK) {
508  offs &= ~REC_2BYTE_EXTERN_MASK;
509  offs |= REC_OFFS_EXTERNAL;
510  *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
511  }
512  rec_offs_base(offsets)[1 + i] = offs;
513  } while (++i < rec_offs_n_fields(offsets));
514  }
515  }
516 }
517 
518 /******************************************************/
522 UNIV_INTERN
523 ulint*
525 /*=================*/
526  const rec_t* rec,
527  const dict_index_t* index,
528  ulint* offsets,
532  ulint n_fields,
535  mem_heap_t** heap,
536  const char* file,
537  ulint line)
538 {
539  ulint n;
540  ulint size;
541 
542  ut_ad(rec);
543  ut_ad(index);
544  ut_ad(heap);
545 
546  if (dict_table_is_comp(index->table)) {
547  switch (UNIV_EXPECT(rec_get_status(rec),
548  REC_STATUS_ORDINARY)) {
549  case REC_STATUS_ORDINARY:
550  n = dict_index_get_n_fields(index);
551  break;
552  case REC_STATUS_NODE_PTR:
553  n = dict_index_get_n_unique_in_tree(index) + 1;
554  break;
555  case REC_STATUS_INFIMUM:
556  case REC_STATUS_SUPREMUM:
557  /* infimum or supremum record */
558  n = 1;
559  break;
560  default:
561  ut_error;
562  return(NULL);
563  }
564  } else {
565  n = rec_get_n_fields_old(rec);
566  }
567 
568  if (UNIV_UNLIKELY(n_fields < n)) {
569  n = n_fields;
570  }
571 
572  size = n + (1 + REC_OFFS_HEADER_SIZE);
573 
574  if (UNIV_UNLIKELY(!offsets)
575  || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
576  if (UNIV_UNLIKELY(!*heap)) {
577  *heap = mem_heap_create_func(size * sizeof(ulint),
578  MEM_HEAP_DYNAMIC,
579  file, line);
580  }
581  offsets = static_cast<unsigned long *>(mem_heap_alloc(*heap, size * sizeof(ulint)));
582  rec_offs_set_n_alloc(offsets, size);
583  }
584 
585  rec_offs_set_n_fields(offsets, n);
586  rec_init_offsets(rec, index, offsets);
587  return(offsets);
588 }
589 
590 /******************************************************/
593 UNIV_INTERN
594 void
596 /*====================*/
597  const byte* extra,
601  const dict_index_t* index,
602  ulint node_ptr,
604  ulint* offsets)
606 {
607  ulint n;
608  ulint i;
609  ulint offs;
610  ulint any_ext;
611  const byte* nulls;
612  const byte* lens;
613  dict_field_t* field;
614  ulint null_mask;
615  ulint n_node_ptr_field;
616 
617  ut_ad(extra);
618  ut_ad(index);
619  ut_ad(offsets);
620  ut_ad(dict_table_is_comp(index->table));
621 
622  if (UNIV_UNLIKELY(node_ptr)) {
623  n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
624  n = n_node_ptr_field + 1;
625  } else {
626  n_node_ptr_field = ULINT_UNDEFINED;
627  n = dict_index_get_n_fields(index);
628  }
629 
630  ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
631  rec_offs_set_n_fields(offsets, n);
632 
633  nulls = extra;
634  lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
635  i = offs = 0;
636  null_mask = 1;
637  any_ext = 0;
638 
639  /* read the lengths of fields 0..n */
640  do {
641  ulint len;
642  if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
643  len = offs += 4;
644  goto resolved;
645  }
646 
647  field = dict_index_get_nth_field(index, i);
648  if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
649  /* nullable field => read the null flag */
650 
651  if (UNIV_UNLIKELY(!(byte) null_mask)) {
652  nulls++;
653  null_mask = 1;
654  }
655 
656  if (*nulls & null_mask) {
657  null_mask <<= 1;
658  /* No length is stored for NULL fields.
659  We do not advance offs, and we set
660  the length to zero and enable the
661  SQL NULL flag in offsets[]. */
662  len = offs | REC_OFFS_SQL_NULL;
663  goto resolved;
664  }
665  null_mask <<= 1;
666  }
667 
668  if (UNIV_UNLIKELY(!field->fixed_len)) {
669  /* Variable-length field: read the length */
670  const dict_col_t* col
671  = dict_field_get_col(field);
672  len = *lens++;
673  /* If the maximum length of the field is up
674  to 255 bytes, the actual length is always
675  stored in one byte. If the maximum length is
676  more than 255 bytes, the actual length is
677  stored in one byte for 0..127. The length
678  will be encoded in two bytes when it is 128 or
679  more, or when the field is stored externally. */
680  if (UNIV_UNLIKELY(col->len > 255)
681  || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
682  if (len & 0x80) {
683  /* 1exxxxxxx xxxxxxxx */
684  len <<= 8;
685  len |= *lens++;
686 
687  offs += len & 0x3fff;
688  if (UNIV_UNLIKELY(len & 0x4000)) {
689  any_ext = REC_OFFS_EXTERNAL;
690  len = offs | REC_OFFS_EXTERNAL;
691  } else {
692  len = offs;
693  }
694 
695  goto resolved;
696  }
697  }
698 
699  len = offs += len;
700  } else {
701  len = offs += field->fixed_len;
702  }
703 resolved:
704  rec_offs_base(offsets)[i + 1] = len;
705  } while (++i < rec_offs_n_fields(offsets));
706 
707  ut_ad(lens >= extra);
708  *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
709  | REC_OFFS_COMPACT | any_ext;
710 }
711 
712 /************************************************************/
716 UNIV_INTERN
717 ulint
719 /*=======================*/
720  const rec_t* rec,
721  ulint n,
722  ulint* len)
724 {
725  ulint os;
726  ulint next_os;
727 
728  ut_ad(len);
729  ut_a(rec);
730  ut_a(n < rec_get_n_fields_old(rec));
731 
732  if (rec_get_1byte_offs_flag(rec)) {
733  os = rec_1_get_field_start_offs(rec, n);
734 
735  next_os = rec_1_get_field_end_info(rec, n);
736 
737  if (next_os & REC_1BYTE_SQL_NULL_MASK) {
738  *len = UNIV_SQL_NULL;
739 
740  return(os);
741  }
742 
743  next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
744  } else {
745  os = rec_2_get_field_start_offs(rec, n);
746 
747  next_os = rec_2_get_field_end_info(rec, n);
748 
749  if (next_os & REC_2BYTE_SQL_NULL_MASK) {
750  *len = UNIV_SQL_NULL;
751 
752  return(os);
753  }
754 
755  next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
756  | REC_2BYTE_EXTERN_MASK);
757  }
758 
759  *len = next_os - os;
760 
761  ut_ad(*len < UNIV_PAGE_SIZE);
762 
763  return(os);
764 }
765 
766 /**********************************************************/
769 UNIV_INTERN
770 ulint
772 /*===============================*/
773  const dict_index_t* index,
777  const dfield_t* fields,
778  ulint n_fields,
779  ulint* extra)
780 {
781  ulint extra_size;
782  ulint data_size;
783  ulint i;
784  ut_ad(index);
785  ut_ad(fields);
786  ut_ad(n_fields > 0);
787  ut_ad(n_fields <= dict_index_get_n_fields(index));
788 
789  extra_size = REC_N_NEW_EXTRA_BYTES
790  + UT_BITS_IN_BYTES(index->n_nullable);
791  data_size = 0;
792 
793  /* read the lengths of fields 0..n */
794  for (i = 0; i < n_fields; i++) {
795  const dict_field_t* field;
796  ulint len;
797  const dict_col_t* col;
798 
799  field = dict_index_get_nth_field(index, i);
800  len = dfield_get_len(&fields[i]);
801  col = dict_field_get_col(field);
802 
803  ut_ad(dict_col_type_assert_equal(col,
804  dfield_get_type(&fields[i])));
805 
806  if (dfield_is_null(&fields[i])) {
807  /* No length is stored for NULL fields. */
808  ut_ad(!(col->prtype & DATA_NOT_NULL));
809  continue;
810  }
811 
812  ut_ad(len <= col->len || col->mtype == DATA_BLOB);
813 
814  /* If the maximum length of a variable-length field
815  is up to 255 bytes, the actual length is always stored
816  in one byte. If the maximum length is more than 255
817  bytes, the actual length is stored in one byte for
818  0..127. The length will be encoded in two bytes when
819  it is 128 or more, or when the field is stored externally. */
820 
821  if (field->fixed_len) {
822  ut_ad(len == field->fixed_len);
823  /* dict_index_add_col() should guarantee this */
824  ut_ad(!field->prefix_len
825  || field->fixed_len == field->prefix_len);
826  } else if (dfield_is_ext(&fields[i])) {
827  ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
828  extra_size += 2;
829  } else if (len < 128
830  || (col->len < 256 && col->mtype != DATA_BLOB)) {
831  extra_size++;
832  } else {
833  /* For variable-length columns, we look up the
834  maximum length from the column itself. If this
835  is a prefix index column shorter than 256 bytes,
836  this will waste one byte. */
837  extra_size += 2;
838  }
839  data_size += len;
840  }
841 
842  if (UNIV_LIKELY_NULL(extra)) {
843  *extra = extra_size;
844  }
845 
846  return(extra_size + data_size);
847 }
848 
849 /**********************************************************/
852 UNIV_INTERN
853 ulint
855 /*========================*/
856  const dict_index_t* index,
860  ulint status,
861  const dfield_t* fields,
862  ulint n_fields,
863  ulint* extra)
864 {
865  ulint size;
866  ut_ad(index);
867  ut_ad(fields);
868  ut_ad(n_fields > 0);
869 
870  switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
871  case REC_STATUS_ORDINARY:
872  ut_ad(n_fields == dict_index_get_n_fields(index));
873  size = 0;
874  break;
875  case REC_STATUS_NODE_PTR:
876  n_fields--;
877  ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
878  ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
879  size = REC_NODE_PTR_SIZE; /* child page number */
880  break;
881  case REC_STATUS_INFIMUM:
882  case REC_STATUS_SUPREMUM:
883  /* infimum or supremum record, 8 data bytes */
884  if (UNIV_LIKELY_NULL(extra)) {
885  *extra = REC_N_NEW_EXTRA_BYTES;
886  }
887  return(REC_N_NEW_EXTRA_BYTES + 8);
888  default:
889  ut_error;
890  return(ULINT_UNDEFINED);
891  }
892 
893  return(size + rec_get_converted_size_comp_prefix(index, fields,
894  n_fields, extra));
895 }
896 
897 /***********************************************************/
899 UNIV_INTERN
900 void
901 rec_set_nth_field_null_bit(
902 /*=======================*/
903  rec_t* rec,
904  ulint i,
905  ibool val)
906 {
907  ulint info;
908 
909  if (rec_get_1byte_offs_flag(rec)) {
910 
911  info = rec_1_get_field_end_info(rec, i);
912 
913  if (val) {
914  info = info | REC_1BYTE_SQL_NULL_MASK;
915  } else {
916  info = info & ~REC_1BYTE_SQL_NULL_MASK;
917  }
918 
919  rec_1_set_field_end_info(rec, i, info);
920 
921  return;
922  }
923 
924  info = rec_2_get_field_end_info(rec, i);
925 
926  if (val) {
927  info = info | REC_2BYTE_SQL_NULL_MASK;
928  } else {
929  info = info & ~REC_2BYTE_SQL_NULL_MASK;
930  }
931 
932  rec_2_set_field_end_info(rec, i, info);
933 }
934 
935 /***********************************************************/
938 UNIV_INTERN
939 void
940 rec_set_nth_field_sql_null(
941 /*=======================*/
942  rec_t* rec,
943  ulint n)
944 {
945  ulint offset;
946 
947  offset = rec_get_field_start_offs(rec, n);
948 
949  data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
950 
951  rec_set_nth_field_null_bit(rec, n, TRUE);
952 }
953 
954 /*********************************************************/
958 static
959 rec_t*
960 rec_convert_dtuple_to_rec_old(
961 /*==========================*/
962  byte* buf,
963  const dtuple_t* dtuple,
964  ulint n_ext)
965 {
966  const dfield_t* field;
967  ulint n_fields;
968  ulint data_size;
969  rec_t* rec;
970  ulint end_offset;
971  ulint ored_offset;
972  ulint len;
973  ulint i;
974 
975  ut_ad(buf && dtuple);
976  ut_ad(dtuple_validate(dtuple));
977  ut_ad(dtuple_check_typed(dtuple));
978 
979  n_fields = dtuple_get_n_fields(dtuple);
980  data_size = dtuple_get_data_size(dtuple, 0);
981 
982  ut_ad(n_fields > 0);
983 
984  /* Calculate the offset of the origin in the physical record */
985 
986  rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
987 #ifdef UNIV_DEBUG
988  /* Suppress Valgrind warnings of ut_ad()
989  in mach_write_to_1(), mach_write_to_2() et al. */
990  memset(buf, 0xff, rec - buf + data_size);
991 #endif /* UNIV_DEBUG */
992  /* Store the number of fields */
993  rec_set_n_fields_old(rec, n_fields);
994 
995  /* Set the info bits of the record */
997  & REC_INFO_BITS_MASK);
998 
999  /* Store the data and the offsets */
1000 
1001  end_offset = 0;
1002 
1003  if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1004 
1005  rec_set_1byte_offs_flag(rec, TRUE);
1006 
1007  for (i = 0; i < n_fields; i++) {
1008 
1009  field = dtuple_get_nth_field(dtuple, i);
1010 
1011  if (dfield_is_null(field)) {
1013  dfield_get_type(field), 0);
1014  data_write_sql_null(rec + end_offset, len);
1015 
1016  end_offset += len;
1017  ored_offset = end_offset
1018  | REC_1BYTE_SQL_NULL_MASK;
1019  } else {
1020  /* If the data is not SQL null, store it */
1021  len = dfield_get_len(field);
1022 
1023  memcpy(rec + end_offset,
1024  dfield_get_data(field), len);
1025 
1026  end_offset += len;
1027  ored_offset = end_offset;
1028  }
1029 
1030  rec_1_set_field_end_info(rec, i, ored_offset);
1031  }
1032  } else {
1033  rec_set_1byte_offs_flag(rec, FALSE);
1034 
1035  for (i = 0; i < n_fields; i++) {
1036 
1037  field = dtuple_get_nth_field(dtuple, i);
1038 
1039  if (dfield_is_null(field)) {
1041  dfield_get_type(field), 0);
1042  data_write_sql_null(rec + end_offset, len);
1043 
1044  end_offset += len;
1045  ored_offset = end_offset
1046  | REC_2BYTE_SQL_NULL_MASK;
1047  } else {
1048  /* If the data is not SQL null, store it */
1049  len = dfield_get_len(field);
1050 
1051  memcpy(rec + end_offset,
1052  dfield_get_data(field), len);
1053 
1054  end_offset += len;
1055  ored_offset = end_offset;
1056 
1057  if (dfield_is_ext(field)) {
1058  ored_offset |= REC_2BYTE_EXTERN_MASK;
1059  }
1060  }
1061 
1062  rec_2_set_field_end_info(rec, i, ored_offset);
1063  }
1064  }
1065 
1066  return(rec);
1067 }
1068 
1069 /*********************************************************/
1071 UNIV_INTERN
1072 void
1074 /*===========================*/
1075  rec_t* rec,
1076  ulint extra,
1080  const dict_index_t* index,
1081  ulint status,
1082  const dfield_t* fields,
1083  ulint n_fields)
1084 {
1085  const dfield_t* field;
1086  const dtype_t* type;
1087  byte* end;
1088  byte* nulls;
1089  byte* lens;
1090  ulint len;
1091  ulint i;
1092  ulint n_node_ptr_field;
1093  ulint fixed_len;
1094  ulint null_mask = 1;
1095  ut_ad(extra == 0 || dict_table_is_comp(index->table));
1096  ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
1097  ut_ad(n_fields > 0);
1098 
1099  switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1100  case REC_STATUS_ORDINARY:
1101  ut_ad(n_fields <= dict_index_get_n_fields(index));
1102  n_node_ptr_field = ULINT_UNDEFINED;
1103  break;
1104  case REC_STATUS_NODE_PTR:
1105  ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1106  n_node_ptr_field = n_fields - 1;
1107  break;
1108  case REC_STATUS_INFIMUM:
1109  case REC_STATUS_SUPREMUM:
1110  ut_ad(n_fields == 1);
1111  n_node_ptr_field = ULINT_UNDEFINED;
1112  break;
1113  default:
1114  ut_error;
1115  return;
1116  }
1117 
1118  end = rec;
1119  nulls = rec - (extra + 1);
1120  lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1121  /* clear the SQL-null flags */
1122  memset(lens + 1, 0, nulls - lens);
1123 
1124  /* Store the data and the offsets */
1125 
1126  for (i = 0, field = fields; i < n_fields; i++, field++) {
1127  const dict_field_t* ifield;
1128 
1129  type = dfield_get_type(field);
1130  len = dfield_get_len(field);
1131 
1132  if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1133  ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1134  ut_ad(len == 4);
1135  memcpy(end, dfield_get_data(field), len);
1136  end += 4;
1137  break;
1138  }
1139 
1140  if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1141  /* nullable field */
1142  ut_ad(index->n_nullable > 0);
1143 
1144  if (UNIV_UNLIKELY(!(byte) null_mask)) {
1145  nulls--;
1146  null_mask = 1;
1147  }
1148 
1149  ut_ad(*nulls < null_mask);
1150 
1151  /* set the null flag if necessary */
1152  if (dfield_is_null(field)) {
1153  *nulls |= null_mask;
1154  null_mask <<= 1;
1155  continue;
1156  }
1157 
1158  null_mask <<= 1;
1159  }
1160  /* only nullable fields can be null */
1161  ut_ad(!dfield_is_null(field));
1162 
1163  ifield = dict_index_get_nth_field(index, i);
1164  fixed_len = ifield->fixed_len;
1165  /* If the maximum length of a variable-length field
1166  is up to 255 bytes, the actual length is always stored
1167  in one byte. If the maximum length is more than 255
1168  bytes, the actual length is stored in one byte for
1169  0..127. The length will be encoded in two bytes when
1170  it is 128 or more, or when the field is stored externally. */
1171  if (fixed_len) {
1172  ut_ad(len == fixed_len);
1173  ut_ad(!dfield_is_ext(field));
1174  } else if (dfield_is_ext(field)) {
1175  ut_ad(ifield->col->len >= 256
1176  || ifield->col->mtype == DATA_BLOB);
1177  ut_ad(len <= REC_MAX_INDEX_COL_LEN
1179  *lens-- = (byte) (len >> 8) | 0xc0;
1180  *lens-- = (byte) len;
1181  } else {
1182  ut_ad(len <= dtype_get_len(type)
1183  || dtype_get_mtype(type) == DATA_BLOB);
1184  if (len < 128
1185  || (dtype_get_len(type) < 256
1186  && dtype_get_mtype(type) != DATA_BLOB)) {
1187 
1188  *lens-- = (byte) len;
1189  } else {
1190  ut_ad(len < 16384);
1191  *lens-- = (byte) (len >> 8) | 0x80;
1192  *lens-- = (byte) len;
1193  }
1194  }
1195 
1196  memcpy(end, dfield_get_data(field), len);
1197  end += len;
1198  }
1199 }
1200 
1201 /*********************************************************/
1205 static
1206 rec_t*
1207 rec_convert_dtuple_to_rec_new(
1208 /*==========================*/
1209  byte* buf,
1211  const dict_index_t* index,
1212  const dtuple_t* dtuple)
1213 {
1214  ulint extra_size;
1215  ulint status;
1216  rec_t* rec;
1217 
1218  status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1219  rec_get_converted_size_comp(index, status,
1220  dtuple->fields, dtuple->n_fields,
1221  &extra_size);
1222  rec = buf + extra_size;
1223 
1225  rec, REC_N_NEW_EXTRA_BYTES, index, status,
1226  dtuple->fields, dtuple->n_fields);
1227 
1228  /* Set the info bits of the record */
1230 
1231  return(rec);
1232 }
1233 
1234 /*********************************************************/
1238 UNIV_INTERN
1239 rec_t*
1241 /*======================*/
1242  byte* buf,
1244  const dict_index_t* index,
1245  const dtuple_t* dtuple,
1246  ulint n_ext)
1248 {
1249  rec_t* rec;
1250 
1251  ut_ad(buf && index && dtuple);
1252  ut_ad(dtuple_validate(dtuple));
1253  ut_ad(dtuple_check_typed(dtuple));
1254 
1255  if (dict_table_is_comp(index->table)) {
1256  rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1257  } else {
1258  rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1259  }
1260 
1261 #ifdef UNIV_DEBUG
1262  {
1263  mem_heap_t* heap = NULL;
1264  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1265  const ulint* offsets;
1266  ulint i;
1267  rec_offs_init(offsets_);
1268 
1269  offsets = rec_get_offsets(rec, index,
1270  offsets_, ULINT_UNDEFINED, &heap);
1271  ut_ad(rec_validate(rec, offsets));
1272  ut_ad(dtuple_get_n_fields(dtuple)
1273  == rec_offs_n_fields(offsets));
1274 
1275  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1276  ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
1277  == !rec_offs_nth_extern(offsets, i));
1278  }
1279 
1280  if (UNIV_LIKELY_NULL(heap)) {
1281  mem_heap_free(heap);
1282  }
1283  }
1284 #endif /* UNIV_DEBUG */
1285  return(rec);
1286 }
1287 
1288 /**************************************************************/
1291 UNIV_INTERN
1292 void
1294 /*======================*/
1295  dtuple_t* tuple,
1296  const rec_t* rec,
1297  const dict_index_t* index,
1298  ulint n_fields,
1300  mem_heap_t* heap)
1301 {
1302  ulint i;
1303  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1304  ulint* offsets = offsets_;
1305  rec_offs_init(offsets_);
1306 
1307  offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1308 
1309  ut_ad(rec_validate(rec, offsets));
1310  ut_ad(dtuple_check_typed(tuple));
1311 
1313  rec, dict_table_is_comp(index->table)));
1314 
1315  for (i = 0; i < n_fields; i++) {
1316  dfield_t* field;
1317  const byte* data;
1318  ulint len;
1319 
1320  field = dtuple_get_nth_field(tuple, i);
1321  data = rec_get_nth_field(rec, offsets, i, &len);
1322 
1323  if (len != UNIV_SQL_NULL) {
1324  dfield_set_data(field,
1325  mem_heap_dup(heap, data, len), len);
1326  ut_ad(!rec_offs_nth_extern(offsets, i));
1327  } else {
1328  dfield_set_null(field);
1329  }
1330  }
1331 }
1332 
1333 /**************************************************************/
1337 static
1338 rec_t*
1339 rec_copy_prefix_to_buf_old(
1340 /*=======================*/
1341  const rec_t* rec,
1342  ulint n_fields,
1343  ulint area_end,
1344  byte** buf,
1346  ulint* buf_size)
1347 {
1348  rec_t* copy_rec;
1349  ulint area_start;
1350  ulint prefix_len;
1351 
1352  if (rec_get_1byte_offs_flag(rec)) {
1353  area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1354  } else {
1355  area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1356  }
1357 
1358  prefix_len = area_start + area_end;
1359 
1360  if ((*buf == NULL) || (*buf_size < prefix_len)) {
1361  if (*buf != NULL) {
1362  mem_free(*buf);
1363  }
1364 
1365  *buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
1366  }
1367 
1368  ut_memcpy(*buf, rec - area_start, prefix_len);
1369 
1370  copy_rec = *buf + area_start;
1371 
1372  rec_set_n_fields_old(copy_rec, n_fields);
1373 
1374  return(copy_rec);
1375 }
1376 
1377 /**************************************************************/
1381 UNIV_INTERN
1382 rec_t*
1384 /*===================*/
1385  const rec_t* rec,
1386  const dict_index_t* index,
1387  ulint n_fields,
1389  byte** buf,
1392  ulint* buf_size)
1393 {
1394  const byte* nulls;
1395  const byte* lens;
1396  ulint i;
1397  ulint prefix_len;
1398  ulint null_mask;
1399  ulint status;
1400 
1401  UNIV_PREFETCH_RW(*buf);
1402 
1403  if (!dict_table_is_comp(index->table)) {
1404  ut_ad(rec_validate_old(rec));
1405  return(rec_copy_prefix_to_buf_old(
1406  rec, n_fields,
1407  rec_get_field_start_offs(rec, n_fields),
1408  buf, buf_size));
1409  }
1410 
1411  status = rec_get_status(rec);
1412 
1413  switch (status) {
1414  case REC_STATUS_ORDINARY:
1415  ut_ad(n_fields <= dict_index_get_n_fields(index));
1416  break;
1417  case REC_STATUS_NODE_PTR:
1418  /* it doesn't make sense to copy the child page number field */
1419  ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1420  break;
1421  case REC_STATUS_INFIMUM:
1422  case REC_STATUS_SUPREMUM:
1423  /* infimum or supremum record: no sense to copy anything */
1424  default:
1425  ut_error;
1426  return(NULL);
1427  }
1428 
1429  nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1430  lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1431  UNIV_PREFETCH_R(lens);
1432  prefix_len = 0;
1433  null_mask = 1;
1434 
1435  /* read the lengths of fields 0..n */
1436  for (i = 0; i < n_fields; i++) {
1437  const dict_field_t* field;
1438  const dict_col_t* col;
1439 
1440  field = dict_index_get_nth_field(index, i);
1441  col = dict_field_get_col(field);
1442 
1443  if (!(col->prtype & DATA_NOT_NULL)) {
1444  /* nullable field => read the null flag */
1445  if (UNIV_UNLIKELY(!(byte) null_mask)) {
1446  nulls--;
1447  null_mask = 1;
1448  }
1449 
1450  if (*nulls & null_mask) {
1451  null_mask <<= 1;
1452  continue;
1453  }
1454 
1455  null_mask <<= 1;
1456  }
1457 
1458  if (field->fixed_len) {
1459  prefix_len += field->fixed_len;
1460  } else {
1461  ulint len = *lens--;
1462  /* If the maximum length of the column is up
1463  to 255 bytes, the actual length is always
1464  stored in one byte. If the maximum length is
1465  more than 255 bytes, the actual length is
1466  stored in one byte for 0..127. The length
1467  will be encoded in two bytes when it is 128 or
1468  more, or when the column is stored externally. */
1469  if (col->len > 255 || col->mtype == DATA_BLOB) {
1470  if (len & 0x80) {
1471  /* 1exxxxxx */
1472  len &= 0x3f;
1473  len <<= 8;
1474  len |= *lens--;
1475  UNIV_PREFETCH_R(lens);
1476  }
1477  }
1478  prefix_len += len;
1479  }
1480  }
1481 
1482  UNIV_PREFETCH_R(rec + prefix_len);
1483 
1484  prefix_len += rec - (lens + 1);
1485 
1486  if ((*buf == NULL) || (*buf_size < prefix_len)) {
1487  if (*buf != NULL) {
1488  mem_free(*buf);
1489  }
1490 
1491  *buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
1492  }
1493 
1494  memcpy(*buf, lens + 1, prefix_len);
1495 
1496  return(*buf + (rec - (lens + 1)));
1497 }
1498 
1499 /***************************************************************/
1502 static
1503 ibool
1504 rec_validate_old(
1505 /*=============*/
1506  const rec_t* rec)
1507 {
1508  const byte* data;
1509  ulint len;
1510  ulint n_fields;
1511  ulint len_sum = 0;
1512  ulint sum = 0;
1513  ulint i;
1514 
1515  ut_a(rec);
1516  n_fields = rec_get_n_fields_old(rec);
1517 
1518  if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1519  fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1520  (ulong) n_fields);
1521  return(FALSE);
1522  }
1523 
1524  for (i = 0; i < n_fields; i++) {
1525  data = rec_get_nth_field_old(rec, i, &len);
1526 
1527  if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1528  fprintf(stderr,
1529  "InnoDB: Error: record field %lu len %lu\n",
1530  (ulong) i,
1531  (ulong) len);
1532  return(FALSE);
1533  }
1534 
1535  if (len != UNIV_SQL_NULL) {
1536  len_sum += len;
1537  sum += *(data + len -1); /* dereference the
1538  end of the field to
1539  cause a memory trap
1540  if possible */
1541  } else {
1542  len_sum += rec_get_nth_field_size(rec, i);
1543  }
1544  }
1545 
1546  if (len_sum != rec_get_data_size_old(rec)) {
1547  fprintf(stderr,
1548  "InnoDB: Error: record len should be %lu, len %lu\n",
1549  (ulong) len_sum,
1550  rec_get_data_size_old(rec));
1551  return(FALSE);
1552  }
1553 
1554  rec_dummy = sum; /* This is here only to fool the compiler */
1555 
1556  return(TRUE);
1557 }
1558 
1559 /***************************************************************/
1562 UNIV_INTERN
1563 ibool
1565 /*=========*/
1566  const rec_t* rec,
1567  const ulint* offsets)
1568 {
1569  const byte* data;
1570  ulint len;
1571  ulint n_fields;
1572  ulint len_sum = 0;
1573  ulint sum = 0;
1574  ulint i;
1575 
1576  ut_a(rec);
1577  n_fields = rec_offs_n_fields(offsets);
1578 
1579  if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1580  fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1581  (ulong) n_fields);
1582  return(FALSE);
1583  }
1584 
1585  ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1586 
1587  for (i = 0; i < n_fields; i++) {
1588  data = rec_get_nth_field(rec, offsets, i, &len);
1589 
1590  if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1591  fprintf(stderr,
1592  "InnoDB: Error: record field %lu len %lu\n",
1593  (ulong) i,
1594  (ulong) len);
1595  return(FALSE);
1596  }
1597 
1598  if (len != UNIV_SQL_NULL) {
1599  len_sum += len;
1600  sum += *(data + len -1); /* dereference the
1601  end of the field to
1602  cause a memory trap
1603  if possible */
1604  } else if (!rec_offs_comp(offsets)) {
1605  len_sum += rec_get_nth_field_size(rec, i);
1606  }
1607  }
1608 
1609  if (len_sum != rec_offs_data_size(offsets)) {
1610  fprintf(stderr,
1611  "InnoDB: Error: record len should be %lu, len %lu\n",
1612  (ulong) len_sum,
1613  (ulong) rec_offs_data_size(offsets));
1614  return(FALSE);
1615  }
1616 
1617  rec_dummy = sum; /* This is here only to fool the compiler */
1618 
1619  if (!rec_offs_comp(offsets)) {
1620  ut_a(rec_validate_old(rec));
1621  }
1622 
1623  return(TRUE);
1624 }
1625 
1626 /***************************************************************/
1628 UNIV_INTERN
1629 void
1631 /*==========*/
1632  FILE* file,
1633  const rec_t* rec)
1634 {
1635  const byte* data;
1636  ulint len;
1637  ulint n;
1638  ulint i;
1639 
1640  ut_ad(rec);
1641 
1642  n = rec_get_n_fields_old(rec);
1643 
1644  fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1645  " %u-byte offsets; info bits %lu\n",
1646  (ulong) n,
1647  rec_get_1byte_offs_flag(rec) ? 1 : 2,
1648  (ulong) rec_get_info_bits(rec, FALSE));
1649 
1650  for (i = 0; i < n; i++) {
1651 
1652  data = rec_get_nth_field_old(rec, i, &len);
1653 
1654  fprintf(file, " %lu:", (ulong) i);
1655 
1656  if (len != UNIV_SQL_NULL) {
1657  if (len <= 30) {
1658 
1659  ut_print_buf(file, data, len);
1660  } else {
1661  ut_print_buf(file, data, 30);
1662 
1663  fprintf(file, " (total %lu bytes)",
1664  (ulong) len);
1665  }
1666  } else {
1667  fprintf(file, " SQL NULL, size %lu ",
1668  rec_get_nth_field_size(rec, i));
1669  }
1670 
1671  putc(';', file);
1672  putc('\n', file);
1673  }
1674 
1675  rec_validate_old(rec);
1676 }
1677 
1678 #ifndef UNIV_HOTBACKUP
1679 /***************************************************************/
1682 UNIV_INTERN
1683 void
1685 /*===========*/
1686  FILE* file,
1687  const rec_t* rec,
1688  const ulint* offsets)
1689 {
1690  ulint i;
1691 
1692  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1693  const byte* data;
1694  ulint len;
1695 
1696  data = rec_get_nth_field(rec, offsets, i, &len);
1697 
1698  fprintf(file, " %lu:", (ulong) i);
1699 
1700  if (len != UNIV_SQL_NULL) {
1701  if (len <= 30) {
1702 
1703  ut_print_buf(file, data, len);
1704  } else {
1705  ut_print_buf(file, data, 30);
1706 
1707  fprintf(file, " (total %lu bytes)",
1708  (ulong) len);
1709  }
1710  } else {
1711  fputs(" SQL NULL", file);
1712  }
1713  putc(';', file);
1714  putc('\n', file);
1715  }
1716 }
1717 
1718 /***************************************************************/
1720 UNIV_INTERN
1721 void
1723 /*==========*/
1724  FILE* file,
1725  const rec_t* rec,
1726  const ulint* offsets)
1727 {
1728  ut_ad(rec);
1729  ut_ad(offsets);
1730  ut_ad(rec_offs_validate(rec, NULL, offsets));
1731 
1732  if (!rec_offs_comp(offsets)) {
1733  rec_print_old(file, rec);
1734  return;
1735  }
1736 
1737  fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1738  " compact format; info bits %lu\n",
1739  (ulong) rec_offs_n_fields(offsets),
1740  (ulong) rec_get_info_bits(rec, TRUE));
1741 
1742  rec_print_comp(file, rec, offsets);
1743  rec_validate(rec, offsets);
1744 }
1745 
1746 /***************************************************************/
1748 UNIV_INTERN
1749 void
1751 /*======*/
1752  FILE* file,
1753  const rec_t* rec,
1754  const dict_index_t* index)
1755 {
1756  ut_ad(index);
1757 
1758  if (!dict_table_is_comp(index->table)) {
1759  rec_print_old(file, rec);
1760  return;
1761  } else {
1762  mem_heap_t* heap = NULL;
1763  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1764  rec_offs_init(offsets_);
1765 
1766  rec_print_new(file, rec,
1767  rec_get_offsets(rec, index, offsets_,
1768  ULINT_UNDEFINED, &heap));
1769  if (UNIV_LIKELY_NULL(heap)) {
1770  mem_heap_free(heap);
1771  }
1772  }
1773 }
1774 #endif /* !UNIV_HOTBACKUP */