~drizzle-trunk/drizzle/development

« 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
 
/* this is used to fool compiler in rec_validate */
128
 
UNIV_INTERN ulint       rec_dummy;
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
 
        const rec_t*    rec);   /* in: physical record */
138
 
 
139
 
/**********************************************************
140
 
Determine how many of the first n columns in a compact
141
 
physical record are stored externally. */
142
 
UNIV_INTERN
143
 
ulint
144
 
rec_get_n_extern_new(
145
 
/*=================*/
146
 
                                /* out: number of externally stored columns */
147
 
        const rec_t*    rec,    /* in: compact physical record */
148
 
        dict_index_t*   index,  /* in: record descriptor */
149
 
        ulint           n)      /* in: number of columns to scan */
150
 
{
151
 
        const byte*     nulls;
152
 
        const byte*     lens;
153
 
        dict_field_t*   field;
154
 
        ulint           null_mask;
155
 
        ulint           n_extern;
156
 
        ulint           i;
157
 
 
158
 
        ut_ad(dict_table_is_comp(index->table));
159
 
        ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
160
 
        ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
161
 
 
162
 
        if (n == ULINT_UNDEFINED) {
163
 
                n = dict_index_get_n_fields(index);
164
 
        }
165
 
 
166
 
        nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
167
 
        lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
168
 
        null_mask = 1;
169
 
        n_extern = 0;
170
 
        i = 0;
171
 
 
172
 
        /* read the lengths of fields 0..n */
173
 
        do {
174
 
                ulint   len;
175
 
 
176
 
                field = dict_index_get_nth_field(index, i);
177
 
                if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
178
 
                        /* nullable field => read the null flag */
179
 
 
180
 
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
181
 
                                nulls--;
182
 
                                null_mask = 1;
183
 
                        }
184
 
 
185
 
                        if (*nulls & null_mask) {
186
 
                                null_mask <<= 1;
187
 
                                /* No length is stored for NULL fields. */
188
 
                                continue;
189
 
                        }
190
 
                        null_mask <<= 1;
191
 
                }
192
 
 
193
 
                if (UNIV_UNLIKELY(!field->fixed_len)) {
194
 
                        /* Variable-length field: read the length */
195
 
                        const dict_col_t*       col
196
 
                                = dict_field_get_col(field);
197
 
                        len = *lens--;
198
 
                        if (UNIV_UNLIKELY(col->len > 255)
199
 
                            || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
200
 
                                if (len & 0x80) {
201
 
                                        /* 1exxxxxxx xxxxxxxx */
202
 
                                        if (len & 0x40) {
203
 
                                                n_extern++;
204
 
                                        }
205
 
                                        lens--;
206
 
                                }
207
 
                        }
208
 
                }
209
 
        } while (++i < n);
210
 
 
211
 
        return(n_extern);
212
 
}
213
 
 
214
 
/**********************************************************
215
 
Determine the offset to each field in a leaf-page record
216
 
in ROW_FORMAT=COMPACT.  This is a special case of
217
 
rec_init_offsets() and rec_get_offsets_func(). */
218
 
UNIV_INTERN
219
 
void
220
 
rec_init_offsets_comp_ordinary(
221
 
/*===========================*/
222
 
        const rec_t*            rec,    /* in: physical record in
223
 
                                        ROW_FORMAT=COMPACT */
224
 
        ulint                   extra,  /* in: number of bytes to reserve
225
 
                                        between the record header and
226
 
                                        the data payload
227
 
                                        (usually REC_N_NEW_EXTRA_BYTES) */
228
 
        const dict_index_t*     index,  /* in: record descriptor */
229
 
        ulint*                  offsets)/* in/out: array of offsets;
230
 
                                        in: n=rec_offs_n_fields(offsets) */
231
 
{
232
 
        ulint           i               = 0;
233
 
        ulint           offs            = 0;
234
 
        ulint           any_ext         = 0;
235
 
        const byte*     nulls           = rec - (extra + 1);
236
 
        const byte*     lens            = nulls
237
 
                - UT_BITS_IN_BYTES(index->n_nullable);
238
 
        dict_field_t*   field;
239
 
        ulint           null_mask       = 1;
240
 
 
241
 
#ifdef UNIV_DEBUG
242
 
        /* We cannot invoke rec_offs_make_valid() here, because it can hold
243
 
        that extra != REC_N_NEW_EXTRA_BYTES.  Similarly, rec_offs_validate()
244
 
        will fail in that case, because it invokes rec_get_status(). */
245
 
        offsets[2] = (ulint) rec;
246
 
        offsets[3] = (ulint) index;
247
 
#endif /* UNIV_DEBUG */
248
 
 
249
 
        /* read the lengths of fields 0..n */
250
 
        do {
251
 
                ulint   len;
252
 
 
253
 
                field = dict_index_get_nth_field(index, i);
254
 
                if (!(dict_field_get_col(field)->prtype
255
 
                      & DATA_NOT_NULL)) {
256
 
                        /* nullable field => read the null flag */
257
 
 
258
 
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
259
 
                                nulls--;
260
 
                                null_mask = 1;
261
 
                        }
262
 
 
263
 
                        if (*nulls & null_mask) {
264
 
                                null_mask <<= 1;
265
 
                                /* No length is stored for NULL fields.
266
 
                                We do not advance offs, and we set
267
 
                                the length to zero and enable the
268
 
                                SQL NULL flag in offsets[]. */
269
 
                                len = offs | REC_OFFS_SQL_NULL;
270
 
                                goto resolved;
271
 
                        }
272
 
                        null_mask <<= 1;
273
 
                }
274
 
 
275
 
                if (UNIV_UNLIKELY(!field->fixed_len)) {
276
 
                        /* Variable-length field: read the length */
277
 
                        const dict_col_t*       col
278
 
                                = dict_field_get_col(field);
279
 
                        len = *lens--;
280
 
                        if (UNIV_UNLIKELY(col->len > 255)
281
 
                            || UNIV_UNLIKELY(col->mtype
282
 
                                             == DATA_BLOB)) {
283
 
                                if (len & 0x80) {
284
 
                                        /* 1exxxxxxx xxxxxxxx */
285
 
                                        len <<= 8;
286
 
                                        len |= *lens--;
287
 
 
288
 
                                        offs += len & 0x3fff;
289
 
                                        if (UNIV_UNLIKELY(len
290
 
                                                          & 0x4000)) {
291
 
                                                ut_ad(dict_index_is_clust
292
 
                                                      (index));
293
 
                                                any_ext = REC_OFFS_EXTERNAL;
294
 
                                                len = offs
295
 
                                                        | REC_OFFS_EXTERNAL;
296
 
                                        } else {
297
 
                                                len = offs;
298
 
                                        }
299
 
 
300
 
                                        goto resolved;
301
 
                                }
302
 
                        }
303
 
 
304
 
                        len = offs += len;
305
 
                } else {
306
 
                        len = offs += field->fixed_len;
307
 
                }
308
 
resolved:
309
 
                rec_offs_base(offsets)[i + 1] = len;
310
 
        } while (++i < rec_offs_n_fields(offsets));
311
 
 
312
 
        *rec_offs_base(offsets)
313
 
                = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
314
 
}
315
 
 
316
 
/**********************************************************
317
 
The following function determines the offsets to each field in the
318
 
record.  The offsets are written to a previously allocated array of
319
 
ulint, where rec_offs_n_fields(offsets) has been initialized to the
320
 
number of fields in the record.  The rest of the array will be
321
 
initialized by this function.  rec_offs_base(offsets)[0] will be set
322
 
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
323
 
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
324
 
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
325
 
offsets past the end of fields 0..n_fields, or to the beginning of
326
 
fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
327
 
is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
328
 
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
329
 
field i is being stored externally. */
330
 
static
331
 
void
332
 
rec_init_offsets(
333
 
/*=============*/
334
 
        const rec_t*            rec,    /* in: physical record */
335
 
        const dict_index_t*     index,  /* in: record descriptor */
336
 
        ulint*                  offsets)/* in/out: array of offsets;
337
 
                                        in: n=rec_offs_n_fields(offsets) */
338
 
{
339
 
        ulint   i       = 0;
340
 
        ulint   offs;
341
 
 
342
 
        rec_offs_make_valid(rec, index, offsets);
343
 
 
344
 
        if (dict_table_is_comp(index->table)) {
345
 
                const byte*     nulls;
346
 
                const byte*     lens;
347
 
                dict_field_t*   field;
348
 
                ulint           null_mask;
349
 
                ulint           status = rec_get_status(rec);
350
 
                ulint           n_node_ptr_field = ULINT_UNDEFINED;
351
 
 
352
 
                switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
353
 
                case REC_STATUS_INFIMUM:
354
 
                case REC_STATUS_SUPREMUM:
355
 
                        /* the field is 8 bytes long */
356
 
                        rec_offs_base(offsets)[0]
357
 
                                = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
358
 
                        rec_offs_base(offsets)[1] = 8;
359
 
                        return;
360
 
                case REC_STATUS_NODE_PTR:
361
 
                        n_node_ptr_field
362
 
                                = dict_index_get_n_unique_in_tree(index);
363
 
                        break;
364
 
                case REC_STATUS_ORDINARY:
365
 
                        rec_init_offsets_comp_ordinary(rec,
366
 
                                                       REC_N_NEW_EXTRA_BYTES,
367
 
                                                       index, offsets);
368
 
                        return;
369
 
                }
370
 
 
371
 
                nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
372
 
                lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
373
 
                offs = 0;
374
 
                null_mask = 1;
375
 
 
376
 
                /* read the lengths of fields 0..n */
377
 
                do {
378
 
                        ulint   len;
379
 
                        if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
380
 
                                len = offs += 4;
381
 
                                goto resolved;
382
 
                        }
383
 
 
384
 
                        field = dict_index_get_nth_field(index, i);
385
 
                        if (!(dict_field_get_col(field)->prtype
386
 
                              & DATA_NOT_NULL)) {
387
 
                                /* nullable field => read the null flag */
388
 
 
389
 
                                if (UNIV_UNLIKELY(!(byte) null_mask)) {
390
 
                                        nulls--;
391
 
                                        null_mask = 1;
392
 
                                }
393
 
 
394
 
                                if (*nulls & null_mask) {
395
 
                                        null_mask <<= 1;
396
 
                                        /* No length is stored for NULL fields.
397
 
                                        We do not advance offs, and we set
398
 
                                        the length to zero and enable the
399
 
                                        SQL NULL flag in offsets[]. */
400
 
                                        len = offs | REC_OFFS_SQL_NULL;
401
 
                                        goto resolved;
402
 
                                }
403
 
                                null_mask <<= 1;
404
 
                        }
405
 
 
406
 
                        if (UNIV_UNLIKELY(!field->fixed_len)) {
407
 
                                /* Variable-length field: read the length */
408
 
                                const dict_col_t*       col
409
 
                                        = dict_field_get_col(field);
410
 
                                len = *lens--;
411
 
                                if (UNIV_UNLIKELY(col->len > 255)
412
 
                                    || UNIV_UNLIKELY(col->mtype
413
 
                                                     == DATA_BLOB)) {
414
 
                                        if (len & 0x80) {
415
 
                                                /* 1exxxxxxx xxxxxxxx */
416
 
 
417
 
                                                len <<= 8;
418
 
                                                len |= *lens--;
419
 
 
420
 
                                                /* B-tree node pointers
421
 
                                                must not contain externally
422
 
                                                stored columns.  Thus
423
 
                                                the "e" flag must be 0. */
424
 
                                                ut_a(!(len & 0x4000));
425
 
                                                offs += len & 0x3fff;
426
 
                                                len = offs;
427
 
 
428
 
                                                goto resolved;
429
 
                                        }
430
 
                                }
431
 
 
432
 
                                len = offs += len;
433
 
                        } else {
434
 
                                len = offs += field->fixed_len;
435
 
                        }
436
 
resolved:
437
 
                        rec_offs_base(offsets)[i + 1] = len;
438
 
                } while (++i < rec_offs_n_fields(offsets));
439
 
 
440
 
                *rec_offs_base(offsets)
441
 
                        = (rec - (lens + 1)) | REC_OFFS_COMPACT;
442
 
        } else {
443
 
                /* Old-style record: determine extra size and end offsets */
444
 
                offs = REC_N_OLD_EXTRA_BYTES;
445
 
                if (rec_get_1byte_offs_flag(rec)) {
446
 
                        offs += rec_offs_n_fields(offsets);
447
 
                        *rec_offs_base(offsets) = offs;
448
 
                        /* Determine offsets to fields */
449
 
                        do {
450
 
                                offs = rec_1_get_field_end_info(rec, i);
451
 
                                if (offs & REC_1BYTE_SQL_NULL_MASK) {
452
 
                                        offs &= ~REC_1BYTE_SQL_NULL_MASK;
453
 
                                        offs |= REC_OFFS_SQL_NULL;
454
 
                                }
455
 
                                rec_offs_base(offsets)[1 + i] = offs;
456
 
                        } while (++i < rec_offs_n_fields(offsets));
457
 
                } else {
458
 
                        offs += 2 * rec_offs_n_fields(offsets);
459
 
                        *rec_offs_base(offsets) = offs;
460
 
                        /* Determine offsets to fields */
461
 
                        do {
462
 
                                offs = rec_2_get_field_end_info(rec, i);
463
 
                                if (offs & REC_2BYTE_SQL_NULL_MASK) {
464
 
                                        offs &= ~REC_2BYTE_SQL_NULL_MASK;
465
 
                                        offs |= REC_OFFS_SQL_NULL;
466
 
                                }
467
 
                                if (offs & REC_2BYTE_EXTERN_MASK) {
468
 
                                        offs &= ~REC_2BYTE_EXTERN_MASK;
469
 
                                        offs |= REC_OFFS_EXTERNAL;
470
 
                                        *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
471
 
                                }
472
 
                                rec_offs_base(offsets)[1 + i] = offs;
473
 
                        } while (++i < rec_offs_n_fields(offsets));
474
 
                }
475
 
        }
476
 
}
477
 
 
478
 
/**********************************************************
479
 
The following function determines the offsets to each field
480
 
in the record.  It can reuse a previously returned array. */
481
 
UNIV_INTERN
482
 
ulint*
483
 
rec_get_offsets_func(
484
 
/*=================*/
485
 
                                        /* out: the new offsets */
486
 
        const rec_t*            rec,    /* in: physical record */
487
 
        const dict_index_t*     index,  /* in: record descriptor */
488
 
        ulint*                  offsets,/* in/out: array consisting of
489
 
                                        offsets[0] allocated elements,
490
 
                                        or an array from rec_get_offsets(),
491
 
                                        or NULL */
492
 
        ulint                   n_fields,/* in: maximum number of
493
 
                                        initialized fields
494
 
                                         (ULINT_UNDEFINED if all fields) */
495
 
        mem_heap_t**            heap,   /* in/out: memory heap */
496
 
        const char*             file,   /* in: file name where called */
497
 
        ulint                   line)   /* in: line number where called */
498
 
{
499
 
        ulint   n;
500
 
        ulint   size;
501
 
 
502
 
        ut_ad(rec);
503
 
        ut_ad(index);
504
 
        ut_ad(heap);
505
 
 
506
 
        if (dict_table_is_comp(index->table)) {
507
 
                switch (UNIV_EXPECT(rec_get_status(rec),
508
 
                                    REC_STATUS_ORDINARY)) {
509
 
                case REC_STATUS_ORDINARY:
510
 
                        n = dict_index_get_n_fields(index);
511
 
                        break;
512
 
                case REC_STATUS_NODE_PTR:
513
 
                        n = dict_index_get_n_unique_in_tree(index) + 1;
514
 
                        break;
515
 
                case REC_STATUS_INFIMUM:
516
 
                case REC_STATUS_SUPREMUM:
517
 
                        /* infimum or supremum record */
518
 
                        n = 1;
519
 
                        break;
520
 
                default:
521
 
                        ut_error;
522
 
                        return(NULL);
523
 
                }
524
 
        } else {
525
 
                n = rec_get_n_fields_old(rec);
526
 
        }
527
 
 
528
 
        if (UNIV_UNLIKELY(n_fields < n)) {
529
 
                n = n_fields;
530
 
        }
531
 
 
532
 
        size = n + (1 + REC_OFFS_HEADER_SIZE);
533
 
 
534
 
        if (UNIV_UNLIKELY(!offsets)
535
 
            || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
536
 
                if (UNIV_UNLIKELY(!*heap)) {
537
 
                        *heap = mem_heap_create_func(size * sizeof(ulint),
538
 
                                                     MEM_HEAP_DYNAMIC,
539
 
                                                     file, line);
540
 
                }
541
 
                offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
542
 
                rec_offs_set_n_alloc(offsets, size);
543
 
        }
544
 
 
545
 
        rec_offs_set_n_fields(offsets, n);
546
 
        rec_init_offsets(rec, index, offsets);
547
 
        return(offsets);
548
 
}
549
 
 
550
 
/**********************************************************
551
 
The following function determines the offsets to each field
552
 
in the record.  It can reuse a previously allocated array. */
553
 
UNIV_INTERN
554
 
void
555
 
rec_get_offsets_reverse(
556
 
/*====================*/
557
 
        const byte*             extra,  /* in: the extra bytes of a
558
 
                                        compact record in reverse order,
559
 
                                        excluding the fixed-size
560
 
                                        REC_N_NEW_EXTRA_BYTES */
561
 
        const dict_index_t*     index,  /* in: record descriptor */
562
 
        ulint                   node_ptr,/* in: nonzero=node pointer,
563
 
                                        0=leaf node */
564
 
        ulint*                  offsets)/* in/out: array consisting of
565
 
                                        offsets[0] allocated elements */
566
 
{
567
 
        ulint           n;
568
 
        ulint           i;
569
 
        ulint           offs;
570
 
        ulint           any_ext;
571
 
        const byte*     nulls;
572
 
        const byte*     lens;
573
 
        dict_field_t*   field;
574
 
        ulint           null_mask;
575
 
        ulint           n_node_ptr_field;
576
 
 
577
 
        ut_ad(extra);
578
 
        ut_ad(index);
579
 
        ut_ad(offsets);
580
 
        ut_ad(dict_table_is_comp(index->table));
581
 
 
582
 
        if (UNIV_UNLIKELY(node_ptr)) {
583
 
                n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
584
 
                n = n_node_ptr_field + 1;
585
 
        } else {
586
 
                n_node_ptr_field = ULINT_UNDEFINED;
587
 
                n = dict_index_get_n_fields(index);
588
 
        }
589
 
 
590
 
        ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
591
 
        rec_offs_set_n_fields(offsets, n);
592
 
 
593
 
        nulls = extra;
594
 
        lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
595
 
        i = offs = 0;
596
 
        null_mask = 1;
597
 
        any_ext = 0;
598
 
 
599
 
        /* read the lengths of fields 0..n */
600
 
        do {
601
 
                ulint   len;
602
 
                if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
603
 
                        len = offs += 4;
604
 
                        goto resolved;
605
 
                }
606
 
 
607
 
                field = dict_index_get_nth_field(index, i);
608
 
                if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
609
 
                        /* nullable field => read the null flag */
610
 
 
611
 
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
612
 
                                nulls++;
613
 
                                null_mask = 1;
614
 
                        }
615
 
 
616
 
                        if (*nulls & null_mask) {
617
 
                                null_mask <<= 1;
618
 
                                /* No length is stored for NULL fields.
619
 
                                We do not advance offs, and we set
620
 
                                the length to zero and enable the
621
 
                                SQL NULL flag in offsets[]. */
622
 
                                len = offs | REC_OFFS_SQL_NULL;
623
 
                                goto resolved;
624
 
                        }
625
 
                        null_mask <<= 1;
626
 
                }
627
 
 
628
 
                if (UNIV_UNLIKELY(!field->fixed_len)) {
629
 
                        /* Variable-length field: read the length */
630
 
                        const dict_col_t*       col
631
 
                                = dict_field_get_col(field);
632
 
                        len = *lens++;
633
 
                        if (UNIV_UNLIKELY(col->len > 255)
634
 
                            || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
635
 
                                if (len & 0x80) {
636
 
                                        /* 1exxxxxxx xxxxxxxx */
637
 
                                        len <<= 8;
638
 
                                        len |= *lens++;
639
 
 
640
 
                                        offs += len & 0x3fff;
641
 
                                        if (UNIV_UNLIKELY(len & 0x4000)) {
642
 
                                                any_ext = REC_OFFS_EXTERNAL;
643
 
                                                len = offs | REC_OFFS_EXTERNAL;
644
 
                                        } else {
645
 
                                                len = offs;
646
 
                                        }
647
 
 
648
 
                                        goto resolved;
649
 
                                }
650
 
                        }
651
 
 
652
 
                        len = offs += len;
653
 
                } else {
654
 
                        len = offs += field->fixed_len;
655
 
                }
656
 
resolved:
657
 
                rec_offs_base(offsets)[i + 1] = len;
658
 
        } while (++i < rec_offs_n_fields(offsets));
659
 
 
660
 
        ut_ad(lens >= extra);
661
 
        *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
662
 
                | REC_OFFS_COMPACT | any_ext;
663
 
}
664
 
 
665
 
/****************************************************************
666
 
The following function is used to get the offset to the nth
667
 
data field in an old-style record. */
668
 
UNIV_INTERN
669
 
ulint
670
 
rec_get_nth_field_offs_old(
671
 
/*=======================*/
672
 
                                /* out: offset to the field */
673
 
        const rec_t*    rec,    /* in: record */
674
 
        ulint           n,      /* in: index of the field */
675
 
        ulint*          len)    /* out: length of the field;
676
 
                                UNIV_SQL_NULL if SQL null */
677
 
{
678
 
        ulint   os;
679
 
        ulint   next_os;
680
 
 
681
 
        ut_ad(rec && len);
682
 
        ut_ad(n < rec_get_n_fields_old(rec));
683
 
 
684
 
        if (n > REC_MAX_N_FIELDS) {
685
 
                fprintf(stderr, "Error: trying to access field %lu in rec\n",
686
 
                        (ulong) n);
687
 
                ut_error;
688
 
        }
689
 
 
690
 
        if (rec == NULL) {
691
 
                fputs("Error: rec is NULL pointer\n", stderr);
692
 
                ut_error;
693
 
        }
694
 
 
695
 
        if (rec_get_1byte_offs_flag(rec)) {
696
 
                os = rec_1_get_field_start_offs(rec, n);
697
 
 
698
 
                next_os = rec_1_get_field_end_info(rec, n);
699
 
 
700
 
                if (next_os & REC_1BYTE_SQL_NULL_MASK) {
701
 
                        *len = UNIV_SQL_NULL;
702
 
 
703
 
                        return(os);
704
 
                }
705
 
 
706
 
                next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
707
 
        } else {
708
 
                os = rec_2_get_field_start_offs(rec, n);
709
 
 
710
 
                next_os = rec_2_get_field_end_info(rec, n);
711
 
 
712
 
                if (next_os & REC_2BYTE_SQL_NULL_MASK) {
713
 
                        *len = UNIV_SQL_NULL;
714
 
 
715
 
                        return(os);
716
 
                }
717
 
 
718
 
                next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
719
 
                                      | REC_2BYTE_EXTERN_MASK);
720
 
        }
721
 
 
722
 
        *len = next_os - os;
723
 
 
724
 
        ut_ad(*len < UNIV_PAGE_SIZE);
725
 
 
726
 
        return(os);
727
 
}
728
 
 
729
 
/**************************************************************
730
 
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT. */
731
 
UNIV_INTERN
732
 
ulint
733
 
rec_get_converted_size_comp_prefix(
734
 
/*===============================*/
735
 
                                        /* out: total size */
736
 
        const dict_index_t*     index,  /* in: record descriptor;
737
 
                                        dict_table_is_comp() is
738
 
                                        assumed to hold, even if
739
 
                                        it does not */
740
 
        const dfield_t*         fields, /* in: array of data fields */
741
 
        ulint                   n_fields,/* in: number of data fields */
742
 
        ulint*                  extra)  /* out: extra size */
743
 
{
744
 
        ulint   extra_size;
745
 
        ulint   data_size;
746
 
        ulint   i;
747
 
        ut_ad(index);
748
 
        ut_ad(fields);
749
 
        ut_ad(n_fields > 0);
750
 
        ut_ad(n_fields <= dict_index_get_n_fields(index));
751
 
 
752
 
        extra_size = REC_N_NEW_EXTRA_BYTES
753
 
                + UT_BITS_IN_BYTES(index->n_nullable);
754
 
        data_size = 0;
755
 
 
756
 
        /* read the lengths of fields 0..n */
757
 
        for (i = 0; i < n_fields; i++) {
758
 
                const dict_field_t*     field;
759
 
                ulint                   len;
760
 
                const dict_col_t*       col;
761
 
 
762
 
                field = dict_index_get_nth_field(index, i);
763
 
                len = dfield_get_len(&fields[i]);
764
 
                col = dict_field_get_col(field);
765
 
 
766
 
                ut_ad(dict_col_type_assert_equal(col,
767
 
                                                 dfield_get_type(&fields[i])));
768
 
 
769
 
                if (dfield_is_null(&fields[i])) {
770
 
                        /* No length is stored for NULL fields. */
771
 
                        ut_ad(!(col->prtype & DATA_NOT_NULL));
772
 
                        continue;
773
 
                }
774
 
 
775
 
                ut_ad(len <= col->len || col->mtype == DATA_BLOB);
776
 
 
777
 
                if (field->fixed_len) {
778
 
                        ut_ad(len == field->fixed_len);
779
 
                        /* dict_index_add_col() should guarantee this */
780
 
                        ut_ad(!field->prefix_len
781
 
                              || field->fixed_len == field->prefix_len);
782
 
                } else if (dfield_is_ext(&fields[i])) {
783
 
                        extra_size += 2;
784
 
                } else if (len < 128
785
 
                           || (col->len < 256 && col->mtype != DATA_BLOB)) {
786
 
                        extra_size++;
787
 
                } else {
788
 
                        /* For variable-length columns, we look up the
789
 
                        maximum length from the column itself.  If this
790
 
                        is a prefix index column shorter than 256 bytes,
791
 
                        this will waste one byte. */
792
 
                        extra_size += 2;
793
 
                }
794
 
                data_size += len;
795
 
        }
796
 
 
797
 
        if (UNIV_LIKELY_NULL(extra)) {
798
 
                *extra = extra_size;
799
 
        }
800
 
 
801
 
        return(extra_size + data_size);
802
 
}
803
 
 
804
 
/**************************************************************
805
 
Determines the size of a data tuple in ROW_FORMAT=COMPACT. */
806
 
UNIV_INTERN
807
 
ulint
808
 
rec_get_converted_size_comp(
809
 
/*========================*/
810
 
                                        /* out: total size */
811
 
        const dict_index_t*     index,  /* in: record descriptor;
812
 
                                        dict_table_is_comp() is
813
 
                                        assumed to hold, even if
814
 
                                        it does not */
815
 
        ulint                   status, /* in: status bits of the record */
816
 
        const dfield_t*         fields, /* in: array of data fields */
817
 
        ulint                   n_fields,/* in: number of data fields */
818
 
        ulint*                  extra)  /* out: extra size */
819
 
{
820
 
        ulint   size;
821
 
        ut_ad(index);
822
 
        ut_ad(fields);
823
 
        ut_ad(n_fields > 0);
824
 
 
825
 
        switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
826
 
        case REC_STATUS_ORDINARY:
827
 
                ut_ad(n_fields == dict_index_get_n_fields(index));
828
 
                size = 0;
829
 
                break;
830
 
        case REC_STATUS_NODE_PTR:
831
 
                n_fields--;
832
 
                ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
833
 
                ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
834
 
                size = REC_NODE_PTR_SIZE; /* child page number */
835
 
                break;
836
 
        case REC_STATUS_INFIMUM:
837
 
        case REC_STATUS_SUPREMUM:
838
 
                /* infimum or supremum record, 8 data bytes */
839
 
                if (UNIV_LIKELY_NULL(extra)) {
840
 
                        *extra = REC_N_NEW_EXTRA_BYTES;
841
 
                }
842
 
                return(REC_N_NEW_EXTRA_BYTES + 8);
843
 
        default:
844
 
                ut_error;
845
 
                return(ULINT_UNDEFINED);
846
 
        }
847
 
 
848
 
        return(size + rec_get_converted_size_comp_prefix(index, fields,
849
 
                                                         n_fields, extra));
850
 
}
851
 
 
852
 
/***************************************************************
853
 
Sets the value of the ith field SQL null bit of an old-style record. */
854
 
UNIV_INTERN
855
 
void
856
 
rec_set_nth_field_null_bit(
857
 
/*=======================*/
858
 
        rec_t*  rec,    /* in: record */
859
 
        ulint   i,      /* in: ith field */
860
 
        ibool   val)    /* in: value to set */
861
 
{
862
 
        ulint   info;
863
 
 
864
 
        if (rec_get_1byte_offs_flag(rec)) {
865
 
 
866
 
                info = rec_1_get_field_end_info(rec, i);
867
 
 
868
 
                if (val) {
869
 
                        info = info | REC_1BYTE_SQL_NULL_MASK;
870
 
                } else {
871
 
                        info = info & ~REC_1BYTE_SQL_NULL_MASK;
872
 
                }
873
 
 
874
 
                rec_1_set_field_end_info(rec, i, info);
875
 
 
876
 
                return;
877
 
        }
878
 
 
879
 
        info = rec_2_get_field_end_info(rec, i);
880
 
 
881
 
        if (val) {
882
 
                info = info | REC_2BYTE_SQL_NULL_MASK;
883
 
        } else {
884
 
                info = info & ~REC_2BYTE_SQL_NULL_MASK;
885
 
        }
886
 
 
887
 
        rec_2_set_field_end_info(rec, i, info);
888
 
}
889
 
 
890
 
/***************************************************************
891
 
Sets an old-style record field to SQL null.
892
 
The physical size of the field is not changed. */
893
 
UNIV_INTERN
894
 
void
895
 
rec_set_nth_field_sql_null(
896
 
/*=======================*/
897
 
        rec_t*  rec,    /* in: record */
898
 
        ulint   n)      /* in: index of the field */
899
 
{
900
 
        ulint   offset;
901
 
 
902
 
        offset = rec_get_field_start_offs(rec, n);
903
 
 
904
 
        data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
905
 
 
906
 
        rec_set_nth_field_null_bit(rec, n, TRUE);
907
 
}
908
 
 
909
 
/*************************************************************
910
 
Builds an old-style physical record out of a data tuple and
911
 
stores it beginning from the start of the given buffer. */
912
 
static
913
 
rec_t*
914
 
rec_convert_dtuple_to_rec_old(
915
 
/*==========================*/
916
 
                                /* out: pointer to the origin of
917
 
                                physical record */
918
 
        byte*           buf,    /* in: start address of the physical record */
919
 
        const dtuple_t* dtuple, /* in: data tuple */
920
 
        ulint           n_ext)  /* in: number of externally stored columns */
921
 
{
922
 
        const dfield_t* field;
923
 
        ulint           n_fields;
924
 
        ulint           data_size;
925
 
        rec_t*          rec;
926
 
        ulint           end_offset;
927
 
        ulint           ored_offset;
928
 
        ulint           len;
929
 
        ulint           i;
930
 
 
931
 
        ut_ad(buf && dtuple);
932
 
        ut_ad(dtuple_validate(dtuple));
933
 
        ut_ad(dtuple_check_typed(dtuple));
934
 
 
935
 
        n_fields = dtuple_get_n_fields(dtuple);
936
 
        data_size = dtuple_get_data_size(dtuple);
937
 
 
938
 
        ut_ad(n_fields > 0);
939
 
 
940
 
        /* Calculate the offset of the origin in the physical record */
941
 
 
942
 
        rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
943
 
#ifdef UNIV_DEBUG
944
 
        /* Suppress Valgrind warnings of ut_ad()
945
 
        in mach_write_to_1(), mach_write_to_2() et al. */
946
 
        memset(buf, 0xff, rec - buf + data_size);
947
 
#endif /* UNIV_DEBUG */
948
 
        /* Store the number of fields */
949
 
        rec_set_n_fields_old(rec, n_fields);
950
 
 
951
 
        /* Set the info bits of the record */
952
 
        rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
953
 
                              & REC_INFO_BITS_MASK);
954
 
 
955
 
        /* Store the data and the offsets */
956
 
 
957
 
        end_offset = 0;
958
 
 
959
 
        if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
960
 
 
961
 
                rec_set_1byte_offs_flag(rec, TRUE);
962
 
 
963
 
                for (i = 0; i < n_fields; i++) {
964
 
 
965
 
                        field = dtuple_get_nth_field(dtuple, i);
966
 
 
967
 
                        if (dfield_is_null(field)) {
968
 
                                len = dtype_get_sql_null_size(
969
 
                                        dfield_get_type(field));
970
 
                                data_write_sql_null(rec + end_offset, len);
971
 
 
972
 
                                end_offset += len;
973
 
                                ored_offset = end_offset
974
 
                                        | REC_1BYTE_SQL_NULL_MASK;
975
 
                        } else {
976
 
                                /* If the data is not SQL null, store it */
977
 
                                len = dfield_get_len(field);
978
 
 
979
 
                                memcpy(rec + end_offset,
980
 
                                       dfield_get_data(field), len);
981
 
 
982
 
                                end_offset += len;
983
 
                                ored_offset = end_offset;
984
 
                        }
985
 
 
986
 
                        rec_1_set_field_end_info(rec, i, ored_offset);
987
 
                }
988
 
        } else {
989
 
                rec_set_1byte_offs_flag(rec, FALSE);
990
 
 
991
 
                for (i = 0; i < n_fields; i++) {
992
 
 
993
 
                        field = dtuple_get_nth_field(dtuple, i);
994
 
 
995
 
                        if (dfield_is_null(field)) {
996
 
                                len = dtype_get_sql_null_size(
997
 
                                        dfield_get_type(field));
998
 
                                data_write_sql_null(rec + end_offset, len);
999
 
 
1000
 
                                end_offset += len;
1001
 
                                ored_offset = end_offset
1002
 
                                        | REC_2BYTE_SQL_NULL_MASK;
1003
 
                        } else {
1004
 
                                /* If the data is not SQL null, store it */
1005
 
                                len = dfield_get_len(field);
1006
 
 
1007
 
                                memcpy(rec + end_offset,
1008
 
                                       dfield_get_data(field), len);
1009
 
 
1010
 
                                end_offset += len;
1011
 
                                ored_offset = end_offset;
1012
 
 
1013
 
                                if (dfield_is_ext(field)) {
1014
 
                                        ored_offset |= REC_2BYTE_EXTERN_MASK;
1015
 
                                }
1016
 
                        }
1017
 
 
1018
 
                        rec_2_set_field_end_info(rec, i, ored_offset);
1019
 
                }
1020
 
        }
1021
 
 
1022
 
        return(rec);
1023
 
}
1024
 
 
1025
 
/*************************************************************
1026
 
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1027
 
UNIV_INTERN
1028
 
void
1029
 
rec_convert_dtuple_to_rec_comp(
1030
 
/*===========================*/
1031
 
        rec_t*                  rec,    /* in: origin of record */
1032
 
        ulint                   extra,  /* in: number of bytes to
1033
 
                                        reserve between the record
1034
 
                                        header and the data payload
1035
 
                                        (normally REC_N_NEW_EXTRA_BYTES) */
1036
 
        const dict_index_t*     index,  /* in: record descriptor */
1037
 
        ulint                   status, /* in: status bits of the record */
1038
 
        const dfield_t*         fields, /* in: array of data fields */
1039
 
        ulint                   n_fields)/* in: number of data fields */
1040
 
{
1041
 
        const dfield_t* field;
1042
 
        const dtype_t*  type;
1043
 
        byte*           end;
1044
 
        byte*           nulls;
1045
 
        byte*           lens;
1046
 
        ulint           len;
1047
 
        ulint           i;
1048
 
        ulint           n_node_ptr_field;
1049
 
        ulint           fixed_len;
1050
 
        ulint           null_mask       = 1;
1051
 
        ut_ad(extra == 0 || dict_table_is_comp(index->table));
1052
 
        ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
1053
 
        ut_ad(n_fields > 0);
1054
 
 
1055
 
        switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1056
 
        case REC_STATUS_ORDINARY:
1057
 
                ut_ad(n_fields <= dict_index_get_n_fields(index));
1058
 
                n_node_ptr_field = ULINT_UNDEFINED;
1059
 
                break;
1060
 
        case REC_STATUS_NODE_PTR:
1061
 
                ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1062
 
                n_node_ptr_field = n_fields - 1;
1063
 
                break;
1064
 
        case REC_STATUS_INFIMUM:
1065
 
        case REC_STATUS_SUPREMUM:
1066
 
                ut_ad(n_fields == 1);
1067
 
                n_node_ptr_field = ULINT_UNDEFINED;
1068
 
                break;
1069
 
        default:
1070
 
                ut_error;
1071
 
                return;
1072
 
        }
1073
 
 
1074
 
        end = rec;
1075
 
        nulls = rec - (extra + 1);
1076
 
        lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1077
 
        /* clear the SQL-null flags */
1078
 
        memset(lens + 1, 0, nulls - lens);
1079
 
 
1080
 
        /* Store the data and the offsets */
1081
 
 
1082
 
        for (i = 0, field = fields; i < n_fields; i++, field++) {
1083
 
                type = dfield_get_type(field);
1084
 
                len = dfield_get_len(field);
1085
 
 
1086
 
                if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1087
 
                        ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1088
 
                        ut_ad(len == 4);
1089
 
                        memcpy(end, dfield_get_data(field), len);
1090
 
                        end += 4;
1091
 
                        break;
1092
 
                }
1093
 
 
1094
 
                if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1095
 
                        /* nullable field */
1096
 
                        ut_ad(index->n_nullable > 0);
1097
 
 
1098
 
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
1099
 
                                nulls--;
1100
 
                                null_mask = 1;
1101
 
                        }
1102
 
 
1103
 
                        ut_ad(*nulls < null_mask);
1104
 
 
1105
 
                        /* set the null flag if necessary */
1106
 
                        if (dfield_is_null(field)) {
1107
 
                                *nulls |= null_mask;
1108
 
                                null_mask <<= 1;
1109
 
                                continue;
1110
 
                        }
1111
 
 
1112
 
                        null_mask <<= 1;
1113
 
                }
1114
 
                /* only nullable fields can be null */
1115
 
                ut_ad(!dfield_is_null(field));
1116
 
 
1117
 
                fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
1118
 
 
1119
 
                if (fixed_len) {
1120
 
                        ut_ad(len == fixed_len);
1121
 
                        ut_ad(!dfield_is_ext(field));
1122
 
                } else if (dfield_is_ext(field)) {
1123
 
                        ut_ad(len <= REC_MAX_INDEX_COL_LEN
1124
 
                              + BTR_EXTERN_FIELD_REF_SIZE);
1125
 
                        *lens-- = (byte) (len >> 8) | 0xc0;
1126
 
                        *lens-- = (byte) len;
1127
 
                } else {
1128
 
                        ut_ad(len <= dtype_get_len(type)
1129
 
                              || dtype_get_mtype(type) == DATA_BLOB);
1130
 
                        if (len < 128
1131
 
                            || (dtype_get_len(type) < 256
1132
 
                                && dtype_get_mtype(type) != DATA_BLOB)) {
1133
 
 
1134
 
                                *lens-- = (byte) len;
1135
 
                        } else {
1136
 
                                ut_ad(len < 16384);
1137
 
                                *lens-- = (byte) (len >> 8) | 0x80;
1138
 
                                *lens-- = (byte) len;
1139
 
                        }
1140
 
                }
1141
 
 
1142
 
                memcpy(end, dfield_get_data(field), len);
1143
 
                end += len;
1144
 
        }
1145
 
}
1146
 
 
1147
 
/*************************************************************
1148
 
Builds a new-style physical record out of a data tuple and
1149
 
stores it beginning from the start of the given buffer. */
1150
 
static
1151
 
rec_t*
1152
 
rec_convert_dtuple_to_rec_new(
1153
 
/*==========================*/
1154
 
                                        /* out: pointer to the origin
1155
 
                                        of physical record */
1156
 
        byte*                   buf,    /* in: start address of
1157
 
                                        the physical record */
1158
 
        const dict_index_t*     index,  /* in: record descriptor */
1159
 
        const dtuple_t*         dtuple) /* in: data tuple */
1160
 
{
1161
 
        ulint   extra_size;
1162
 
        ulint   status;
1163
 
        rec_t*  rec;
1164
 
 
1165
 
        status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1166
 
        rec_get_converted_size_comp(index, status,
1167
 
                                    dtuple->fields, dtuple->n_fields,
1168
 
                                    &extra_size);
1169
 
        rec = buf + extra_size;
1170
 
 
1171
 
        rec_convert_dtuple_to_rec_comp(
1172
 
                rec, REC_N_NEW_EXTRA_BYTES, index, status,
1173
 
                dtuple->fields, dtuple->n_fields);
1174
 
 
1175
 
        /* Set the info bits of the record */
1176
 
        rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1177
 
 
1178
 
        return(rec);
1179
 
}
1180
 
 
1181
 
/*************************************************************
1182
 
Builds a physical record out of a data tuple and
1183
 
stores it beginning from the start of the given buffer. */
1184
 
UNIV_INTERN
1185
 
rec_t*
1186
 
rec_convert_dtuple_to_rec(
1187
 
/*======================*/
1188
 
                                        /* out: pointer to the origin
1189
 
                                        of physical record */
1190
 
        byte*                   buf,    /* in: start address of the
1191
 
                                        physical record */
1192
 
        const dict_index_t*     index,  /* in: record descriptor */
1193
 
        const dtuple_t*         dtuple, /* in: data tuple */
1194
 
        ulint                   n_ext)  /* in: number of
1195
 
                                        externally stored columns */
1196
 
{
1197
 
        rec_t*  rec;
1198
 
 
1199
 
        ut_ad(buf && index && dtuple);
1200
 
        ut_ad(dtuple_validate(dtuple));
1201
 
        ut_ad(dtuple_check_typed(dtuple));
1202
 
 
1203
 
        if (dict_table_is_comp(index->table)) {
1204
 
                rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1205
 
        } else {
1206
 
                rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1207
 
        }
1208
 
 
1209
 
#ifdef UNIV_DEBUG
1210
 
        {
1211
 
                mem_heap_t*     heap    = NULL;
1212
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1213
 
                const ulint*    offsets;
1214
 
                rec_offs_init(offsets_);
1215
 
 
1216
 
                offsets = rec_get_offsets(rec, index,
1217
 
                                          offsets_, ULINT_UNDEFINED, &heap);
1218
 
                ut_ad(rec_validate(rec, offsets));
1219
 
                if (UNIV_LIKELY_NULL(heap)) {
1220
 
                        mem_heap_free(heap);
1221
 
                }
1222
 
        }
1223
 
#endif /* UNIV_DEBUG */
1224
 
        return(rec);
1225
 
}
1226
 
 
1227
 
/******************************************************************
1228
 
Copies the first n fields of a physical record to a data tuple. The fields
1229
 
are copied to the memory heap. */
1230
 
UNIV_INTERN
1231
 
void
1232
 
rec_copy_prefix_to_dtuple(
1233
 
/*======================*/
1234
 
        dtuple_t*               tuple,          /* out: data tuple */
1235
 
        const rec_t*            rec,            /* in: physical record */
1236
 
        const dict_index_t*     index,          /* in: record descriptor */
1237
 
        ulint                   n_fields,       /* in: number of fields
1238
 
                                                to copy */
1239
 
        mem_heap_t*             heap)           /* in: memory heap */
1240
 
{
1241
 
        ulint   i;
1242
 
        ulint   offsets_[REC_OFFS_NORMAL_SIZE];
1243
 
        ulint*  offsets = offsets_;
1244
 
        rec_offs_init(offsets_);
1245
 
 
1246
 
        offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1247
 
 
1248
 
        ut_ad(rec_validate(rec, offsets));
1249
 
        ut_ad(dtuple_check_typed(tuple));
1250
 
 
1251
 
        dtuple_set_info_bits(tuple, rec_get_info_bits(
1252
 
                                     rec, dict_table_is_comp(index->table)));
1253
 
 
1254
 
        for (i = 0; i < n_fields; i++) {
1255
 
                dfield_t*       field;
1256
 
                const byte*     data;
1257
 
                ulint           len;
1258
 
 
1259
 
                field = dtuple_get_nth_field(tuple, i);
1260
 
                data = rec_get_nth_field(rec, offsets, i, &len);
1261
 
 
1262
 
                if (len != UNIV_SQL_NULL) {
1263
 
                        dfield_set_data(field,
1264
 
                                        mem_heap_dup(heap, data, len), len);
1265
 
                        ut_ad(!rec_offs_nth_extern(offsets, i));
1266
 
                } else {
1267
 
                        dfield_set_null(field);
1268
 
                }
1269
 
        }
1270
 
}
1271
 
 
1272
 
/******************************************************************
1273
 
Copies the first n fields of an old-style physical record
1274
 
to a new physical record in a buffer. */
1275
 
static
1276
 
rec_t*
1277
 
rec_copy_prefix_to_buf_old(
1278
 
/*=======================*/
1279
 
                                        /* out, own: copied record */
1280
 
        const rec_t*    rec,            /* in: physical record */
1281
 
        ulint           n_fields,       /* in: number of fields to copy */
1282
 
        ulint           area_end,       /* in: end of the prefix data */
1283
 
        byte**          buf,            /* in/out: memory buffer for
1284
 
                                        the copied prefix, or NULL */
1285
 
        ulint*          buf_size)       /* in/out: buffer size */
1286
 
{
1287
 
        rec_t*  copy_rec;
1288
 
        ulint   area_start;
1289
 
        ulint   prefix_len;
1290
 
 
1291
 
        if (rec_get_1byte_offs_flag(rec)) {
1292
 
                area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1293
 
        } else {
1294
 
                area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1295
 
        }
1296
 
 
1297
 
        prefix_len = area_start + area_end;
1298
 
 
1299
 
        if ((*buf == NULL) || (*buf_size < prefix_len)) {
1300
 
                if (*buf != NULL) {
1301
 
                        mem_free(*buf);
1302
 
                }
1303
 
 
1304
 
                *buf = mem_alloc2(prefix_len, buf_size);
1305
 
        }
1306
 
 
1307
 
        ut_memcpy(*buf, rec - area_start, prefix_len);
1308
 
 
1309
 
        copy_rec = *buf + area_start;
1310
 
 
1311
 
        rec_set_n_fields_old(copy_rec, n_fields);
1312
 
 
1313
 
        return(copy_rec);
1314
 
}
1315
 
 
1316
 
/******************************************************************
1317
 
Copies the first n fields of a physical record to a new physical record in
1318
 
a buffer. */
1319
 
UNIV_INTERN
1320
 
rec_t*
1321
 
rec_copy_prefix_to_buf(
1322
 
/*===================*/
1323
 
                                                /* out, own: copied record */
1324
 
        const rec_t*            rec,            /* in: physical record */
1325
 
        const dict_index_t*     index,          /* in: record descriptor */
1326
 
        ulint                   n_fields,       /* in: number of fields
1327
 
                                                to copy */
1328
 
        byte**                  buf,            /* in/out: memory buffer
1329
 
                                                for the copied prefix,
1330
 
                                                or NULL */
1331
 
        ulint*                  buf_size)       /* in/out: buffer size */
1332
 
{
1333
 
        const byte*     nulls;
1334
 
        const byte*     lens;
1335
 
        ulint           i;
1336
 
        ulint           prefix_len;
1337
 
        ulint           null_mask;
1338
 
        ulint           status;
1339
 
 
1340
 
        UNIV_PREFETCH_RW(*buf);
1341
 
 
1342
 
        if (!dict_table_is_comp(index->table)) {
1343
 
                ut_ad(rec_validate_old(rec));
1344
 
                return(rec_copy_prefix_to_buf_old(
1345
 
                               rec, n_fields,
1346
 
                               rec_get_field_start_offs(rec, n_fields),
1347
 
                               buf, buf_size));
1348
 
        }
1349
 
 
1350
 
        status = rec_get_status(rec);
1351
 
 
1352
 
        switch (status) {
1353
 
        case REC_STATUS_ORDINARY:
1354
 
                ut_ad(n_fields <= dict_index_get_n_fields(index));
1355
 
                break;
1356
 
        case REC_STATUS_NODE_PTR:
1357
 
                /* it doesn't make sense to copy the child page number field */
1358
 
                ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1359
 
                break;
1360
 
        case REC_STATUS_INFIMUM:
1361
 
        case REC_STATUS_SUPREMUM:
1362
 
                /* infimum or supremum record: no sense to copy anything */
1363
 
        default:
1364
 
                ut_error;
1365
 
                return(NULL);
1366
 
        }
1367
 
 
1368
 
        nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1369
 
        lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1370
 
        UNIV_PREFETCH_R(lens);
1371
 
        prefix_len = 0;
1372
 
        null_mask = 1;
1373
 
 
1374
 
        /* read the lengths of fields 0..n */
1375
 
        for (i = 0; i < n_fields; i++) {
1376
 
                const dict_field_t*     field;
1377
 
                const dict_col_t*       col;
1378
 
 
1379
 
                field = dict_index_get_nth_field(index, i);
1380
 
                col = dict_field_get_col(field);
1381
 
 
1382
 
                if (!(col->prtype & DATA_NOT_NULL)) {
1383
 
                        /* nullable field => read the null flag */
1384
 
                        if (UNIV_UNLIKELY(!(byte) null_mask)) {
1385
 
                                nulls--;
1386
 
                                null_mask = 1;
1387
 
                        }
1388
 
 
1389
 
                        if (*nulls & null_mask) {
1390
 
                                null_mask <<= 1;
1391
 
                                continue;
1392
 
                        }
1393
 
 
1394
 
                        null_mask <<= 1;
1395
 
                }
1396
 
 
1397
 
                if (field->fixed_len) {
1398
 
                        prefix_len += field->fixed_len;
1399
 
                } else {
1400
 
                        ulint   len = *lens--;
1401
 
                        if (col->len > 255 || col->mtype == DATA_BLOB) {
1402
 
                                if (len & 0x80) {
1403
 
                                        /* 1exxxxxx */
1404
 
                                        len &= 0x3f;
1405
 
                                        len <<= 8;
1406
 
                                        len |= *lens--;
1407
 
                                        UNIV_PREFETCH_R(lens);
1408
 
                                }
1409
 
                        }
1410
 
                        prefix_len += len;
1411
 
                }
1412
 
        }
1413
 
 
1414
 
        UNIV_PREFETCH_R(rec + prefix_len);
1415
 
 
1416
 
        prefix_len += rec - (lens + 1);
1417
 
 
1418
 
        if ((*buf == NULL) || (*buf_size < prefix_len)) {
1419
 
                if (*buf != NULL) {
1420
 
                        mem_free(*buf);
1421
 
                }
1422
 
 
1423
 
                *buf = mem_alloc2(prefix_len, buf_size);
1424
 
        }
1425
 
 
1426
 
        memcpy(*buf, lens + 1, prefix_len);
1427
 
 
1428
 
        return(*buf + (rec - (lens + 1)));
1429
 
}
1430
 
 
1431
 
/*******************************************************************
1432
 
Validates the consistency of an old-style physical record. */
1433
 
static
1434
 
ibool
1435
 
rec_validate_old(
1436
 
/*=============*/
1437
 
                                /* out: TRUE if ok */
1438
 
        const rec_t*    rec)    /* in: physical record */
1439
 
{
1440
 
        const byte*     data;
1441
 
        ulint           len;
1442
 
        ulint           n_fields;
1443
 
        ulint           len_sum         = 0;
1444
 
        ulint           sum             = 0;
1445
 
        ulint           i;
1446
 
 
1447
 
        ut_a(rec);
1448
 
        n_fields = rec_get_n_fields_old(rec);
1449
 
 
1450
 
        if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1451
 
                fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1452
 
                        (ulong) n_fields);
1453
 
                return(FALSE);
1454
 
        }
1455
 
 
1456
 
        for (i = 0; i < n_fields; i++) {
1457
 
                data = rec_get_nth_field_old(rec, i, &len);
1458
 
 
1459
 
                if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1460
 
                        fprintf(stderr,
1461
 
                                "InnoDB: Error: record field %lu len %lu\n",
1462
 
                                (ulong) i,
1463
 
                                (ulong) len);
1464
 
                        return(FALSE);
1465
 
                }
1466
 
 
1467
 
                if (len != UNIV_SQL_NULL) {
1468
 
                        len_sum += len;
1469
 
                        sum += *(data + len -1); /* dereference the
1470
 
                                                 end of the field to
1471
 
                                                 cause a memory trap
1472
 
                                                 if possible */
1473
 
                } else {
1474
 
                        len_sum += rec_get_nth_field_size(rec, i);
1475
 
                }
1476
 
        }
1477
 
 
1478
 
        if (len_sum != rec_get_data_size_old(rec)) {
1479
 
                fprintf(stderr,
1480
 
                        "InnoDB: Error: record len should be %lu, len %lu\n",
1481
 
                        (ulong) len_sum,
1482
 
                        rec_get_data_size_old(rec));
1483
 
                return(FALSE);
1484
 
        }
1485
 
 
1486
 
        rec_dummy = sum; /* This is here only to fool the compiler */
1487
 
 
1488
 
        return(TRUE);
1489
 
}
1490
 
 
1491
 
/*******************************************************************
1492
 
Validates the consistency of a physical record. */
1493
 
UNIV_INTERN
1494
 
ibool
1495
 
rec_validate(
1496
 
/*=========*/
1497
 
                                /* out: TRUE if ok */
1498
 
        const rec_t*    rec,    /* in: physical record */
1499
 
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1500
 
{
1501
 
        const byte*     data;
1502
 
        ulint           len;
1503
 
        ulint           n_fields;
1504
 
        ulint           len_sum         = 0;
1505
 
        ulint           sum             = 0;
1506
 
        ulint           i;
1507
 
 
1508
 
        ut_a(rec);
1509
 
        n_fields = rec_offs_n_fields(offsets);
1510
 
 
1511
 
        if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1512
 
                fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1513
 
                        (ulong) n_fields);
1514
 
                return(FALSE);
1515
 
        }
1516
 
 
1517
 
        ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1518
 
 
1519
 
        for (i = 0; i < n_fields; i++) {
1520
 
                data = rec_get_nth_field(rec, offsets, i, &len);
1521
 
 
1522
 
                if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1523
 
                        fprintf(stderr,
1524
 
                                "InnoDB: Error: record field %lu len %lu\n",
1525
 
                                (ulong) i,
1526
 
                                (ulong) len);
1527
 
                        return(FALSE);
1528
 
                }
1529
 
 
1530
 
                if (len != UNIV_SQL_NULL) {
1531
 
                        len_sum += len;
1532
 
                        sum += *(data + len -1); /* dereference the
1533
 
                                                 end of the field to
1534
 
                                                 cause a memory trap
1535
 
                                                 if possible */
1536
 
                } else if (!rec_offs_comp(offsets)) {
1537
 
                        len_sum += rec_get_nth_field_size(rec, i);
1538
 
                }
1539
 
        }
1540
 
 
1541
 
        if (len_sum != rec_offs_data_size(offsets)) {
1542
 
                fprintf(stderr,
1543
 
                        "InnoDB: Error: record len should be %lu, len %lu\n",
1544
 
                        (ulong) len_sum,
1545
 
                        (ulong) rec_offs_data_size(offsets));
1546
 
                return(FALSE);
1547
 
        }
1548
 
 
1549
 
        rec_dummy = sum; /* This is here only to fool the compiler */
1550
 
 
1551
 
        if (!rec_offs_comp(offsets)) {
1552
 
                ut_a(rec_validate_old(rec));
1553
 
        }
1554
 
 
1555
 
        return(TRUE);
1556
 
}
1557
 
 
1558
 
/*******************************************************************
1559
 
Prints an old-style physical record. */
1560
 
UNIV_INTERN
1561
 
void
1562
 
rec_print_old(
1563
 
/*==========*/
1564
 
        FILE*           file,   /* in: file where to print */
1565
 
        const rec_t*    rec)    /* in: physical record */
1566
 
{
1567
 
        const byte*     data;
1568
 
        ulint           len;
1569
 
        ulint           n;
1570
 
        ulint           i;
1571
 
 
1572
 
        ut_ad(rec);
1573
 
 
1574
 
        n = rec_get_n_fields_old(rec);
1575
 
 
1576
 
        fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1577
 
                " %u-byte offsets; info bits %lu\n",
1578
 
                (ulong) n,
1579
 
                rec_get_1byte_offs_flag(rec) ? 1 : 2,
1580
 
                (ulong) rec_get_info_bits(rec, FALSE));
1581
 
 
1582
 
        for (i = 0; i < n; i++) {
1583
 
 
1584
 
                data = rec_get_nth_field_old(rec, i, &len);
1585
 
 
1586
 
                fprintf(file, " %lu:", (ulong) i);
1587
 
 
1588
 
                if (len != UNIV_SQL_NULL) {
1589
 
                        if (len <= 30) {
1590
 
 
1591
 
                                ut_print_buf(file, data, len);
1592
 
                        } else {
1593
 
                                ut_print_buf(file, data, 30);
1594
 
 
1595
 
                                fprintf(file, " (total %lu bytes)",
1596
 
                                        (ulong) len);
1597
 
                        }
1598
 
                } else {
1599
 
                        fprintf(file, " SQL NULL, size %lu ",
1600
 
                                rec_get_nth_field_size(rec, i));
1601
 
                }
1602
 
                putc(';', file);
1603
 
        }
1604
 
 
1605
 
        putc('\n', file);
1606
 
 
1607
 
        rec_validate_old(rec);
1608
 
}
1609
 
 
1610
 
/*******************************************************************
1611
 
Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
1612
 
record header. */
1613
 
UNIV_INTERN
1614
 
void
1615
 
rec_print_comp(
1616
 
/*===========*/
1617
 
        FILE*           file,   /* in: file where to print */
1618
 
        const rec_t*    rec,    /* in: physical record */
1619
 
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1620
 
{
1621
 
        ulint   i;
1622
 
 
1623
 
        for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1624
 
                const byte*     data;
1625
 
                ulint           len;
1626
 
 
1627
 
                data = rec_get_nth_field(rec, offsets, i, &len);
1628
 
 
1629
 
                fprintf(file, " %lu:", (ulong) i);
1630
 
 
1631
 
                if (len != UNIV_SQL_NULL) {
1632
 
                        if (len <= 30) {
1633
 
 
1634
 
                                ut_print_buf(file, data, len);
1635
 
                        } else {
1636
 
                                ut_print_buf(file, data, 30);
1637
 
 
1638
 
                                fprintf(file, " (total %lu bytes)",
1639
 
                                        (ulong) len);
1640
 
                        }
1641
 
                } else {
1642
 
                        fputs(" SQL NULL", file);
1643
 
                }
1644
 
                putc(';', file);
1645
 
        }
1646
 
 
1647
 
        putc('\n', file);
1648
 
}
1649
 
 
1650
 
/*******************************************************************
1651
 
Prints a physical record. */
1652
 
UNIV_INTERN
1653
 
void
1654
 
rec_print_new(
1655
 
/*==========*/
1656
 
        FILE*           file,   /* in: file where to print */
1657
 
        const rec_t*    rec,    /* in: physical record */
1658
 
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
1659
 
{
1660
 
        ut_ad(rec);
1661
 
        ut_ad(offsets);
1662
 
        ut_ad(rec_offs_validate(rec, NULL, offsets));
1663
 
 
1664
 
        if (!rec_offs_comp(offsets)) {
1665
 
                rec_print_old(file, rec);
1666
 
                return;
1667
 
        }
1668
 
 
1669
 
        fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1670
 
                " compact format; info bits %lu\n",
1671
 
                (ulong) rec_offs_n_fields(offsets),
1672
 
                (ulong) rec_get_info_bits(rec, TRUE));
1673
 
 
1674
 
        rec_print_comp(file, rec, offsets);
1675
 
        rec_validate(rec, offsets);
1676
 
}
1677
 
 
1678
 
/*******************************************************************
1679
 
Prints a physical record. */
1680
 
UNIV_INTERN
1681
 
void
1682
 
rec_print(
1683
 
/*======*/
1684
 
        FILE*           file,   /* in: file where to print */
1685
 
        const rec_t*    rec,    /* in: physical record */
1686
 
        dict_index_t*   index)  /* in: record descriptor */
1687
 
{
1688
 
        ut_ad(index);
1689
 
 
1690
 
        if (!dict_table_is_comp(index->table)) {
1691
 
                rec_print_old(file, rec);
1692
 
                return;
1693
 
        } else {
1694
 
                mem_heap_t*     heap    = NULL;
1695
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1696
 
                rec_offs_init(offsets_);
1697
 
 
1698
 
                rec_print_new(file, rec,
1699
 
                              rec_get_offsets(rec, index, offsets_,
1700
 
                                              ULINT_UNDEFINED, &heap));
1701
 
                if (UNIV_LIKELY_NULL(heap)) {
1702
 
                        mem_heap_free(heap);
1703
 
                }
1704
 
        }
1705
 
}