~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************
 
2
Record manager
 
3
 
 
4
(c) 1994-2001 Innobase Oy
 
5
 
 
6
Created 5/30/1994 Heikki Tuuri
 
7
*************************************************************************/
 
8
 
 
9
#include "rem0rec.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "rem0rec.ic"
 
13
#endif
 
14
 
 
15
#include "mtr0mtr.h"
 
16
#include "mtr0log.h"
 
17
 
 
18
/*                      PHYSICAL RECORD (OLD STYLE)
 
19
                        ===========================
 
20
 
 
21
The physical record, which is the data type of all the records
 
22
found in index pages of the database, has the following format
 
23
(lower addresses and more significant bits inside a byte are below
 
24
represented on a higher text line):
 
25
 
 
26
| offset of the end of the last field of data, the most significant
 
27
  bit is set to 1 if and only if the field is SQL-null,
 
28
  if the offset is 2-byte, then the second most significant
 
29
  bit is set to 1 if the field is stored on another page:
 
30
  mostly this will occur in the case of big BLOB fields |
 
31
...
 
32
| offset of the end of the first field of data + the SQL-null bit |
 
33
| 4 bits used to delete mark a record, and mark a predefined
 
34
  minimum record in alphabetical order |
 
35
| 4 bits giving the number of records owned by this record
 
36
  (this term is explained in page0page.h) |
 
37
| 13 bits giving the order number of this record in the
 
38
  heap of the index page |
 
39
| 10 bits giving the number of fields in this record |
 
40
| 1 bit which is set to 1 if the offsets above are given in
 
41
  one byte format, 0 if in two byte format |
 
42
| two bytes giving an absolute pointer to the next record in the page |
 
43
ORIGIN of the record
 
44
| first field of data |
 
45
...
 
46
| last field of data |
 
47
 
 
48
The origin of the record is the start address of the first field
 
49
of data. The offsets are given relative to the origin.
 
50
The offsets of the data fields are stored in an inverted
 
51
order because then the offset of the first fields are near the
 
52
origin, giving maybe a better processor cache hit rate in searches.
 
53
 
 
54
The offsets of the data fields are given as one-byte
 
55
(if there are less than 127 bytes of data in the record)
 
56
or two-byte unsigned integers. The most significant bit
 
57
is not part of the offset, instead it indicates the SQL-null
 
58
if the bit is set to 1. */
 
59
 
 
60
/*                      PHYSICAL RECORD (NEW STYLE)
 
61
                        ===========================
 
62
 
 
63
The physical record, which is the data type of all the records
 
64
found in index pages of the database, has the following format
 
65
(lower addresses and more significant bits inside a byte are below
 
66
represented on a higher text line):
 
67
 
 
68
| length of the last non-null variable-length field of data:
 
69
  if the maximum length is 255, one byte; otherwise,
 
70
  0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
 
71
  length=128..16383, extern storage flag) |
 
72
...
 
73
| length of first variable-length field of data |
 
74
| SQL-null flags (1 bit per nullable field), padded to full bytes |
 
75
| 4 bits used to delete mark a record, and mark a predefined
 
76
  minimum record in alphabetical order |
 
77
| 4 bits giving the number of records owned by this record
 
78
  (this term is explained in page0page.h) |
 
79
| 13 bits giving the order number of this record in the
 
80
  heap of the index page |
 
81
| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
 
82
  010=infimum, 011=supremum, 1xx=reserved |
 
83
| two bytes giving a relative pointer to the next record in the page |
 
84
ORIGIN of the record
 
85
| first field of data |
 
86
...
 
87
| last field of data |
 
88
 
 
89
The origin of the record is the start address of the first field
 
90
of data. The offsets are given relative to the origin.
 
91
The offsets of the data fields are stored in an inverted
 
92
order because then the offset of the first fields are near the
 
93
origin, giving maybe a better processor cache hit rate in searches.
 
94
 
 
95
The offsets of the data fields are given as one-byte
 
96
(if there are less than 127 bytes of data in the record)
 
97
or two-byte unsigned integers. The most significant bit
 
98
is not part of the offset, instead it indicates the SQL-null
 
99
if the bit is set to 1. */
 
100
 
 
101
/* CANONICAL COORDINATES. A record can be seen as a single
 
102
string of 'characters' in the following way: catenate the bytes
 
103
in each field, in the order of fields. An SQL-null field
 
104
is taken to be an empty sequence of bytes. Then after
 
105
the position of each field insert in the string
 
106
the 'character' <FIELD-END>, except that after an SQL-null field
 
107
insert <NULL-FIELD-END>. Now the ordinal position of each
 
108
byte in this canonical string is its canonical coordinate.
 
109
So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
 
110
string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
 
111
We identify prefixes (= initial segments) of a record
 
112
with prefixes of the canonical string. The canonical
 
113
length of the prefix is the length of the corresponding
 
114
prefix of the canonical string. The canonical length of
 
115
a record is the length of its canonical string.
 
116
 
 
117
For example, the maximal common prefix of records
 
118
("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
 
119
is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
 
120
length is 5.
 
121
 
 
122
A complete-field prefix of a record is a prefix which ends at the
 
123
end of some field (containing also <FIELD-END>).
 
124
A record is a complete-field prefix of another record, if
 
125
the corresponding canonical strings have the same property. */
 
126
 
 
127
ulint   rec_dummy;      /* this is used to fool compiler in
 
128
                        rec_validate */
 
129
 
 
130
/*******************************************************************
 
131
Validates the consistency of an old-style physical record. */
 
132
static
 
133
ibool
 
134
rec_validate_old(
 
135
/*=============*/
 
136
                        /* out: TRUE if ok */
 
137
        rec_t*  rec);   /* in: physical record */
 
138
 
 
139
/**********************************************************
 
140
The following function determines the offsets to each field in the
 
141
record.  The offsets are written to a previously allocated array of
 
142
ulint, where rec_offs_n_fields(offsets) has been initialized to the
 
143
number of fields in the record.  The rest of the array will be
 
144
initialized by this function.  rec_offs_base(offsets)[0] will be set
 
145
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
 
146
new format), and rec_offs_base(offsets)[1..n_fields] will be set to
 
147
offsets past the end of fields 0..n_fields, or to the beginning of
 
148
fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
 
149
is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
 
150
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
 
151
field i is being stored externally. */
 
152
static
 
153
void
 
154
rec_init_offsets(
 
155
/*=============*/
 
156
        rec_t*          rec,    /* in: physical record */
 
157
        dict_index_t*   index,  /* in: record descriptor */
 
158
        ulint*          offsets)/* in/out: array of offsets;
 
159
                                in: n=rec_offs_n_fields(offsets) */
 
160
{
 
161
        ulint   i       = 0;
 
162
        ulint   offs;
 
163
 
 
164
        rec_offs_make_valid(rec, index, offsets);
 
165
 
 
166
        if (dict_table_is_comp(index->table)) {
 
167
                const byte*     nulls;
 
168
                const byte*     lens;
 
169
                dict_field_t*   field;
 
170
                ulint           null_mask;
 
171
                ulint           status = rec_get_status(rec);
 
172
                ulint           n_node_ptr_field = ULINT_UNDEFINED;
 
173
 
 
174
                switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
 
175
                case REC_STATUS_INFIMUM:
 
176
                case REC_STATUS_SUPREMUM:
 
177
                        /* the field is 8 bytes long */
 
178
                        rec_offs_base(offsets)[0]
 
179
                                = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
 
180
                        rec_offs_base(offsets)[1] = 8;
 
181
                        return;
 
182
                case REC_STATUS_NODE_PTR:
 
183
                        n_node_ptr_field
 
184
                                = dict_index_get_n_unique_in_tree(index);
 
185
                        break;
 
186
                case REC_STATUS_ORDINARY:
 
187
                        break;
 
188
                }
 
189
 
 
190
                nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
 
191
                lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
 
192
                offs = 0;
 
193
                null_mask = 1;
 
194
 
 
195
                /* read the lengths of fields 0..n */
 
196
                do {
 
197
                        ulint   len;
 
198
                        if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
 
199
                                len = offs += 4;
 
200
                                goto resolved;
 
201
                        }
 
202
 
 
203
                        field = dict_index_get_nth_field(index, i);
 
204
                        if (!(dict_field_get_col(field)->prtype
 
205
                              & DATA_NOT_NULL)) {
 
206
                                /* nullable field => read the null flag */
 
207
 
 
208
                                if (UNIV_UNLIKELY(!(byte) null_mask)) {
 
209
                                        nulls--;
 
210
                                        null_mask = 1;
 
211
                                }
 
212
 
 
213
                                if (*nulls & null_mask) {
 
214
                                        null_mask <<= 1;
 
215
                                        /* No length is stored for NULL fields.
 
216
                                        We do not advance offs, and we set
 
217
                                        the length to zero and enable the
 
218
                                        SQL NULL flag in offsets[]. */
 
219
                                        len = offs | REC_OFFS_SQL_NULL;
 
220
                                        goto resolved;
 
221
                                }
 
222
                                null_mask <<= 1;
 
223
                        }
 
224
 
 
225
                        if (UNIV_UNLIKELY(!field->fixed_len)) {
 
226
                                /* Variable-length field: read the length */
 
227
                                const dict_col_t*       col
 
228
                                        = dict_field_get_col(field);
 
229
                                len = *lens--;
 
230
                                if (UNIV_UNLIKELY(col->len > 255)
 
231
                                    || UNIV_UNLIKELY(col->mtype
 
232
                                                     == DATA_BLOB)) {
 
233
                                        if (len & 0x80) {
 
234
                                                /* 1exxxxxxx xxxxxxxx */
 
235
                                                len <<= 8;
 
236
                                                len |= *lens--;
 
237
 
 
238
                                                offs += len & 0x3fff;
 
239
                                                if (UNIV_UNLIKELY(len
 
240
                                                                  & 0x4000)) {
 
241
                                                        len = offs
 
242
                                                                | REC_OFFS_EXTERNAL;
 
243
                                                } else {
 
244
                                                        len = offs;
 
245
                                                }
 
246
 
 
247
                                                goto resolved;
 
248
                                        }
 
249
                                }
 
250
 
 
251
                                len = offs += len;
 
252
                        } else {
 
253
                                len = offs += field->fixed_len;
 
254
                        }
 
255
resolved:
 
256
                        rec_offs_base(offsets)[i + 1] = len;
 
257
                } while (++i < rec_offs_n_fields(offsets));
 
258
 
 
259
                *rec_offs_base(offsets)
 
260
                        = (rec - (lens + 1)) | REC_OFFS_COMPACT;
 
261
        } else {
 
262
                /* Old-style record: determine extra size and end offsets */
 
263
                offs = REC_N_OLD_EXTRA_BYTES;
 
264
                if (rec_get_1byte_offs_flag(rec)) {
 
265
                        offs += rec_offs_n_fields(offsets);
 
266
                        *rec_offs_base(offsets) = offs;
 
267
                        /* Determine offsets to fields */
 
268
                        do {
 
269
                                offs = rec_1_get_field_end_info(rec, i);
 
270
                                if (offs & REC_1BYTE_SQL_NULL_MASK) {
 
271
                                        offs &= ~REC_1BYTE_SQL_NULL_MASK;
 
272
                                        offs |= REC_OFFS_SQL_NULL;
 
273
                                }
 
274
                                rec_offs_base(offsets)[1 + i] = offs;
 
275
                        } while (++i < rec_offs_n_fields(offsets));
 
276
                } else {
 
277
                        offs += 2 * rec_offs_n_fields(offsets);
 
278
                        *rec_offs_base(offsets) = offs;
 
279
                        /* Determine offsets to fields */
 
280
                        do {
 
281
                                offs = rec_2_get_field_end_info(rec, i);
 
282
                                if (offs & REC_2BYTE_SQL_NULL_MASK) {
 
283
                                        offs &= ~REC_2BYTE_SQL_NULL_MASK;
 
284
                                        offs |= REC_OFFS_SQL_NULL;
 
285
                                }
 
286
                                if (offs & REC_2BYTE_EXTERN_MASK) {
 
287
                                        offs &= ~REC_2BYTE_EXTERN_MASK;
 
288
                                        offs |= REC_OFFS_EXTERNAL;
 
289
                                }
 
290
                                rec_offs_base(offsets)[1 + i] = offs;
 
291
                        } while (++i < rec_offs_n_fields(offsets));
 
292
                }
 
293
        }
 
294
}
 
295
 
 
296
/**********************************************************
 
297
The following function determines the offsets to each field
 
298
in the record.  It can reuse a previously returned array. */
 
299
 
 
300
ulint*
 
301
rec_get_offsets_func(
 
302
/*=================*/
 
303
                                /* out: the new offsets */
 
304
        rec_t*          rec,    /* in: physical record */
 
305
        dict_index_t*   index,  /* in: record descriptor */
 
306
        ulint*          offsets,/* in/out: array consisting of offsets[0]
 
307
                                allocated elements, or an array from
 
308
                                rec_get_offsets(), or NULL */
 
309
        ulint           n_fields,/* in: maximum number of initialized fields
 
310
                                (ULINT_UNDEFINED if all fields) */
 
311
        mem_heap_t**    heap,   /* in/out: memory heap */
 
312
        const char*     file,   /* in: file name where called */
 
313
        ulint           line)   /* in: line number where called */
 
314
{
 
315
        ulint   n;
 
316
        ulint   size;
 
317
 
 
318
        ut_ad(rec);
 
319
        ut_ad(index);
 
320
        ut_ad(heap);
 
321
 
 
322
        if (dict_table_is_comp(index->table)) {
 
323
                switch (UNIV_EXPECT(rec_get_status(rec),
 
324
                                    REC_STATUS_ORDINARY)) {
 
325
                case REC_STATUS_ORDINARY:
 
326
                        n = dict_index_get_n_fields(index);
 
327
                        break;
 
328
                case REC_STATUS_NODE_PTR:
 
329
                        n = dict_index_get_n_unique_in_tree(index) + 1;
 
330
                        break;
 
331
                case REC_STATUS_INFIMUM:
 
332
                case REC_STATUS_SUPREMUM:
 
333
                        /* infimum or supremum record */
 
334
                        n = 1;
 
335
                        break;
 
336
                default:
 
337
                        ut_error;
 
338
                        return(NULL);
 
339
                }
 
340
        } else {
 
341
                n = rec_get_n_fields_old(rec);
 
342
        }
 
343
 
 
344
        if (UNIV_UNLIKELY(n_fields < n)) {
 
345
                n = n_fields;
 
346
        }
 
347
 
 
348
        size = n + (1 + REC_OFFS_HEADER_SIZE);
 
349
 
 
350
        if (UNIV_UNLIKELY(!offsets)
 
351
            || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
 
352
                if (!*heap) {
 
353
                        *heap = mem_heap_create_func(size * sizeof(ulint),
 
354
                                                     NULL, MEM_HEAP_DYNAMIC,
 
355
                                                     file, line);
 
356
                }
 
357
                offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
 
358
                rec_offs_set_n_alloc(offsets, size);
 
359
        }
 
360
 
 
361
        rec_offs_set_n_fields(offsets, n);
 
362
        rec_init_offsets(rec, index, offsets);
 
363
        return(offsets);
 
364
}
 
365
 
 
366
/****************************************************************
 
367
The following function is used to get a pointer to the nth
 
368
data field in an old-style record. */
 
369
 
 
370
byte*
 
371
rec_get_nth_field_old(
 
372
/*==================*/
 
373
                        /* out: pointer to the field */
 
374
        rec_t*  rec,    /* in: record */
 
375
        ulint   n,      /* in: index of the field */
 
376
        ulint*  len)    /* out: length of the field; UNIV_SQL_NULL if SQL
 
377
                        null */
 
378
{
 
379
        ulint   os;
 
380
        ulint   next_os;
 
381
 
 
382
        ut_ad(rec && len);
 
383
        ut_ad(n < rec_get_n_fields_old(rec));
 
384
 
 
385
        if (n > REC_MAX_N_FIELDS) {
 
386
                fprintf(stderr, "Error: trying to access field %lu in rec\n",
 
387
                        (ulong) n);
 
388
                ut_error;
 
389
        }
 
390
 
 
391
        if (rec == NULL) {
 
392
                fputs("Error: rec is NULL pointer\n", stderr);
 
393
                ut_error;
 
394
        }
 
395
 
 
396
        if (rec_get_1byte_offs_flag(rec)) {
 
397
                os = rec_1_get_field_start_offs(rec, n);
 
398
 
 
399
                next_os = rec_1_get_field_end_info(rec, n);
 
400
 
 
401
                if (next_os & REC_1BYTE_SQL_NULL_MASK) {
 
402
                        *len = UNIV_SQL_NULL;
 
403
 
 
404
                        return(rec + os);
 
405
                }
 
406
 
 
407
                next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
 
408
        } else {
 
409
                os = rec_2_get_field_start_offs(rec, n);
 
410
 
 
411
                next_os = rec_2_get_field_end_info(rec, n);
 
412
 
 
413
                if (next_os & REC_2BYTE_SQL_NULL_MASK) {
 
414
                        *len = UNIV_SQL_NULL;
 
415
 
 
416
                        return(rec + os);
 
417
                }
 
418
 
 
419
                next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
 
420
                                      | REC_2BYTE_EXTERN_MASK);
 
421
        }
 
422
 
 
423
        *len = next_os - os;
 
424
 
 
425
        ut_ad(*len < UNIV_PAGE_SIZE);
 
426
 
 
427
        return(rec + os);
 
428
}
 
429
 
 
430
/**************************************************************
 
431
The following function returns the size of a data tuple when converted to
 
432
a new-style physical record. */
 
433
 
 
434
ulint
 
435
rec_get_converted_size_new(
 
436
/*=======================*/
 
437
                                /* out: size */
 
438
        dict_index_t*   index,  /* in: record descriptor */
 
439
        dtuple_t*       dtuple) /* in: data tuple */
 
440
{
 
441
        ulint           size            = REC_N_NEW_EXTRA_BYTES
 
442
                + UT_BITS_IN_BYTES(index->n_nullable);
 
443
        ulint           i;
 
444
        ulint           n_fields;
 
445
        ut_ad(index && dtuple);
 
446
        ut_ad(dict_table_is_comp(index->table));
 
447
 
 
448
        switch (dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK) {
 
449
        case REC_STATUS_ORDINARY:
 
450
                n_fields = dict_index_get_n_fields(index);
 
451
                ut_ad(n_fields == dtuple_get_n_fields(dtuple));
 
452
                break;
 
453
        case REC_STATUS_NODE_PTR:
 
454
                n_fields = dict_index_get_n_unique_in_tree(index);
 
455
                ut_ad(n_fields + 1 == dtuple_get_n_fields(dtuple));
 
456
                ut_ad(dtuple_get_nth_field(dtuple, n_fields)->len == 4);
 
457
                size += 4; /* child page number */
 
458
                break;
 
459
        case REC_STATUS_INFIMUM:
 
460
        case REC_STATUS_SUPREMUM:
 
461
                /* infimum or supremum record, 8 data bytes */
 
462
                return(REC_N_NEW_EXTRA_BYTES + 8);
 
463
        default:
 
464
                ut_error;
 
465
                return(ULINT_UNDEFINED);
 
466
        }
 
467
 
 
468
        /* read the lengths of fields 0..n */
 
469
        for (i = 0; i < n_fields; i++) {
 
470
                dict_field_t*           field;
 
471
                ulint                   len;
 
472
                const dict_col_t*       col;
 
473
 
 
474
                field = dict_index_get_nth_field(index, i);
 
475
                len = dtuple_get_nth_field(dtuple, i)->len;
 
476
                col = dict_field_get_col(field);
 
477
 
 
478
                ut_ad(dict_col_type_assert_equal(
 
479
                              col, dfield_get_type(dtuple_get_nth_field(
 
480
                                                           dtuple, i))));
 
481
 
 
482
                if (len == UNIV_SQL_NULL) {
 
483
                        /* No length is stored for NULL fields. */
 
484
                        ut_ad(!(col->prtype & DATA_NOT_NULL));
 
485
                        continue;
 
486
                }
 
487
 
 
488
                ut_ad(len <= col->len || col->mtype == DATA_BLOB);
 
489
 
 
490
                if (field->fixed_len) {
 
491
                        ut_ad(len == field->fixed_len);
 
492
                        /* dict_index_add_col() should guarantee this */
 
493
                        ut_ad(!field->prefix_len
 
494
                              || field->fixed_len == field->prefix_len);
 
495
                } else if (len < 128
 
496
                           || (col->len < 256 && col->mtype != DATA_BLOB)) {
 
497
                        size++;
 
498
                } else {
 
499
                        /* For variable-length columns, we look up the
 
500
                        maximum length from the column itself.  If this
 
501
                        is a prefix index column shorter than 256 bytes,
 
502
                        this will waste one byte. */
 
503
                        size += 2;
 
504
                }
 
505
                size += len;
 
506
        }
 
507
 
 
508
        return(size);
 
509
}
 
510
 
 
511
/***************************************************************
 
512
Sets the value of the ith field SQL null bit of an old-style record. */
 
513
 
 
514
void
 
515
rec_set_nth_field_null_bit(
 
516
/*=======================*/
 
517
        rec_t*  rec,    /* in: record */
 
518
        ulint   i,      /* in: ith field */
 
519
        ibool   val)    /* in: value to set */
 
520
{
 
521
        ulint   info;
 
522
 
 
523
        if (rec_get_1byte_offs_flag(rec)) {
 
524
 
 
525
                info = rec_1_get_field_end_info(rec, i);
 
526
 
 
527
                if (val) {
 
528
                        info = info | REC_1BYTE_SQL_NULL_MASK;
 
529
                } else {
 
530
                        info = info & ~REC_1BYTE_SQL_NULL_MASK;
 
531
                }
 
532
 
 
533
                rec_1_set_field_end_info(rec, i, info);
 
534
 
 
535
                return;
 
536
        }
 
537
 
 
538
        info = rec_2_get_field_end_info(rec, i);
 
539
 
 
540
        if (val) {
 
541
                info = info | REC_2BYTE_SQL_NULL_MASK;
 
542
        } else {
 
543
                info = info & ~REC_2BYTE_SQL_NULL_MASK;
 
544
        }
 
545
 
 
546
        rec_2_set_field_end_info(rec, i, info);
 
547
}
 
548
 
 
549
/***************************************************************
 
550
Sets the value of the ith field extern storage bit of an old-style record. */
 
551
 
 
552
void
 
553
rec_set_nth_field_extern_bit_old(
 
554
/*=============================*/
 
555
        rec_t*  rec,    /* in: old-style record */
 
556
        ulint   i,      /* in: ith field */
 
557
        ibool   val,    /* in: value to set */
 
558
        mtr_t*  mtr)    /* in: mtr holding an X-latch to the page where
 
559
                        rec is, or NULL; in the NULL case we do not
 
560
                        write to log about the change */
 
561
{
 
562
        ulint   info;
 
563
 
 
564
        ut_a(!rec_get_1byte_offs_flag(rec));
 
565
        ut_a(i < rec_get_n_fields_old(rec));
 
566
 
 
567
        info = rec_2_get_field_end_info(rec, i);
 
568
 
 
569
        if (val) {
 
570
                info = info | REC_2BYTE_EXTERN_MASK;
 
571
        } else {
 
572
                info = info & ~REC_2BYTE_EXTERN_MASK;
 
573
        }
 
574
 
 
575
        if (mtr) {
 
576
                mlog_write_ulint(rec - REC_N_OLD_EXTRA_BYTES - 2 * (i + 1),
 
577
                                 info, MLOG_2BYTES, mtr);
 
578
        } else {
 
579
                rec_2_set_field_end_info(rec, i, info);
 
580
        }
 
581
}
 
582
 
 
583
/***************************************************************
 
584
Sets the value of the ith field extern storage bit of a new-style record. */
 
585
 
 
586
void
 
587
rec_set_nth_field_extern_bit_new(
 
588
/*=============================*/
 
589
        rec_t*          rec,    /* in: record */
 
590
        dict_index_t*   index,  /* in: record descriptor */
 
591
        ulint           ith,    /* in: ith field */
 
592
        ibool           val,    /* in: value to set */
 
593
        mtr_t*          mtr)    /* in: mtr holding an X-latch to the page
 
594
                                where rec is, or NULL; in the NULL case
 
595
                                we do not write to log about the change */
 
596
{
 
597
        byte*           nulls   = rec - (REC_N_NEW_EXTRA_BYTES + 1);
 
598
        byte*           lens    = nulls - UT_BITS_IN_BYTES(index->n_nullable);
 
599
        ulint           i;
 
600
        ulint           n_fields;
 
601
        ulint           null_mask       = 1;
 
602
        ut_ad(rec && index);
 
603
        ut_ad(dict_table_is_comp(index->table));
 
604
        ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
 
605
 
 
606
        n_fields = dict_index_get_n_fields(index);
 
607
 
 
608
        ut_ad(ith < n_fields);
 
609
 
 
610
        /* read the lengths of fields 0..n */
 
611
        for (i = 0; i < n_fields; i++) {
 
612
                const dict_field_t*     field;
 
613
                const dict_col_t*       col;
 
614
 
 
615
                field = dict_index_get_nth_field(index, i);
 
616
                col = dict_field_get_col(field);
 
617
 
 
618
                if (!(col->prtype & DATA_NOT_NULL)) {
 
619
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
 
620
                                nulls--;
 
621
                                null_mask = 1;
 
622
                        }
 
623
 
 
624
                        if (*nulls & null_mask) {
 
625
                                null_mask <<= 1;
 
626
                                /* NULL fields cannot be external. */
 
627
                                ut_ad(i != ith);
 
628
                                continue;
 
629
                        }
 
630
 
 
631
                        null_mask <<= 1;
 
632
                }
 
633
                if (field->fixed_len) {
 
634
                        /* fixed-length fields cannot be external
 
635
                        (Fixed-length fields longer than
 
636
                        DICT_MAX_INDEX_COL_LEN will be treated as
 
637
                        variable-length ones in dict_index_add_col().) */
 
638
                        ut_ad(i != ith);
 
639
                        continue;
 
640
                }
 
641
                lens--;
 
642
                if (col->len > 255 || col->mtype == DATA_BLOB) {
 
643
                        ulint   len = lens[1];
 
644
                        if (len & 0x80) { /* 1exxxxxx: 2-byte length */
 
645
                                if (i == ith) {
 
646
                                        if (!val == !(len & 0x40)) {
 
647
                                                return; /* no change */
 
648
                                        }
 
649
                                        /* toggle the extern bit */
 
650
                                        len ^= 0x40;
 
651
                                        if (mtr) {
 
652
                                                mlog_write_ulint(lens + 1,
 
653
                                                                 len,
 
654
                                                                 MLOG_1BYTE,
 
655
                                                                 mtr);
 
656
                                        } else {
 
657
                                                lens[1] = (byte) len;
 
658
                                        }
 
659
                                        return;
 
660
                                }
 
661
                                lens--;
 
662
                        } else {
 
663
                                /* short fields cannot be external */
 
664
                                ut_ad(i != ith);
 
665
                        }
 
666
                } else {
 
667
                        /* short fields cannot be external */
 
668
                        ut_ad(i != ith);
 
669
                }
 
670
        }
 
671
}
 
672
 
 
673
/***************************************************************
 
674
Sets TRUE the extern storage bits of fields mentioned in an array. */
 
675
 
 
676
void
 
677
rec_set_field_extern_bits(
 
678
/*======================*/
 
679
        rec_t*          rec,    /* in: record */
 
680
        dict_index_t*   index,  /* in: record descriptor */
 
681
        const ulint*    vec,    /* in: array of field numbers */
 
682
        ulint           n_fields,/* in: number of fields numbers */
 
683
        mtr_t*          mtr)    /* in: mtr holding an X-latch to the
 
684
                                page where rec is, or NULL;
 
685
                                in the NULL case we do not write
 
686
                                to log about the change */
 
687
{
 
688
        ulint   i;
 
689
 
 
690
        if (dict_table_is_comp(index->table)) {
 
691
                for (i = 0; i < n_fields; i++) {
 
692
                        rec_set_nth_field_extern_bit_new(rec, index, vec[i],
 
693
                                                         TRUE, mtr);
 
694
                }
 
695
        } else {
 
696
                for (i = 0; i < n_fields; i++) {
 
697
                        rec_set_nth_field_extern_bit_old(rec, vec[i],
 
698
                                                         TRUE, mtr);
 
699
                }
 
700
        }
 
701
}
 
702
 
 
703
/***************************************************************
 
704
Sets an old-style record field to SQL null.
 
705
The physical size of the field is not changed. */
 
706
 
 
707
void
 
708
rec_set_nth_field_sql_null(
 
709
/*=======================*/
 
710
        rec_t*  rec,    /* in: record */
 
711
        ulint   n)      /* in: index of the field */
 
712
{
 
713
        ulint   offset;
 
714
 
 
715
        offset = rec_get_field_start_offs(rec, n);
 
716
 
 
717
        data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
 
718
 
 
719
        rec_set_nth_field_null_bit(rec, n, TRUE);
 
720
}
 
721
 
 
722
/*************************************************************
 
723
Builds an old-style physical record out of a data tuple and
 
724
stores it beginning from the start of the given buffer. */
 
725
static
 
726
rec_t*
 
727
rec_convert_dtuple_to_rec_old(
 
728
/*==========================*/
 
729
                        /* out: pointer to the origin of
 
730
                        physical record */
 
731
        byte*   buf,    /* in: start address of the physical record */
 
732
        dtuple_t* dtuple)/* in: data tuple */
 
733
{
 
734
        dfield_t*       field;
 
735
        ulint           n_fields;
 
736
        ulint           data_size;
 
737
        rec_t*          rec;
 
738
        ulint           end_offset;
 
739
        ulint           ored_offset;
 
740
        byte*           data;
 
741
        ulint           len;
 
742
        ulint           i;
 
743
 
 
744
        ut_ad(buf && dtuple);
 
745
        ut_ad(dtuple_validate(dtuple));
 
746
        ut_ad(dtuple_check_typed(dtuple));
 
747
 
 
748
        n_fields = dtuple_get_n_fields(dtuple);
 
749
        data_size = dtuple_get_data_size(dtuple);
 
750
 
 
751
        ut_ad(n_fields > 0);
 
752
 
 
753
        /* Calculate the offset of the origin in the physical record */
 
754
 
 
755
        rec = buf + rec_get_converted_extra_size(data_size, n_fields);
 
756
#ifdef UNIV_DEBUG
 
757
        /* Suppress Valgrind warnings of ut_ad()
 
758
        in mach_write_to_1(), mach_write_to_2() et al. */
 
759
        memset(buf, 0xff, rec - buf + data_size);
 
760
#endif /* UNIV_DEBUG */
 
761
        /* Store the number of fields */
 
762
        rec_set_n_fields_old(rec, n_fields);
 
763
 
 
764
        /* Set the info bits of the record */
 
765
        rec_set_info_bits(rec, FALSE,
 
766
                          dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
 
767
 
 
768
        /* Store the data and the offsets */
 
769
 
 
770
        end_offset = 0;
 
771
 
 
772
        if (data_size <= REC_1BYTE_OFFS_LIMIT) {
 
773
 
 
774
                rec_set_1byte_offs_flag(rec, TRUE);
 
775
 
 
776
                for (i = 0; i < n_fields; i++) {
 
777
 
 
778
                        field = dtuple_get_nth_field(dtuple, i);
 
779
 
 
780
                        data = dfield_get_data(field);
 
781
                        len = dfield_get_len(field);
 
782
 
 
783
                        if (len == UNIV_SQL_NULL) {
 
784
                                len = dtype_get_sql_null_size(
 
785
                                        dfield_get_type(field));
 
786
                                data_write_sql_null(rec + end_offset, len);
 
787
 
 
788
                                end_offset += len;
 
789
                                ored_offset = end_offset
 
790
                                        | REC_1BYTE_SQL_NULL_MASK;
 
791
                        } else {
 
792
                                /* If the data is not SQL null, store it */
 
793
                                ut_memcpy(rec + end_offset, data, len);
 
794
 
 
795
                                end_offset += len;
 
796
                                ored_offset = end_offset;
 
797
                        }
 
798
 
 
799
                        rec_1_set_field_end_info(rec, i, ored_offset);
 
800
                }
 
801
        } else {
 
802
                rec_set_1byte_offs_flag(rec, FALSE);
 
803
 
 
804
                for (i = 0; i < n_fields; i++) {
 
805
 
 
806
                        field = dtuple_get_nth_field(dtuple, i);
 
807
 
 
808
                        data = dfield_get_data(field);
 
809
                        len = dfield_get_len(field);
 
810
 
 
811
                        if (len == UNIV_SQL_NULL) {
 
812
                                len = dtype_get_sql_null_size(
 
813
                                        dfield_get_type(field));
 
814
                                data_write_sql_null(rec + end_offset, len);
 
815
 
 
816
                                end_offset += len;
 
817
                                ored_offset = end_offset
 
818
                                        | REC_2BYTE_SQL_NULL_MASK;
 
819
                        } else {
 
820
                                /* If the data is not SQL null, store it */
 
821
                                ut_memcpy(rec + end_offset, data, len);
 
822
 
 
823
                                end_offset += len;
 
824
                                ored_offset = end_offset;
 
825
                        }
 
826
 
 
827
                        rec_2_set_field_end_info(rec, i, ored_offset);
 
828
                }
 
829
        }
 
830
 
 
831
        return(rec);
 
832
}
 
833
 
 
834
/*************************************************************
 
835
Builds a new-style physical record out of a data tuple and
 
836
stores it beginning from the start of the given buffer. */
 
837
static
 
838
rec_t*
 
839
rec_convert_dtuple_to_rec_new(
 
840
/*==========================*/
 
841
                                /* out: pointer to the origin
 
842
                                of physical record */
 
843
        byte*           buf,    /* in: start address of the physical record */
 
844
        dict_index_t*   index,  /* in: record descriptor */
 
845
        dtuple_t*       dtuple) /* in: data tuple */
 
846
{
 
847
        dfield_t*       field;
 
848
        dtype_t*        type;
 
849
        rec_t*          rec             = buf + REC_N_NEW_EXTRA_BYTES;
 
850
        byte*           end;
 
851
        byte*           nulls;
 
852
        byte*           lens;
 
853
        ulint           len;
 
854
        ulint           i;
 
855
        ulint           n_node_ptr_field;
 
856
        ulint           fixed_len;
 
857
        ulint           null_mask       = 1;
 
858
        const ulint     n_fields        = dtuple_get_n_fields(dtuple);
 
859
        const ulint     status          = dtuple_get_info_bits(dtuple)
 
860
                & REC_NEW_STATUS_MASK;
 
861
        ut_ad(dict_table_is_comp(index->table));
 
862
        ut_ad(n_fields > 0);
 
863
 
 
864
        /* Try to ensure that the memset() between the for() loops
 
865
        completes fast.  The address is not exact, but UNIV_PREFETCH
 
866
        should never generate a memory fault. */
 
867
        UNIV_PREFETCH_RW(rec - REC_N_NEW_EXTRA_BYTES - n_fields);
 
868
        UNIV_PREFETCH_RW(rec);
 
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
                n_node_ptr_field = ULINT_UNDEFINED;
 
874
                break;
 
875
        case REC_STATUS_NODE_PTR:
 
876
                ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
 
877
                n_node_ptr_field = n_fields - 1;
 
878
                break;
 
879
        case REC_STATUS_INFIMUM:
 
880
        case REC_STATUS_SUPREMUM:
 
881
                ut_ad(n_fields == 1);
 
882
                n_node_ptr_field = ULINT_UNDEFINED;
 
883
                goto init;
 
884
        default:
 
885
                ut_a(0);
 
886
                return(0);
 
887
        }
 
888
 
 
889
        /* Calculate the offset of the origin in the physical record.
 
890
        We must loop over all fields to do this. */
 
891
        rec += UT_BITS_IN_BYTES(index->n_nullable);
 
892
 
 
893
        for (i = 0; i < n_fields; i++) {
 
894
                if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
 
895
#ifdef UNIV_DEBUG
 
896
                        field = dtuple_get_nth_field(dtuple, i);
 
897
                        type = dfield_get_type(field);
 
898
                        ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
 
899
                        ut_ad(dfield_get_len(field) == 4);
 
900
#endif /* UNIV_DEBUG */
 
901
                        goto init;
 
902
                }
 
903
                field = dtuple_get_nth_field(dtuple, i);
 
904
                type = dfield_get_type(field);
 
905
                len = dfield_get_len(field);
 
906
                fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
 
907
 
 
908
                ut_ad(dict_col_type_assert_equal(
 
909
                              dict_field_get_col(dict_index_get_nth_field(
 
910
                                                         index, i)),
 
911
                              dfield_get_type(field)));
 
912
 
 
913
                if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
 
914
                        if (len == UNIV_SQL_NULL)
 
915
                                continue;
 
916
                }
 
917
                /* only nullable fields can be null */
 
918
                ut_ad(len != UNIV_SQL_NULL);
 
919
                if (fixed_len) {
 
920
                        ut_ad(len == fixed_len);
 
921
                } else {
 
922
                        ut_ad(len <= dtype_get_len(type)
 
923
                              || dtype_get_mtype(type) == DATA_BLOB);
 
924
                        rec++;
 
925
                        if (len >= 128
 
926
                            && (dtype_get_len(type) >= 256
 
927
                                || dtype_get_mtype(type) == DATA_BLOB)) {
 
928
                                rec++;
 
929
                        }
 
930
                }
 
931
        }
 
932
 
 
933
init:
 
934
        end = rec;
 
935
        nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
 
936
        lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
 
937
        /* clear the SQL-null flags */
 
938
        memset (lens + 1, 0, nulls - lens);
 
939
 
 
940
        /* Set the info bits of the record */
 
941
        rec_set_status(rec, status);
 
942
 
 
943
        rec_set_info_bits(rec, TRUE,
 
944
                          dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
 
945
 
 
946
        /* Store the data and the offsets */
 
947
 
 
948
        for (i = 0; i < n_fields; i++) {
 
949
                field = dtuple_get_nth_field(dtuple, i);
 
950
                type = dfield_get_type(field);
 
951
                len = dfield_get_len(field);
 
952
 
 
953
                if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
 
954
                        ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
 
955
                        ut_ad(len == 4);
 
956
                        memcpy(end, dfield_get_data(field), len);
 
957
                        break;
 
958
                }
 
959
                fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
 
960
 
 
961
                if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
 
962
                        /* nullable field */
 
963
                        ut_ad(index->n_nullable > 0);
 
964
 
 
965
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
 
966
                                nulls--;
 
967
                                null_mask = 1;
 
968
                        }
 
969
 
 
970
                        ut_ad(*nulls < null_mask);
 
971
 
 
972
                        /* set the null flag if necessary */
 
973
                        if (len == UNIV_SQL_NULL) {
 
974
                                *nulls |= null_mask;
 
975
                                null_mask <<= 1;
 
976
                                continue;
 
977
                        }
 
978
 
 
979
                        null_mask <<= 1;
 
980
                }
 
981
                /* only nullable fields can be null */
 
982
                ut_ad(len != UNIV_SQL_NULL);
 
983
                if (fixed_len) {
 
984
                        ut_ad(len == fixed_len);
 
985
                } else {
 
986
                        ut_ad(len <= dtype_get_len(type)
 
987
                              || dtype_get_mtype(type) == DATA_BLOB);
 
988
                        if (len < 128
 
989
                            || (dtype_get_len(type) < 256
 
990
                                && dtype_get_mtype(type) != DATA_BLOB)) {
 
991
 
 
992
                                *lens-- = (byte) len;
 
993
                        } else {
 
994
                                /* the extern bits will be set later */
 
995
                                ut_ad(len < 16384);
 
996
                                *lens-- = (byte) (len >> 8) | 0x80;
 
997
                                *lens-- = (byte) len;
 
998
                        }
 
999
                }
 
1000
 
 
1001
                memcpy(end, dfield_get_data(field), len);
 
1002
                end += len;
 
1003
        }
 
1004
 
 
1005
        return(rec);
 
1006
}
 
1007
 
 
1008
/*************************************************************
 
1009
Builds a physical record out of a data tuple and
 
1010
stores it beginning from the start of the given buffer. */
 
1011
 
 
1012
rec_t*
 
1013
rec_convert_dtuple_to_rec(
 
1014
/*======================*/
 
1015
                                        /* out: pointer to the origin
 
1016
                                        of physical record */
 
1017
        byte*           buf,            /* in: start address of the
 
1018
                                        physical record */
 
1019
        dict_index_t*   index,          /* in: record descriptor */
 
1020
        dtuple_t*       dtuple)         /* in: data tuple */
 
1021
{
 
1022
        rec_t*  rec;
 
1023
 
 
1024
        ut_ad(buf && index && dtuple);
 
1025
        ut_ad(dtuple_validate(dtuple));
 
1026
        ut_ad(dtuple_check_typed(dtuple));
 
1027
 
 
1028
        if (dict_table_is_comp(index->table)) {
 
1029
                rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
 
1030
        } else {
 
1031
                rec = rec_convert_dtuple_to_rec_old(buf, dtuple);
 
1032
        }
 
1033
 
 
1034
#ifdef UNIV_DEBUG
 
1035
        {
 
1036
                mem_heap_t*     heap    = NULL;
 
1037
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
1038
                const ulint*    offsets;
 
1039
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
1040
 
 
1041
                offsets = rec_get_offsets(rec, index,
 
1042
                                          offsets_, ULINT_UNDEFINED, &heap);
 
1043
                ut_ad(rec_validate(rec, offsets));
 
1044
                if (UNIV_LIKELY_NULL(heap)) {
 
1045
                        mem_heap_free(heap);
 
1046
                }
 
1047
        }
 
1048
#endif /* UNIV_DEBUG */
 
1049
        return(rec);
 
1050
}
 
1051
 
 
1052
/******************************************************************
 
1053
Copies the first n fields of a physical record to a data tuple. The fields
 
1054
are copied to the memory heap. */
 
1055
 
 
1056
void
 
1057
rec_copy_prefix_to_dtuple(
 
1058
/*======================*/
 
1059
        dtuple_t*       tuple,          /* in: data tuple */
 
1060
        rec_t*          rec,            /* in: physical record */
 
1061
        dict_index_t*   index,          /* in: record descriptor */
 
1062
        ulint           n_fields,       /* in: number of fields to copy */
 
1063
        mem_heap_t*     heap)           /* in: memory heap */
 
1064
{
 
1065
        dfield_t*       field;
 
1066
        byte*           data;
 
1067
        ulint           len;
 
1068
        byte*           buf = NULL;
 
1069
        ulint           i;
 
1070
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
1071
        ulint*          offsets = offsets_;
 
1072
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
1073
 
 
1074
        offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
 
1075
 
 
1076
        ut_ad(rec_validate(rec, offsets));
 
1077
        ut_ad(dtuple_check_typed(tuple));
 
1078
 
 
1079
        dtuple_set_info_bits(tuple, rec_get_info_bits(
 
1080
                                     rec, dict_table_is_comp(index->table)));
 
1081
 
 
1082
        for (i = 0; i < n_fields; i++) {
 
1083
 
 
1084
                field = dtuple_get_nth_field(tuple, i);
 
1085
                data = rec_get_nth_field(rec, offsets, i, &len);
 
1086
 
 
1087
                if (len != UNIV_SQL_NULL) {
 
1088
                        buf = mem_heap_alloc(heap, len);
 
1089
 
 
1090
                        ut_memcpy(buf, data, len);
 
1091
                }
 
1092
 
 
1093
                dfield_set_data(field, buf, len);
 
1094
        }
 
1095
}
 
1096
 
 
1097
/******************************************************************
 
1098
Copies the first n fields of an old-style physical record
 
1099
to a new physical record in a buffer. */
 
1100
static
 
1101
rec_t*
 
1102
rec_copy_prefix_to_buf_old(
 
1103
/*=======================*/
 
1104
                                /* out, own: copied record */
 
1105
        rec_t*  rec,            /* in: physical record */
 
1106
        ulint   n_fields,       /* in: number of fields to copy */
 
1107
        ulint   area_end,       /* in: end of the prefix data */
 
1108
        byte**  buf,            /* in/out: memory buffer for the copied prefix,
 
1109
                                or NULL */
 
1110
        ulint*  buf_size)       /* in/out: buffer size */
 
1111
{
 
1112
        rec_t*  copy_rec;
 
1113
        ulint   area_start;
 
1114
        ulint   prefix_len;
 
1115
 
 
1116
        if (rec_get_1byte_offs_flag(rec)) {
 
1117
                area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
 
1118
        } else {
 
1119
                area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
 
1120
        }
 
1121
 
 
1122
        prefix_len = area_start + area_end;
 
1123
 
 
1124
        if ((*buf == NULL) || (*buf_size < prefix_len)) {
 
1125
                if (*buf != NULL) {
 
1126
                        mem_free(*buf);
 
1127
                }
 
1128
 
 
1129
                *buf = mem_alloc(prefix_len);
 
1130
                *buf_size = prefix_len;
 
1131
        }
 
1132
 
 
1133
        ut_memcpy(*buf, rec - area_start, prefix_len);
 
1134
 
 
1135
        copy_rec = *buf + area_start;
 
1136
 
 
1137
        rec_set_n_fields_old(copy_rec, n_fields);
 
1138
 
 
1139
        return(copy_rec);
 
1140
}
 
1141
 
 
1142
/******************************************************************
 
1143
Copies the first n fields of a physical record to a new physical record in
 
1144
a buffer. */
 
1145
 
 
1146
rec_t*
 
1147
rec_copy_prefix_to_buf(
 
1148
/*===================*/
 
1149
                                        /* out, own: copied record */
 
1150
        rec_t*          rec,            /* in: physical record */
 
1151
        dict_index_t*   index,          /* in: record descriptor */
 
1152
        ulint           n_fields,       /* in: number of fields to copy */
 
1153
        byte**          buf,            /* in/out: memory buffer
 
1154
                                        for the copied prefix, or NULL */
 
1155
        ulint*          buf_size)       /* in/out: buffer size */
 
1156
{
 
1157
        byte*           nulls;
 
1158
        byte*           lens;
 
1159
        ulint           i;
 
1160
        ulint           prefix_len;
 
1161
        ulint           null_mask;
 
1162
        ulint           status;
 
1163
 
 
1164
        UNIV_PREFETCH_RW(*buf);
 
1165
 
 
1166
        if (!dict_table_is_comp(index->table)) {
 
1167
                ut_ad(rec_validate_old(rec));
 
1168
                return(rec_copy_prefix_to_buf_old(
 
1169
                               rec, n_fields,
 
1170
                               rec_get_field_start_offs(rec, n_fields),
 
1171
                               buf, buf_size));
 
1172
        }
 
1173
 
 
1174
        status = rec_get_status(rec);
 
1175
 
 
1176
        switch (status) {
 
1177
        case REC_STATUS_ORDINARY:
 
1178
                ut_ad(n_fields <= dict_index_get_n_fields(index));
 
1179
                break;
 
1180
        case REC_STATUS_NODE_PTR:
 
1181
                /* it doesn't make sense to copy the child page number field */
 
1182
                ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
 
1183
                break;
 
1184
        case REC_STATUS_INFIMUM:
 
1185
        case REC_STATUS_SUPREMUM:
 
1186
                /* infimum or supremum record: no sense to copy anything */
 
1187
        default:
 
1188
                ut_error;
 
1189
                return(NULL);
 
1190
        }
 
1191
 
 
1192
        nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
 
1193
        lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
 
1194
        UNIV_PREFETCH_R(lens);
 
1195
        prefix_len = 0;
 
1196
        null_mask = 1;
 
1197
 
 
1198
        /* read the lengths of fields 0..n */
 
1199
        for (i = 0; i < n_fields; i++) {
 
1200
                const dict_field_t*     field;
 
1201
                const dict_col_t*       col;
 
1202
 
 
1203
                field = dict_index_get_nth_field(index, i);
 
1204
                col = dict_field_get_col(field);
 
1205
 
 
1206
                if (!(col->prtype & DATA_NOT_NULL)) {
 
1207
                        /* nullable field => read the null flag */
 
1208
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
 
1209
                                nulls--;
 
1210
                                null_mask = 1;
 
1211
                        }
 
1212
 
 
1213
                        if (*nulls & null_mask) {
 
1214
                                null_mask <<= 1;
 
1215
                                continue;
 
1216
                        }
 
1217
 
 
1218
                        null_mask <<= 1;
 
1219
                }
 
1220
 
 
1221
                if (field->fixed_len) {
 
1222
                        prefix_len += field->fixed_len;
 
1223
                } else {
 
1224
                        ulint   len = *lens--;
 
1225
                        if (col->len > 255 || col->mtype == DATA_BLOB) {
 
1226
                                if (len & 0x80) {
 
1227
                                        /* 1exxxxxx */
 
1228
                                        len &= 0x3f;
 
1229
                                        len <<= 8;
 
1230
                                        len |= *lens--;
 
1231
                                        UNIV_PREFETCH_R(lens);
 
1232
                                }
 
1233
                        }
 
1234
                        prefix_len += len;
 
1235
                }
 
1236
        }
 
1237
 
 
1238
        UNIV_PREFETCH_R(rec + prefix_len);
 
1239
 
 
1240
        prefix_len += rec - (lens + 1);
 
1241
 
 
1242
        if ((*buf == NULL) || (*buf_size < prefix_len)) {
 
1243
                if (*buf != NULL) {
 
1244
                        mem_free(*buf);
 
1245
                }
 
1246
 
 
1247
                *buf = mem_alloc(prefix_len);
 
1248
                *buf_size = prefix_len;
 
1249
        }
 
1250
 
 
1251
        memcpy(*buf, lens + 1, prefix_len);
 
1252
 
 
1253
        return(*buf + (rec - (lens + 1)));
 
1254
}
 
1255
 
 
1256
/*******************************************************************
 
1257
Validates the consistency of an old-style physical record. */
 
1258
static
 
1259
ibool
 
1260
rec_validate_old(
 
1261
/*=============*/
 
1262
                        /* out: TRUE if ok */
 
1263
        rec_t*  rec)    /* in: physical record */
 
1264
{
 
1265
        byte*   data;
 
1266
        ulint   len;
 
1267
        ulint   n_fields;
 
1268
        ulint   len_sum         = 0;
 
1269
        ulint   sum             = 0;
 
1270
        ulint   i;
 
1271
 
 
1272
        ut_a(rec);
 
1273
        n_fields = rec_get_n_fields_old(rec);
 
1274
 
 
1275
        if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
 
1276
                fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
 
1277
                        (ulong) n_fields);
 
1278
                return(FALSE);
 
1279
        }
 
1280
 
 
1281
        for (i = 0; i < n_fields; i++) {
 
1282
                data = rec_get_nth_field_old(rec, i, &len);
 
1283
 
 
1284
                if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
 
1285
                        fprintf(stderr,
 
1286
                                "InnoDB: Error: record field %lu len %lu\n",
 
1287
                                (ulong) i,
 
1288
                                (ulong) len);
 
1289
                        return(FALSE);
 
1290
                }
 
1291
 
 
1292
                if (len != UNIV_SQL_NULL) {
 
1293
                        len_sum += len;
 
1294
                        sum += *(data + len -1); /* dereference the
 
1295
                                                 end of the field to
 
1296
                                                 cause a memory trap
 
1297
                                                 if possible */
 
1298
                } else {
 
1299
                        len_sum += rec_get_nth_field_size(rec, i);
 
1300
                }
 
1301
        }
 
1302
 
 
1303
        if (len_sum != rec_get_data_size_old(rec)) {
 
1304
                fprintf(stderr,
 
1305
                        "InnoDB: Error: record len should be %lu, len %lu\n",
 
1306
                        (ulong) len_sum,
 
1307
                        rec_get_data_size_old(rec));
 
1308
                return(FALSE);
 
1309
        }
 
1310
 
 
1311
        rec_dummy = sum; /* This is here only to fool the compiler */
 
1312
 
 
1313
        return(TRUE);
 
1314
}
 
1315
 
 
1316
/*******************************************************************
 
1317
Validates the consistency of a physical record. */
 
1318
 
 
1319
ibool
 
1320
rec_validate(
 
1321
/*=========*/
 
1322
                                /* out: TRUE if ok */
 
1323
        rec_t*          rec,    /* in: physical record */
 
1324
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1325
{
 
1326
        const byte*     data;
 
1327
        ulint           len;
 
1328
        ulint           n_fields;
 
1329
        ulint           len_sum         = 0;
 
1330
        ulint           sum             = 0;
 
1331
        ulint           i;
 
1332
 
 
1333
        ut_a(rec);
 
1334
        n_fields = rec_offs_n_fields(offsets);
 
1335
 
 
1336
        if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
 
1337
                fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
 
1338
                        (ulong) n_fields);
 
1339
                return(FALSE);
 
1340
        }
 
1341
 
 
1342
        ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
 
1343
 
 
1344
        for (i = 0; i < n_fields; i++) {
 
1345
                data = rec_get_nth_field(rec, offsets, i, &len);
 
1346
 
 
1347
                if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
 
1348
                        fprintf(stderr,
 
1349
                                "InnoDB: Error: record field %lu len %lu\n",
 
1350
                                (ulong) i,
 
1351
                                (ulong) len);
 
1352
                        return(FALSE);
 
1353
                }
 
1354
 
 
1355
                if (len != UNIV_SQL_NULL) {
 
1356
                        len_sum += len;
 
1357
                        sum += *(data + len -1); /* dereference the
 
1358
                                                 end of the field to
 
1359
                                                 cause a memory trap
 
1360
                                                 if possible */
 
1361
                } else if (!rec_offs_comp(offsets)) {
 
1362
                        len_sum += rec_get_nth_field_size(rec, i);
 
1363
                }
 
1364
        }
 
1365
 
 
1366
        if (len_sum != (ulint)(rec_get_end(rec, offsets) - rec)) {
 
1367
                fprintf(stderr,
 
1368
                        "InnoDB: Error: record len should be %lu, len %lu\n",
 
1369
                        (ulong) len_sum,
 
1370
                        (ulong) (rec_get_end(rec, offsets) - rec));
 
1371
                return(FALSE);
 
1372
        }
 
1373
 
 
1374
        rec_dummy = sum; /* This is here only to fool the compiler */
 
1375
 
 
1376
        if (!rec_offs_comp(offsets)) {
 
1377
                ut_a(rec_validate_old(rec));
 
1378
        }
 
1379
 
 
1380
        return(TRUE);
 
1381
}
 
1382
 
 
1383
/*******************************************************************
 
1384
Prints an old-style physical record. */
 
1385
 
 
1386
void
 
1387
rec_print_old(
 
1388
/*==========*/
 
1389
        FILE*           file,   /* in: file where to print */
 
1390
        rec_t*          rec)    /* in: physical record */
 
1391
{
 
1392
        const byte*     data;
 
1393
        ulint           len;
 
1394
        ulint           n;
 
1395
        ulint           i;
 
1396
 
 
1397
        ut_ad(rec);
 
1398
 
 
1399
        n = rec_get_n_fields_old(rec);
 
1400
 
 
1401
        fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
 
1402
                " %u-byte offsets; info bits %lu\n",
 
1403
                (ulong) n,
 
1404
                rec_get_1byte_offs_flag(rec) ? 1 : 2,
 
1405
                (ulong) rec_get_info_bits(rec, FALSE));
 
1406
 
 
1407
        for (i = 0; i < n; i++) {
 
1408
 
 
1409
                data = rec_get_nth_field_old(rec, i, &len);
 
1410
 
 
1411
                fprintf(file, " %lu:", (ulong) i);
 
1412
 
 
1413
                if (len != UNIV_SQL_NULL) {
 
1414
                        if (len <= 30) {
 
1415
 
 
1416
                                ut_print_buf(file, data, len);
 
1417
                        } else {
 
1418
                                ut_print_buf(file, data, 30);
 
1419
 
 
1420
                                fputs("...(truncated)", file);
 
1421
                        }
 
1422
                } else {
 
1423
                        fprintf(file, " SQL NULL, size %lu ",
 
1424
                                rec_get_nth_field_size(rec, i));
 
1425
                }
 
1426
                putc(';', file);
 
1427
        }
 
1428
 
 
1429
        putc('\n', file);
 
1430
 
 
1431
        rec_validate_old(rec);
 
1432
}
 
1433
 
 
1434
/*******************************************************************
 
1435
Prints a physical record. */
 
1436
 
 
1437
void
 
1438
rec_print_new(
 
1439
/*==========*/
 
1440
        FILE*           file,   /* in: file where to print */
 
1441
        rec_t*          rec,    /* in: physical record */
 
1442
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1443
{
 
1444
        const byte*     data;
 
1445
        ulint           len;
 
1446
        ulint           i;
 
1447
 
 
1448
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
1449
 
 
1450
        if (!rec_offs_comp(offsets)) {
 
1451
                rec_print_old(file, rec);
 
1452
                return;
 
1453
        }
 
1454
 
 
1455
        ut_ad(rec);
 
1456
 
 
1457
        fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
 
1458
                " compact format; info bits %lu\n",
 
1459
                (ulong) rec_offs_n_fields(offsets),
 
1460
                (ulong) rec_get_info_bits(rec, TRUE));
 
1461
 
 
1462
        for (i = 0; i < rec_offs_n_fields(offsets); i++) {
 
1463
 
 
1464
                data = rec_get_nth_field(rec, offsets, i, &len);
 
1465
 
 
1466
                fprintf(file, " %lu:", (ulong) i);
 
1467
 
 
1468
                if (len != UNIV_SQL_NULL) {
 
1469
                        if (len <= 30) {
 
1470
 
 
1471
                                ut_print_buf(file, data, len);
 
1472
                        } else {
 
1473
                                ut_print_buf(file, data, 30);
 
1474
 
 
1475
                                fputs("...(truncated)", file);
 
1476
                        }
 
1477
                } else {
 
1478
                        fputs(" SQL NULL", file);
 
1479
                }
 
1480
                putc(';', file);
 
1481
        }
 
1482
 
 
1483
        putc('\n', file);
 
1484
 
 
1485
        rec_validate(rec, offsets);
 
1486
}
 
1487
 
 
1488
/*******************************************************************
 
1489
Prints a physical record. */
 
1490
 
 
1491
void
 
1492
rec_print(
 
1493
/*======*/
 
1494
        FILE*           file,   /* in: file where to print */
 
1495
        rec_t*          rec,    /* in: physical record */
 
1496
        dict_index_t*   index)  /* in: record descriptor */
 
1497
{
 
1498
        ut_ad(index);
 
1499
 
 
1500
        if (!dict_table_is_comp(index->table)) {
 
1501
                rec_print_old(file, rec);
 
1502
                return;
 
1503
        } else {
 
1504
                mem_heap_t*     heap    = NULL;
 
1505
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
1506
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
1507
 
 
1508
                rec_print_new(file, rec,
 
1509
                              rec_get_offsets(rec, index, offsets_,
 
1510
                                              ULINT_UNDEFINED, &heap));
 
1511
                if (UNIV_LIKELY_NULL(heap)) {
 
1512
                        mem_heap_free(heap);
 
1513
                }
 
1514
        }
 
1515
}