~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/rem/rem0rec.c

  • Committer: Monty Taylor
  • Date: 2010-09-26 21:24:15 UTC
  • mto: (1796.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1797.
  • Revision ID: mordred@inaugust.com-20100926212415-5fn3p3q75pgiei7r
Moved protocol doc into the docs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
/********************************************************************//**
20
 
@file rem/rem0rec.c
21
 
Record manager
22
 
 
23
 
Created 5/30/1994 Heikki Tuuri
24
 
*************************************************************************/
25
 
 
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
 
/***************************************************************//**
148
 
Validates the consistency of an old-style physical record.
149
 
@return TRUE if ok */
150
 
static
151
 
ibool
152
 
rec_validate_old(
153
 
/*=============*/
154
 
        const rec_t*    rec);   /*!< in: physical record */
155
 
 
156
 
/******************************************************//**
157
 
Determine how many of the first n columns in a compact
158
 
physical record are stored externally.
159
 
@return number of externally stored columns */
160
 
UNIV_INTERN
161
 
ulint
162
 
rec_get_n_extern_new(
163
 
/*=================*/
164
 
        const rec_t*    rec,    /*!< in: compact physical record */
165
 
        dict_index_t*   index,  /*!< in: record descriptor */
166
 
        ulint           n)      /*!< in: number of columns to scan */
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
 
/******************************************************//**
239
 
Determine the offset to each field in a leaf-page record
240
 
in ROW_FORMAT=COMPACT.  This is a special case of
241
 
rec_init_offsets() and rec_get_offsets_func(). */
242
 
UNIV_INTERN
243
 
void
244
 
rec_init_offsets_comp_ordinary(
245
 
/*===========================*/
246
 
        const rec_t*            rec,    /*!< in: physical record in
247
 
                                        ROW_FORMAT=COMPACT */
248
 
        ulint                   extra,  /*!< in: number of bytes to reserve
249
 
                                        between the record header and
250
 
                                        the data payload
251
 
                                        (usually REC_N_NEW_EXTRA_BYTES) */
252
 
        const dict_index_t*     index,  /*!< in: record descriptor */
253
 
        ulint*                  offsets)/*!< in/out: array of offsets;
254
 
                                        in: n=rec_offs_n_fields(offsets) */
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)) {
322
 
                                                ut_ad(dict_index_is_clust
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
 
/******************************************************//**
348
 
The following function determines the offsets to each field in the
349
 
record.  The offsets are written to a previously allocated array of
350
 
ulint, where rec_offs_n_fields(offsets) has been initialized to the
351
 
number of fields in the record.  The rest of the array will be
352
 
initialized by this function.  rec_offs_base(offsets)[0] will be set
353
 
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
354
 
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
355
 
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
356
 
offsets past the end of fields 0..n_fields, or to the beginning of
357
 
fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
358
 
is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
359
 
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
360
 
field i is being stored externally. */
361
 
static
362
 
void
363
 
rec_init_offsets(
364
 
/*=============*/
365
 
        const rec_t*            rec,    /*!< in: physical record */
366
 
        const dict_index_t*     index,  /*!< in: record descriptor */
367
 
        ulint*                  offsets)/*!< in/out: array of offsets;
368
 
                                        in: n=rec_offs_n_fields(offsets) */
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
393
 
                                = dict_index_get_n_unique_in_tree(index);
394
 
                        break;
395
 
                case REC_STATUS_ORDINARY:
396
 
                        rec_init_offsets_comp_ordinary(rec,
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
 
/******************************************************//**
519
 
The following function determines the offsets to each field
520
 
in the record.  It can reuse a previously returned array.
521
 
@return the new offsets */
522
 
UNIV_INTERN
523
 
ulint*
524
 
rec_get_offsets_func(
525
 
/*=================*/
526
 
        const rec_t*            rec,    /*!< in: physical record */
527
 
        const dict_index_t*     index,  /*!< in: record descriptor */
528
 
        ulint*                  offsets,/*!< in/out: array consisting of
529
 
                                        offsets[0] allocated elements,
530
 
                                        or an array from rec_get_offsets(),
531
 
                                        or NULL */
532
 
        ulint                   n_fields,/*!< in: maximum number of
533
 
                                        initialized fields
534
 
                                         (ULINT_UNDEFINED if all fields) */
535
 
        mem_heap_t**            heap,   /*!< in/out: memory heap */
536
 
        const char*             file,   /*!< in: file name where called */
537
 
        ulint                   line)   /*!< in: line number where called */
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 = 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
 
/******************************************************//**
591
 
The following function determines the offsets to each field
592
 
in the record.  It can reuse a previously allocated array. */
593
 
UNIV_INTERN
594
 
void
595
 
rec_get_offsets_reverse(
596
 
/*====================*/
597
 
        const byte*             extra,  /*!< in: the extra bytes of a
598
 
                                        compact record in reverse order,
599
 
                                        excluding the fixed-size
600
 
                                        REC_N_NEW_EXTRA_BYTES */
601
 
        const dict_index_t*     index,  /*!< in: record descriptor */
602
 
        ulint                   node_ptr,/*!< in: nonzero=node pointer,
603
 
                                        0=leaf node */
604
 
        ulint*                  offsets)/*!< in/out: array consisting of
605
 
                                        offsets[0] allocated elements */
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
 
/************************************************************//**
713
 
The following function is used to get the offset to the nth
714
 
data field in an old-style record.
715
 
@return offset to the field */
716
 
UNIV_INTERN
717
 
ulint
718
 
rec_get_nth_field_offs_old(
719
 
/*=======================*/
720
 
        const rec_t*    rec,    /*!< in: record */
721
 
        ulint           n,      /*!< in: index of the field */
722
 
        ulint*          len)    /*!< out: length of the field;
723
 
                                UNIV_SQL_NULL if SQL null */
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
 
/**********************************************************//**
767
 
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
768
 
@return total size */
769
 
UNIV_INTERN
770
 
ulint
771
 
rec_get_converted_size_comp_prefix(
772
 
/*===============================*/
773
 
        const dict_index_t*     index,  /*!< in: record descriptor;
774
 
                                        dict_table_is_comp() is
775
 
                                        assumed to hold, even if
776
 
                                        it does not */
777
 
        const dfield_t*         fields, /*!< in: array of data fields */
778
 
        ulint                   n_fields,/*!< in: number of data fields */
779
 
        ulint*                  extra)  /*!< out: extra size */
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
 
/**********************************************************//**
850
 
Determines the size of a data tuple in ROW_FORMAT=COMPACT.
851
 
@return total size */
852
 
UNIV_INTERN
853
 
ulint
854
 
rec_get_converted_size_comp(
855
 
/*========================*/
856
 
        const dict_index_t*     index,  /*!< in: record descriptor;
857
 
                                        dict_table_is_comp() is
858
 
                                        assumed to hold, even if
859
 
                                        it does not */
860
 
        ulint                   status, /*!< in: status bits of the record */
861
 
        const dfield_t*         fields, /*!< in: array of data fields */
862
 
        ulint                   n_fields,/*!< in: number of data fields */
863
 
        ulint*                  extra)  /*!< out: extra size */
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
 
/***********************************************************//**
898
 
Sets the value of the ith field SQL null bit of an old-style record. */
899
 
UNIV_INTERN
900
 
void
901
 
rec_set_nth_field_null_bit(
902
 
/*=======================*/
903
 
        rec_t*  rec,    /*!< in: record */
904
 
        ulint   i,      /*!< in: ith field */
905
 
        ibool   val)    /*!< in: value to set */
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
 
/***********************************************************//**
936
 
Sets an old-style record field to SQL null.
937
 
The physical size of the field is not changed. */
938
 
UNIV_INTERN
939
 
void
940
 
rec_set_nth_field_sql_null(
941
 
/*=======================*/
942
 
        rec_t*  rec,    /*!< in: record */
943
 
        ulint   n)      /*!< in: index of the field */
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
 
/*********************************************************//**
955
 
Builds an old-style physical record out of a data tuple and
956
 
stores it beginning from the start of the given buffer.
957
 
@return pointer to the origin of physical record */
958
 
static
959
 
rec_t*
960
 
rec_convert_dtuple_to_rec_old(
961
 
/*==========================*/
962
 
        byte*           buf,    /*!< in: start address of the physical record */
963
 
        const dtuple_t* dtuple, /*!< in: data tuple */
964
 
        ulint           n_ext)  /*!< in: number of externally stored columns */
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 */
996
 
        rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
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)) {
1012
 
                                len = dtype_get_sql_null_size(
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)) {
1040
 
                                len = dtype_get_sql_null_size(
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
 
/*********************************************************//**
1070
 
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1071
 
UNIV_INTERN
1072
 
void
1073
 
rec_convert_dtuple_to_rec_comp(
1074
 
/*===========================*/
1075
 
        rec_t*                  rec,    /*!< in: origin of record */
1076
 
        ulint                   extra,  /*!< in: number of bytes to
1077
 
                                        reserve between the record
1078
 
                                        header and the data payload
1079
 
                                        (normally REC_N_NEW_EXTRA_BYTES) */
1080
 
        const dict_index_t*     index,  /*!< in: record descriptor */
1081
 
        ulint                   status, /*!< in: status bits of the record */
1082
 
        const dfield_t*         fields, /*!< in: array of data fields */
1083
 
        ulint                   n_fields)/*!< in: number of data fields */
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
1178
 
                              + BTR_EXTERN_FIELD_REF_SIZE);
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
 
/*********************************************************//**
1202
 
Builds a new-style physical record out of a data tuple and
1203
 
stores it beginning from the start of the given buffer.
1204
 
@return pointer to the origin of physical record */
1205
 
static
1206
 
rec_t*
1207
 
rec_convert_dtuple_to_rec_new(
1208
 
/*==========================*/
1209
 
        byte*                   buf,    /*!< in: start address of
1210
 
                                        the physical record */
1211
 
        const dict_index_t*     index,  /*!< in: record descriptor */
1212
 
        const dtuple_t*         dtuple) /*!< in: data tuple */
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
 
 
1224
 
        rec_convert_dtuple_to_rec_comp(
1225
 
                rec, REC_N_NEW_EXTRA_BYTES, index, status,
1226
 
                dtuple->fields, dtuple->n_fields);
1227
 
 
1228
 
        /* Set the info bits of the record */
1229
 
        rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1230
 
 
1231
 
        return(rec);
1232
 
}
1233
 
 
1234
 
/*********************************************************//**
1235
 
Builds a physical record out of a data tuple and
1236
 
stores it beginning from the start of the given buffer.
1237
 
@return pointer to the origin of physical record */
1238
 
UNIV_INTERN
1239
 
rec_t*
1240
 
rec_convert_dtuple_to_rec(
1241
 
/*======================*/
1242
 
        byte*                   buf,    /*!< in: start address of the
1243
 
                                        physical record */
1244
 
        const dict_index_t*     index,  /*!< in: record descriptor */
1245
 
        const dtuple_t*         dtuple, /*!< in: data tuple */
1246
 
        ulint                   n_ext)  /*!< in: number of
1247
 
                                        externally stored columns */
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
 
/**************************************************************//**
1289
 
Copies the first n fields of a physical record to a data tuple. The fields
1290
 
are copied to the memory heap. */
1291
 
UNIV_INTERN
1292
 
void
1293
 
rec_copy_prefix_to_dtuple(
1294
 
/*======================*/
1295
 
        dtuple_t*               tuple,          /*!< out: data tuple */
1296
 
        const rec_t*            rec,            /*!< in: physical record */
1297
 
        const dict_index_t*     index,          /*!< in: record descriptor */
1298
 
        ulint                   n_fields,       /*!< in: number of fields
1299
 
                                                to copy */
1300
 
        mem_heap_t*             heap)           /*!< in: memory 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
 
 
1312
 
        dtuple_set_info_bits(tuple, rec_get_info_bits(
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
 
/**************************************************************//**
1334
 
Copies the first n fields of an old-style physical record
1335
 
to a new physical record in a buffer.
1336
 
@return own: copied record */
1337
 
static
1338
 
rec_t*
1339
 
rec_copy_prefix_to_buf_old(
1340
 
/*=======================*/
1341
 
        const rec_t*    rec,            /*!< in: physical record */
1342
 
        ulint           n_fields,       /*!< in: number of fields to copy */
1343
 
        ulint           area_end,       /*!< in: end of the prefix data */
1344
 
        byte**          buf,            /*!< in/out: memory buffer for
1345
 
                                        the copied prefix, or NULL */
1346
 
        ulint*          buf_size)       /*!< in/out: buffer size */
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 = 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
 
/**************************************************************//**
1378
 
Copies the first n fields of a physical record to a new physical record in
1379
 
a buffer.
1380
 
@return own: copied record */
1381
 
UNIV_INTERN
1382
 
rec_t*
1383
 
rec_copy_prefix_to_buf(
1384
 
/*===================*/
1385
 
        const rec_t*            rec,            /*!< in: physical record */
1386
 
        const dict_index_t*     index,          /*!< in: record descriptor */
1387
 
        ulint                   n_fields,       /*!< in: number of fields
1388
 
                                                to copy */
1389
 
        byte**                  buf,            /*!< in/out: memory buffer
1390
 
                                                for the copied prefix,
1391
 
                                                or NULL */
1392
 
        ulint*                  buf_size)       /*!< in/out: buffer 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 = 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
 
/***************************************************************//**
1500
 
Validates the consistency of an old-style physical record.
1501
 
@return TRUE if ok */
1502
 
static
1503
 
ibool
1504
 
rec_validate_old(
1505
 
/*=============*/
1506
 
        const rec_t*    rec)    /*!< in: physical record */
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
 
/***************************************************************//**
1560
 
Validates the consistency of a physical record.
1561
 
@return TRUE if ok */
1562
 
UNIV_INTERN
1563
 
ibool
1564
 
rec_validate(
1565
 
/*=========*/
1566
 
        const rec_t*    rec,    /*!< in: physical record */
1567
 
        const ulint*    offsets)/*!< in: array returned by rec_get_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
 
/***************************************************************//**
1627
 
Prints an old-style physical record. */
1628
 
UNIV_INTERN
1629
 
void
1630
 
rec_print_old(
1631
 
/*==========*/
1632
 
        FILE*           file,   /*!< in: file where to print */
1633
 
        const rec_t*    rec)    /*!< in: physical record */
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
 
/***************************************************************//**
1680
 
Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
1681
 
record header. */
1682
 
UNIV_INTERN
1683
 
void
1684
 
rec_print_comp(
1685
 
/*===========*/
1686
 
        FILE*           file,   /*!< in: file where to print */
1687
 
        const rec_t*    rec,    /*!< in: physical record */
1688
 
        const ulint*    offsets)/*!< in: array returned by rec_get_offsets() */
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
 
/***************************************************************//**
1719
 
Prints a physical record. */
1720
 
UNIV_INTERN
1721
 
void
1722
 
rec_print_new(
1723
 
/*==========*/
1724
 
        FILE*           file,   /*!< in: file where to print */
1725
 
        const rec_t*    rec,    /*!< in: physical record */
1726
 
        const ulint*    offsets)/*!< in: array returned by rec_get_offsets() */
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
 
/***************************************************************//**
1747
 
Prints a physical record. */
1748
 
UNIV_INTERN
1749
 
void
1750
 
rec_print(
1751
 
/*======*/
1752
 
        FILE*           file,   /*!< in: file where to print */
1753
 
        const rec_t*    rec,    /*!< in: physical record */
1754
 
        dict_index_t*   index)  /*!< in: record descriptor */
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 */