~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/include/rem0rec.ic

  • 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-1996 Innobase Oy
 
5
 
 
6
Created 5/30/1994 Heikki Tuuri
 
7
*************************************************************************/
 
8
 
 
9
#include "mach0data.h"
 
10
#include "ut0byte.h"
 
11
#include "dict0dict.h"
 
12
 
 
13
/* Compact flag ORed to the extra size returned by rec_get_offsets() */
 
14
#define REC_OFFS_COMPACT        ((ulint) 1 << 31)
 
15
/* SQL NULL flag in offsets returned by rec_get_offsets() */
 
16
#define REC_OFFS_SQL_NULL       ((ulint) 1 << 31)
 
17
/* External flag in offsets returned by rec_get_offsets() */
 
18
#define REC_OFFS_EXTERNAL       ((ulint) 1 << 30)
 
19
/* Mask for offsets returned by rec_get_offsets() */
 
20
#define REC_OFFS_MASK           (REC_OFFS_EXTERNAL - 1)
 
21
 
 
22
/* Offsets of the bit-fields in an old-style record. NOTE! In the table the
 
23
most significant bytes and bits are written below less significant.
 
24
 
 
25
        (1) byte offset         (2) bit usage within byte
 
26
        downward from
 
27
        origin ->       1       8 bits pointer to next record
 
28
                        2       8 bits pointer to next record
 
29
                        3       1 bit short flag
 
30
                                7 bits number of fields
 
31
                        4       3 bits number of fields
 
32
                                5 bits heap number
 
33
                        5       8 bits heap number
 
34
                        6       4 bits n_owned
 
35
                                4 bits info bits
 
36
*/
 
37
 
 
38
/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
 
39
most significant bytes and bits are written below less significant.
 
40
 
 
41
        (1) byte offset         (2) bit usage within byte
 
42
        downward from
 
43
        origin ->       1       8 bits relative offset of next record
 
44
                        2       8 bits relative offset of next record
 
45
                                  the relative offset is an unsigned 16-bit
 
46
                                  integer:
 
47
                                  (offset_of_next_record
 
48
                                   - offset_of_this_record) mod 64Ki,
 
49
                                  where mod is the modulo as a non-negative
 
50
                                  number;
 
51
                                  we can calculate the the offset of the next
 
52
                                  record with the formula:
 
53
                                  relative_offset + offset_of_this_record
 
54
                                  mod UNIV_PAGE_SIZE
 
55
                        3       3 bits status:
 
56
                                        000=conventional record
 
57
                                        001=node pointer record (inside B-tree)
 
58
                                        010=infimum record
 
59
                                        011=supremum record
 
60
                                        1xx=reserved
 
61
                                5 bits heap number
 
62
                        4       8 bits heap number
 
63
                        5       4 bits n_owned
 
64
                                4 bits info bits
 
65
*/
 
66
 
 
67
/* We list the byte offsets from the origin of the record, the mask,
 
68
and the shift needed to obtain each bit-field of the record. */
 
69
 
 
70
#define REC_NEXT                2
 
71
#define REC_NEXT_MASK           0xFFFFUL
 
72
#define REC_NEXT_SHIFT          0
 
73
 
 
74
#define REC_OLD_SHORT           3       /* This is single byte bit-field */
 
75
#define REC_OLD_SHORT_MASK      0x1UL
 
76
#define REC_OLD_SHORT_SHIFT     0
 
77
 
 
78
#define REC_OLD_N_FIELDS        4
 
79
#define REC_OLD_N_FIELDS_MASK   0x7FEUL
 
80
#define REC_OLD_N_FIELDS_SHIFT  1
 
81
 
 
82
#define REC_NEW_STATUS          3       /* This is single byte bit-field */
 
83
#define REC_NEW_STATUS_MASK     0x7UL
 
84
#define REC_NEW_STATUS_SHIFT    0
 
85
 
 
86
#define REC_OLD_HEAP_NO         5
 
87
#define REC_NEW_HEAP_NO         4
 
88
#define REC_HEAP_NO_MASK        0xFFF8UL
 
89
#define REC_HEAP_NO_SHIFT       3
 
90
 
 
91
#define REC_OLD_N_OWNED         6       /* This is single byte bit-field */
 
92
#define REC_NEW_N_OWNED         5       /* This is single byte bit-field */
 
93
#define REC_N_OWNED_MASK        0xFUL
 
94
#define REC_N_OWNED_SHIFT       0
 
95
 
 
96
#define REC_OLD_INFO_BITS       6       /* This is single byte bit-field */
 
97
#define REC_NEW_INFO_BITS       5       /* This is single byte bit-field */
 
98
#define REC_INFO_BITS_MASK      0xF0UL
 
99
#define REC_INFO_BITS_SHIFT     0
 
100
 
 
101
/* The deleted flag in info bits */
 
102
#define REC_INFO_DELETED_FLAG   0x20UL  /* when bit is set to 1, it means the
 
103
                                        record has been delete marked */
 
104
/* The following masks are used to filter the SQL null bit from
 
105
one-byte and two-byte offsets */
 
106
 
 
107
#define REC_1BYTE_SQL_NULL_MASK 0x80UL
 
108
#define REC_2BYTE_SQL_NULL_MASK 0x8000UL
 
109
 
 
110
/* In a 2-byte offset the second most significant bit denotes
 
111
a field stored to another page: */
 
112
 
 
113
#define REC_2BYTE_EXTERN_MASK   0x4000UL
 
114
 
 
115
#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
 
116
                ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
 
117
                ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
 
118
                ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
 
119
                ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
 
120
                ^ 0xFFFFFFFFUL
 
121
# error "sum of old-style masks != 0xFFFFFFFFUL"
 
122
#endif
 
123
#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
 
124
                ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
 
125
                ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
 
126
                ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
 
127
                ^ 0xFFFFFFUL
 
128
# error "sum of new-style masks != 0xFFFFFFUL"
 
129
#endif
 
130
 
 
131
/***************************************************************
 
132
Sets the value of the ith field SQL null bit of an old-style record. */
 
133
 
 
134
void
 
135
rec_set_nth_field_null_bit(
 
136
/*=======================*/
 
137
        rec_t*  rec,    /* in: record */
 
138
        ulint   i,      /* in: ith field */
 
139
        ibool   val);   /* in: value to set */
 
140
/***************************************************************
 
141
Sets an old-style record field to SQL null.
 
142
The physical size of the field is not changed. */
 
143
 
 
144
void
 
145
rec_set_nth_field_sql_null(
 
146
/*=======================*/
 
147
        rec_t*  rec,    /* in: record */
 
148
        ulint   n);     /* in: index of the field */
 
149
 
 
150
/***************************************************************
 
151
Sets the value of the ith field extern storage bit of an old-style record. */
 
152
 
 
153
void
 
154
rec_set_nth_field_extern_bit_old(
 
155
/*=============================*/
 
156
        rec_t*  rec,    /* in: old-style record */
 
157
        ulint   i,      /* in: ith field */
 
158
        ibool   val,    /* in: value to set */
 
159
        mtr_t*  mtr);   /* in: mtr holding an X-latch to the page where
 
160
                        rec is, or NULL; in the NULL case we do not
 
161
                        write to log about the change */
 
162
/***************************************************************
 
163
Sets the value of the ith field extern storage bit of a new-style record. */
 
164
 
 
165
void
 
166
rec_set_nth_field_extern_bit_new(
 
167
/*=============================*/
 
168
        rec_t*          rec,    /* in: record */
 
169
        dict_index_t*   index,  /* in: record descriptor */
 
170
        ulint           ith,    /* in: ith field */
 
171
        ibool           val,    /* in: value to set */
 
172
        mtr_t*          mtr);   /* in: mtr holding an X-latch to the page
 
173
                                where rec is, or NULL; in the NULL case
 
174
                                we do not write to log about the change */
 
175
 
 
176
/**********************************************************
 
177
Gets a bit field from within 1 byte. */
 
178
UNIV_INLINE
 
179
ulint
 
180
rec_get_bit_field_1(
 
181
/*================*/
 
182
        rec_t*  rec,    /* in: pointer to record origin */
 
183
        ulint   offs,   /* in: offset from the origin down */
 
184
        ulint   mask,   /* in: mask used to filter bits */
 
185
        ulint   shift)  /* in: shift right applied after masking */
 
186
{
 
187
        ut_ad(rec);
 
188
 
 
189
        return((mach_read_from_1(rec - offs) & mask) >> shift);
 
190
}
 
191
 
 
192
/**********************************************************
 
193
Sets a bit field within 1 byte. */
 
194
UNIV_INLINE
 
195
void
 
196
rec_set_bit_field_1(
 
197
/*================*/
 
198
        rec_t*  rec,    /* in: pointer to record origin */
 
199
        ulint   val,    /* in: value to set */
 
200
        ulint   offs,   /* in: offset from the origin down */
 
201
        ulint   mask,   /* in: mask used to filter bits */
 
202
        ulint   shift)  /* in: shift right applied after masking */
 
203
{
 
204
        ut_ad(rec);
 
205
        ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
 
206
        ut_ad(mask);
 
207
        ut_ad(mask <= 0xFFUL);
 
208
        ut_ad(((mask >> shift) << shift) == mask);
 
209
        ut_ad(((val << shift) & mask) == (val << shift));
 
210
 
 
211
        mach_write_to_1(rec - offs,
 
212
                        (mach_read_from_1(rec - offs) & ~mask)
 
213
                        | (val << shift));
 
214
}
 
215
 
 
216
/**********************************************************
 
217
Gets a bit field from within 2 bytes. */
 
218
UNIV_INLINE
 
219
ulint
 
220
rec_get_bit_field_2(
 
221
/*================*/
 
222
        rec_t*  rec,    /* in: pointer to record origin */
 
223
        ulint   offs,   /* in: offset from the origin down */
 
224
        ulint   mask,   /* in: mask used to filter bits */
 
225
        ulint   shift)  /* in: shift right applied after masking */
 
226
{
 
227
        ut_ad(rec);
 
228
 
 
229
        return((mach_read_from_2(rec - offs) & mask) >> shift);
 
230
}
 
231
 
 
232
/**********************************************************
 
233
Sets a bit field within 2 bytes. */
 
234
UNIV_INLINE
 
235
void
 
236
rec_set_bit_field_2(
 
237
/*================*/
 
238
        rec_t*  rec,    /* in: pointer to record origin */
 
239
        ulint   val,    /* in: value to set */
 
240
        ulint   offs,   /* in: offset from the origin down */
 
241
        ulint   mask,   /* in: mask used to filter bits */
 
242
        ulint   shift)  /* in: shift right applied after masking */
 
243
{
 
244
        ut_ad(rec);
 
245
        ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
 
246
        ut_ad(mask > 0xFFUL);
 
247
        ut_ad(mask <= 0xFFFFUL);
 
248
        ut_ad((mask >> shift) & 1);
 
249
        ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
 
250
        ut_ad(((mask >> shift) << shift) == mask);
 
251
        ut_ad(((val << shift) & mask) == (val << shift));
 
252
 
 
253
        mach_write_to_2(rec - offs,
 
254
                        (mach_read_from_2(rec - offs) & ~mask)
 
255
                        | (val << shift));
 
256
}
 
257
 
 
258
/**********************************************************
 
259
The following function is used to get the offset of the next chained record
 
260
on the same page. */
 
261
UNIV_INLINE
 
262
ulint
 
263
rec_get_next_offs(
 
264
/*==============*/
 
265
                        /* out: the page offset of the next chained record, or
 
266
                        0 if none */
 
267
        rec_t*  rec,    /* in: physical record */
 
268
        ulint   comp)   /* in: nonzero=compact page format */
 
269
{
 
270
        ulint   field_value;
 
271
#if REC_NEXT_MASK != 0xFFFFUL
 
272
# error "REC_NEXT_MASK != 0xFFFFUL"
 
273
#endif
 
274
#if REC_NEXT_SHIFT
 
275
# error "REC_NEXT_SHIFT != 0"
 
276
#endif
 
277
 
 
278
        field_value = mach_read_from_2(rec - REC_NEXT);
 
279
 
 
280
        if (comp) {
 
281
#if UNIV_PAGE_SIZE <= 32768
 
282
                /* Note that for 64 KiB pages, field_value can 'wrap around'
 
283
                and the debug assertion is not valid */
 
284
 
 
285
                /* In the following assertion, field_value is interpreted
 
286
                as signed 16-bit integer in 2's complement arithmetics.
 
287
                If all platforms defined int16_t in the standard headers,
 
288
                the expression could be written simpler as
 
289
                (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
 
290
                */
 
291
                ut_ad((field_value >= 32768
 
292
                       ? field_value - 65536
 
293
                       : field_value)
 
294
                      + ut_align_offset(rec, UNIV_PAGE_SIZE)
 
295
                      < UNIV_PAGE_SIZE);
 
296
#endif
 
297
                if (field_value == 0) {
 
298
 
 
299
                        return(0);
 
300
                }
 
301
 
 
302
                return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
 
303
        } else {
 
304
                ut_ad(field_value < UNIV_PAGE_SIZE);
 
305
 
 
306
                return(field_value);
 
307
        }
 
308
}
 
309
 
 
310
/**********************************************************
 
311
The following function is used to set the next record offset field of the
 
312
record. */
 
313
UNIV_INLINE
 
314
void
 
315
rec_set_next_offs(
 
316
/*==============*/
 
317
        rec_t*  rec,    /* in: physical record */
 
318
        ulint   comp,   /* in: nonzero=compact page format */
 
319
        ulint   next)   /* in: offset of the next record, or 0 if none */
 
320
{
 
321
        ut_ad(rec);
 
322
        ut_ad(UNIV_PAGE_SIZE > next);
 
323
#if REC_NEXT_MASK != 0xFFFFUL
 
324
# error "REC_NEXT_MASK != 0xFFFFUL"
 
325
#endif
 
326
#if REC_NEXT_SHIFT
 
327
# error "REC_NEXT_SHIFT != 0"
 
328
#endif
 
329
 
 
330
        if (comp) {
 
331
                ulint field_value;
 
332
 
 
333
                if (next) {
 
334
                        /* The following two statements calculate
 
335
                        next - offset_of_rec mod 64Ki, where mod is the modulo
 
336
                        as a non-negative number */
 
337
 
 
338
                        field_value = (ulint)((lint)next
 
339
                                              - (lint)ut_align_offset(
 
340
                                                      rec, UNIV_PAGE_SIZE));
 
341
                        field_value &= REC_NEXT_MASK;
 
342
                } else {
 
343
                        field_value = 0;
 
344
                }
 
345
 
 
346
                mach_write_to_2(rec - REC_NEXT, field_value);
 
347
        } else {
 
348
                mach_write_to_2(rec - REC_NEXT, next);
 
349
        }
 
350
}
 
351
 
 
352
/**********************************************************
 
353
The following function is used to get the number of fields
 
354
in an old-style record. */
 
355
UNIV_INLINE
 
356
ulint
 
357
rec_get_n_fields_old(
 
358
/*=================*/
 
359
                        /* out: number of data fields */
 
360
        rec_t*  rec)    /* in: physical record */
 
361
{
 
362
        ulint   ret;
 
363
 
 
364
        ut_ad(rec);
 
365
 
 
366
        ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
 
367
                                  REC_OLD_N_FIELDS_MASK,
 
368
                                  REC_OLD_N_FIELDS_SHIFT);
 
369
        ut_ad(ret <= REC_MAX_N_FIELDS);
 
370
        ut_ad(ret > 0);
 
371
 
 
372
        return(ret);
 
373
}
 
374
 
 
375
/**********************************************************
 
376
The following function is used to set the number of fields
 
377
in an old-style record. */
 
378
UNIV_INLINE
 
379
void
 
380
rec_set_n_fields_old(
 
381
/*=================*/
 
382
        rec_t*  rec,            /* in: physical record */
 
383
        ulint   n_fields)       /* in: the number of fields */
 
384
{
 
385
        ut_ad(rec);
 
386
        ut_ad(n_fields <= REC_MAX_N_FIELDS);
 
387
        ut_ad(n_fields > 0);
 
388
 
 
389
        rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
 
390
                            REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
 
391
}
 
392
 
 
393
/**********************************************************
 
394
The following function retrieves the status bits of a new-style record. */
 
395
UNIV_INLINE
 
396
ulint
 
397
rec_get_status(
 
398
/*===========*/
 
399
                        /* out: status bits */
 
400
        rec_t*  rec)    /* in: physical record */
 
401
{
 
402
        ulint   ret;
 
403
 
 
404
        ut_ad(rec);
 
405
 
 
406
        ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
 
407
                                  REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
 
408
        ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
 
409
 
 
410
        return(ret);
 
411
}
 
412
 
 
413
/**********************************************************
 
414
The following function is used to get the number of fields
 
415
in a record. */
 
416
UNIV_INLINE
 
417
ulint
 
418
rec_get_n_fields(
 
419
/*=============*/
 
420
                                /* out: number of data fields */
 
421
        rec_t*          rec,    /* in: physical record */
 
422
        dict_index_t*   index)  /* in: record descriptor */
 
423
{
 
424
        ut_ad(rec);
 
425
        ut_ad(index);
 
426
 
 
427
        if (!dict_table_is_comp(index->table)) {
 
428
                return(rec_get_n_fields_old(rec));
 
429
        }
 
430
 
 
431
        switch (rec_get_status(rec)) {
 
432
        case REC_STATUS_ORDINARY:
 
433
                return(dict_index_get_n_fields(index));
 
434
        case REC_STATUS_NODE_PTR:
 
435
                return(dict_index_get_n_unique_in_tree(index) + 1);
 
436
        case REC_STATUS_INFIMUM:
 
437
        case REC_STATUS_SUPREMUM:
 
438
                return(1);
 
439
        default:
 
440
                ut_error;
 
441
                return(ULINT_UNDEFINED);
 
442
        }
 
443
}
 
444
 
 
445
/**********************************************************
 
446
The following function is used to get the number of records owned by the
 
447
previous directory record. */
 
448
UNIV_INLINE
 
449
ulint
 
450
rec_get_n_owned(
 
451
/*============*/
 
452
                        /* out: number of owned records */
 
453
        rec_t*  rec,    /* in: physical record */
 
454
        ulint   comp)   /* in: nonzero=compact page format */
 
455
{
 
456
        ulint   ret;
 
457
 
 
458
        ut_ad(rec);
 
459
 
 
460
        ret = rec_get_bit_field_1(rec,
 
461
                                  comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
 
462
                                  REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
 
463
        ut_ad(ret <= REC_MAX_N_OWNED);
 
464
 
 
465
        return(ret);
 
466
}
 
467
 
 
468
/**********************************************************
 
469
The following function is used to set the number of owned records. */
 
470
UNIV_INLINE
 
471
void
 
472
rec_set_n_owned(
 
473
/*============*/
 
474
        rec_t*  rec,            /* in: physical record */
 
475
        ulint   comp,           /* in: nonzero=compact page format */
 
476
        ulint   n_owned)        /* in: the number of owned */
 
477
{
 
478
        ut_ad(rec);
 
479
        ut_ad(n_owned <= REC_MAX_N_OWNED);
 
480
 
 
481
        rec_set_bit_field_1(rec, n_owned,
 
482
                            comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
 
483
                            REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
 
484
}
 
485
 
 
486
/**********************************************************
 
487
The following function is used to retrieve the info bits of a record. */
 
488
UNIV_INLINE
 
489
ulint
 
490
rec_get_info_bits(
 
491
/*==============*/
 
492
                        /* out: info bits */
 
493
        rec_t*  rec,    /* in: physical record */
 
494
        ulint   comp)   /* in: nonzero=compact page format */
 
495
{
 
496
        ulint   ret;
 
497
 
 
498
        ut_ad(rec);
 
499
 
 
500
        ret = rec_get_bit_field_1(rec,
 
501
                                  comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
 
502
                                  REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
 
503
        ut_ad((ret & ~REC_INFO_BITS_MASK) == 0);
 
504
 
 
505
        return(ret);
 
506
}
 
507
 
 
508
/**********************************************************
 
509
The following function is used to set the info bits of a record. */
 
510
UNIV_INLINE
 
511
void
 
512
rec_set_info_bits(
 
513
/*==============*/
 
514
        rec_t*  rec,    /* in: physical record */
 
515
        ulint   comp,   /* in: nonzero=compact page format */
 
516
        ulint   bits)   /* in: info bits */
 
517
{
 
518
        ut_ad(rec);
 
519
        ut_ad((bits & ~REC_INFO_BITS_MASK) == 0);
 
520
 
 
521
        rec_set_bit_field_1(rec, bits,
 
522
                            comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
 
523
                            REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
 
524
}
 
525
 
 
526
/**********************************************************
 
527
The following function is used to set the status bits of a new-style record. */
 
528
UNIV_INLINE
 
529
void
 
530
rec_set_status(
 
531
/*===========*/
 
532
        rec_t*  rec,    /* in: physical record */
 
533
        ulint   bits)   /* in: info bits */
 
534
{
 
535
        ut_ad(rec);
 
536
        ut_ad((bits & ~REC_NEW_STATUS_MASK) == 0);
 
537
 
 
538
        rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
 
539
                            REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
 
540
}
 
541
 
 
542
/**********************************************************
 
543
The following function is used to retrieve the info and status
 
544
bits of a record.  (Only compact records have status bits.) */
 
545
UNIV_INLINE
 
546
ulint
 
547
rec_get_info_and_status_bits(
 
548
/*=========================*/
 
549
                        /* out: info bits */
 
550
        rec_t*  rec,    /* in: physical record */
 
551
        ulint   comp)   /* in: nonzero=compact page format */
 
552
{
 
553
        ulint   bits;
 
554
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
 
555
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
 
556
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
 
557
#endif
 
558
        if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
 
559
                bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
 
560
        } else {
 
561
                bits = rec_get_info_bits(rec, FALSE);
 
562
                ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
 
563
        }
 
564
        return(bits);
 
565
}
 
566
/**********************************************************
 
567
The following function is used to set the info and status
 
568
bits of a record.  (Only compact records have status bits.) */
 
569
UNIV_INLINE
 
570
void
 
571
rec_set_info_and_status_bits(
 
572
/*=========================*/
 
573
        rec_t*  rec,    /* in: physical record */
 
574
        ulint   comp,   /* in: nonzero=compact page format */
 
575
        ulint   bits)   /* in: info bits */
 
576
{
 
577
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
 
578
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
 
579
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
 
580
#endif
 
581
        if (comp) {
 
582
                rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
 
583
        } else {
 
584
                ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
 
585
        }
 
586
        rec_set_info_bits(rec, comp, bits & ~REC_NEW_STATUS_MASK);
 
587
}
 
588
 
 
589
/**********************************************************
 
590
The following function tells if record is delete marked. */
 
591
UNIV_INLINE
 
592
ulint
 
593
rec_get_deleted_flag(
 
594
/*=================*/
 
595
                        /* out: nonzero if delete marked */
 
596
        rec_t*  rec,    /* in: physical record */
 
597
        ulint   comp)   /* in: nonzero=compact page format */
 
598
{
 
599
        if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
 
600
                return(UNIV_UNLIKELY(
 
601
                               rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
 
602
                                                   REC_INFO_DELETED_FLAG,
 
603
                                                   REC_INFO_BITS_SHIFT)));
 
604
        } else {
 
605
                return(UNIV_UNLIKELY(
 
606
                               rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
 
607
                                                   REC_INFO_DELETED_FLAG,
 
608
                                                   REC_INFO_BITS_SHIFT)));
 
609
        }
 
610
}
 
611
 
 
612
/**********************************************************
 
613
The following function is used to set the deleted bit. */
 
614
UNIV_INLINE
 
615
void
 
616
rec_set_deleted_flag(
 
617
/*=================*/
 
618
        rec_t*  rec,    /* in: physical record */
 
619
        ulint   comp,   /* in: nonzero=compact page format */
 
620
        ulint   flag)   /* in: nonzero if delete marked */
 
621
{
 
622
        ulint   val;
 
623
 
 
624
        val = rec_get_info_bits(rec, comp);
 
625
 
 
626
        if (flag) {
 
627
                val |= REC_INFO_DELETED_FLAG;
 
628
        } else {
 
629
                val &= ~REC_INFO_DELETED_FLAG;
 
630
        }
 
631
 
 
632
        rec_set_info_bits(rec, comp, val);
 
633
}
 
634
 
 
635
/**********************************************************
 
636
The following function tells if a new-style record is a node pointer. */
 
637
UNIV_INLINE
 
638
ibool
 
639
rec_get_node_ptr_flag(
 
640
/*==================*/
 
641
                        /* out: TRUE if node pointer */
 
642
        rec_t*  rec)    /* in: physical record */
 
643
{
 
644
        return(REC_STATUS_NODE_PTR == rec_get_status(rec));
 
645
}
 
646
 
 
647
/**********************************************************
 
648
The following function is used to get the order number of the record in the
 
649
heap of the index page. */
 
650
UNIV_INLINE
 
651
ulint
 
652
rec_get_heap_no(
 
653
/*============*/
 
654
                        /* out: heap order number */
 
655
        rec_t*  rec,    /* in: physical record */
 
656
        ulint   comp)   /* in: nonzero=compact page format */
 
657
{
 
658
        ulint   ret;
 
659
 
 
660
        ut_ad(rec);
 
661
 
 
662
        ret = rec_get_bit_field_2(rec,
 
663
                                  comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
 
664
                                  REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
 
665
        ut_ad(ret <= REC_MAX_HEAP_NO);
 
666
 
 
667
        return(ret);
 
668
}
 
669
 
 
670
/**********************************************************
 
671
The following function is used to set the heap number field in the record. */
 
672
UNIV_INLINE
 
673
void
 
674
rec_set_heap_no(
 
675
/*============*/
 
676
        rec_t*  rec,    /* in: physical record */
 
677
        ulint   comp,   /* in: nonzero=compact page format */
 
678
        ulint   heap_no)/* in: the heap number */
 
679
{
 
680
        ut_ad(heap_no <= REC_MAX_HEAP_NO);
 
681
 
 
682
        rec_set_bit_field_2(rec, heap_no,
 
683
                            comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
 
684
                            REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
 
685
}
 
686
 
 
687
/**********************************************************
 
688
The following function is used to test whether the data offsets in the record
 
689
are stored in one-byte or two-byte format. */
 
690
UNIV_INLINE
 
691
ibool
 
692
rec_get_1byte_offs_flag(
 
693
/*====================*/
 
694
                        /* out: TRUE if 1-byte form */
 
695
        rec_t*  rec)    /* in: physical record */
 
696
{
 
697
#if TRUE != 1
 
698
#error "TRUE != 1"
 
699
#endif
 
700
 
 
701
        return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
 
702
                                   REC_OLD_SHORT_SHIFT));
 
703
}
 
704
 
 
705
/**********************************************************
 
706
The following function is used to set the 1-byte offsets flag. */
 
707
UNIV_INLINE
 
708
void
 
709
rec_set_1byte_offs_flag(
 
710
/*====================*/
 
711
        rec_t*  rec,    /* in: physical record */
 
712
        ibool   flag)   /* in: TRUE if 1byte form */
 
713
{
 
714
#if TRUE != 1
 
715
#error "TRUE != 1"
 
716
#endif
 
717
        ut_ad(flag <= TRUE);
 
718
 
 
719
        rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
 
720
                            REC_OLD_SHORT_SHIFT);
 
721
}
 
722
 
 
723
/**********************************************************
 
724
Returns the offset of nth field end if the record is stored in the 1-byte
 
725
offsets form. If the field is SQL null, the flag is ORed in the returned
 
726
value. */
 
727
UNIV_INLINE
 
728
ulint
 
729
rec_1_get_field_end_info(
 
730
/*=====================*/
 
731
                        /* out: offset of the start of the field, SQL null
 
732
                        flag ORed */
 
733
        rec_t*  rec,    /* in: record */
 
734
        ulint   n)      /* in: field index */
 
735
{
 
736
        ut_ad(rec_get_1byte_offs_flag(rec));
 
737
        ut_ad(n < rec_get_n_fields_old(rec));
 
738
 
 
739
        return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
 
740
}
 
741
 
 
742
/**********************************************************
 
743
Returns the offset of nth field end if the record is stored in the 2-byte
 
744
offsets form. If the field is SQL null, the flag is ORed in the returned
 
745
value. */
 
746
UNIV_INLINE
 
747
ulint
 
748
rec_2_get_field_end_info(
 
749
/*=====================*/
 
750
                        /* out: offset of the start of the field, SQL null
 
751
                        flag and extern storage flag ORed */
 
752
        rec_t*  rec,    /* in: record */
 
753
        ulint   n)      /* in: field index */
 
754
{
 
755
        ut_ad(!rec_get_1byte_offs_flag(rec));
 
756
        ut_ad(n < rec_get_n_fields_old(rec));
 
757
 
 
758
        return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
 
759
}
 
760
 
 
761
#ifdef UNIV_DEBUG
 
762
/* Length of the rec_get_offsets() header */
 
763
# define REC_OFFS_HEADER_SIZE   4
 
764
#else /* UNIV_DEBUG */
 
765
/* Length of the rec_get_offsets() header */
 
766
# define REC_OFFS_HEADER_SIZE   2
 
767
#endif /* UNIV_DEBUG */
 
768
 
 
769
/* Get the base address of offsets.  The extra_size is stored at
 
770
this position, and following positions hold the end offsets of
 
771
the fields. */
 
772
#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
 
773
 
 
774
/**************************************************************
 
775
The following function returns the number of allocated elements
 
776
for an array of offsets. */
 
777
UNIV_INLINE
 
778
ulint
 
779
rec_offs_get_n_alloc(
 
780
/*=================*/
 
781
                                /* out: number of elements */
 
782
        const ulint*    offsets)/* in: array for rec_get_offsets() */
 
783
{
 
784
        ulint   n_alloc;
 
785
        ut_ad(offsets);
 
786
        n_alloc = offsets[0];
 
787
        ut_ad(n_alloc > 0);
 
788
        return(n_alloc);
 
789
}
 
790
 
 
791
/**************************************************************
 
792
The following function sets the number of allocated elements
 
793
for an array of offsets. */
 
794
UNIV_INLINE
 
795
void
 
796
rec_offs_set_n_alloc(
 
797
/*=================*/
 
798
        ulint*  offsets,        /* out: array for rec_get_offsets(),
 
799
                                must be allocated */
 
800
        ulint   n_alloc)        /* in: number of elements */
 
801
{
 
802
        ut_ad(offsets);
 
803
        ut_ad(n_alloc > 0);
 
804
        UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
 
805
        offsets[0] = n_alloc;
 
806
}
 
807
 
 
808
/**************************************************************
 
809
The following function returns the number of fields in a record. */
 
810
UNIV_INLINE
 
811
ulint
 
812
rec_offs_n_fields(
 
813
/*==============*/
 
814
                                /* out: number of fields */
 
815
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
816
{
 
817
        ulint   n_fields;
 
818
        ut_ad(offsets);
 
819
        n_fields = offsets[1];
 
820
        ut_ad(n_fields > 0);
 
821
        ut_ad(n_fields <= REC_MAX_N_FIELDS);
 
822
        ut_ad(n_fields + REC_OFFS_HEADER_SIZE
 
823
              <= rec_offs_get_n_alloc(offsets));
 
824
        return(n_fields);
 
825
}
 
826
 
 
827
/****************************************************************
 
828
Validates offsets returned by rec_get_offsets(). */
 
829
UNIV_INLINE
 
830
ibool
 
831
rec_offs_validate(
 
832
/*==============*/
 
833
                                /* out: TRUE if valid */
 
834
        rec_t*          rec,    /* in: record or NULL */
 
835
        dict_index_t*   index,  /* in: record descriptor or NULL */
 
836
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
837
{
 
838
        ulint   i       = rec_offs_n_fields(offsets);
 
839
        ulint   last    = ULINT_MAX;
 
840
        ulint   comp    = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
 
841
 
 
842
        if (rec) {
 
843
                ut_ad((ulint) rec == offsets[2]);
 
844
                if (!comp) {
 
845
                        ut_a(rec_get_n_fields_old(rec) >= i);
 
846
                }
 
847
        }
 
848
        if (index) {
 
849
                ulint max_n_fields;
 
850
                ut_ad((ulint) index == offsets[3]);
 
851
                max_n_fields = ut_max(
 
852
                        dict_index_get_n_fields(index),
 
853
                        dict_index_get_n_unique_in_tree(index) + 1);
 
854
                if (comp && rec) {
 
855
                        switch (rec_get_status(rec)) {
 
856
                        case REC_STATUS_ORDINARY:
 
857
                                break;
 
858
                        case REC_STATUS_NODE_PTR:
 
859
                                max_n_fields = dict_index_get_n_unique_in_tree(
 
860
                                        index) + 1;
 
861
                                break;
 
862
                        case REC_STATUS_INFIMUM:
 
863
                        case REC_STATUS_SUPREMUM:
 
864
                                max_n_fields = 1;
 
865
                                break;
 
866
                        default:
 
867
                                ut_error;
 
868
                        }
 
869
                }
 
870
                /* index->n_def == 0 for dummy indexes if !comp */
 
871
                ut_a(!comp || index->n_def);
 
872
                ut_a(!index->n_def || i <= max_n_fields);
 
873
        }
 
874
        while (i--) {
 
875
                ulint   curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
 
876
                ut_a(curr <= last);
 
877
                last = curr;
 
878
        }
 
879
        return(TRUE);
 
880
}
 
881
/****************************************************************
 
882
Updates debug data in offsets, in order to avoid bogus
 
883
rec_offs_validate() failures. */
 
884
UNIV_INLINE
 
885
void
 
886
rec_offs_make_valid(
 
887
/*================*/
 
888
        rec_t*          rec __attribute__((unused)),
 
889
                                /* in: record */
 
890
        dict_index_t*   index __attribute__((unused)),
 
891
                                /* in: record descriptor */
 
892
        ulint*          offsets __attribute__((unused)))
 
893
                                /* in: array returned by rec_get_offsets() */
 
894
{
 
895
#ifdef UNIV_DEBUG
 
896
        ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
 
897
        offsets[2] = (ulint) rec;
 
898
        offsets[3] = (ulint) index;
 
899
#endif /* UNIV_DEBUG */
 
900
}
 
901
 
 
902
/****************************************************************
 
903
The following function is used to get a pointer to the nth
 
904
data field in a record. */
 
905
UNIV_INLINE
 
906
byte*
 
907
rec_get_nth_field(
 
908
/*==============*/
 
909
                                /* out: pointer to the field */
 
910
        rec_t*          rec,    /* in: record */
 
911
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
912
        ulint           n,      /* in: index of the field */
 
913
        ulint*          len)    /* out: length of the field; UNIV_SQL_NULL
 
914
                                if SQL null */
 
915
{
 
916
        byte*   field;
 
917
        ulint   length;
 
918
        ut_ad(rec);
 
919
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
920
        ut_ad(n < rec_offs_n_fields(offsets));
 
921
        ut_ad(len);
 
922
 
 
923
        if (UNIV_UNLIKELY(n == 0)) {
 
924
                field = rec;
 
925
        } else {
 
926
                field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
 
927
        }
 
928
 
 
929
        length = rec_offs_base(offsets)[1 + n];
 
930
 
 
931
        if (length & REC_OFFS_SQL_NULL) {
 
932
                length = UNIV_SQL_NULL;
 
933
        } else {
 
934
                length &= REC_OFFS_MASK;
 
935
                length -= field - rec;
 
936
        }
 
937
 
 
938
        *len = length;
 
939
        return(field);
 
940
}
 
941
 
 
942
/**********************************************************
 
943
Determine if the offsets are for a record in the new
 
944
compact format. */
 
945
UNIV_INLINE
 
946
ulint
 
947
rec_offs_comp(
 
948
/*==========*/
 
949
                                /* out: nonzero if compact format */
 
950
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
951
{
 
952
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
953
        return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
 
954
}
 
955
 
 
956
/**********************************************************
 
957
Returns nonzero if the extern bit is set in nth field of rec. */
 
958
UNIV_INLINE
 
959
ulint
 
960
rec_offs_nth_extern(
 
961
/*================*/
 
962
                                /* out: nonzero if externally stored */
 
963
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
964
        ulint           n)      /* in: nth field */
 
965
{
 
966
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
967
        ut_ad(n < rec_offs_n_fields(offsets));
 
968
        return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
 
969
                             & REC_OFFS_EXTERNAL));
 
970
}
 
971
 
 
972
/**********************************************************
 
973
Returns nonzero if the SQL NULL bit is set in nth field of rec. */
 
974
UNIV_INLINE
 
975
ulint
 
976
rec_offs_nth_sql_null(
 
977
/*==================*/
 
978
                                /* out: nonzero if SQL NULL */
 
979
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
980
        ulint           n)      /* in: nth field */
 
981
{
 
982
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
983
        ut_ad(n < rec_offs_n_fields(offsets));
 
984
        return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
 
985
                             & REC_OFFS_SQL_NULL));
 
986
}
 
987
 
 
988
/**********************************************************
 
989
Gets the physical size of a field. */
 
990
UNIV_INLINE
 
991
ulint
 
992
rec_offs_nth_size(
 
993
/*==============*/
 
994
                                /* out: length of field */
 
995
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
996
        ulint           n)      /* in: nth field */
 
997
{
 
998
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
999
        ut_ad(n < rec_offs_n_fields(offsets));
 
1000
        if (!n) {
 
1001
                return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
 
1002
        }
 
1003
        return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
 
1004
               & REC_OFFS_MASK);
 
1005
}
 
1006
 
 
1007
/**********************************************************
 
1008
Returns TRUE if the extern bit is set in any of the fields
 
1009
of an old-style record. */
 
1010
UNIV_INLINE
 
1011
ibool
 
1012
rec_offs_any_extern(
 
1013
/*================*/
 
1014
                                /* out: TRUE if a field is stored externally */
 
1015
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1016
{
 
1017
        ulint   i;
 
1018
        for (i = rec_offs_n_fields(offsets); i--; ) {
 
1019
                if (rec_offs_nth_extern(offsets, i)) {
 
1020
                        return(TRUE);
 
1021
                }
 
1022
        }
 
1023
        return(FALSE);
 
1024
}
 
1025
 
 
1026
/***************************************************************
 
1027
Sets the value of the ith field extern storage bit. */
 
1028
UNIV_INLINE
 
1029
void
 
1030
rec_set_nth_field_extern_bit(
 
1031
/*=========================*/
 
1032
        rec_t*          rec,    /* in: record */
 
1033
        dict_index_t*   index,  /* in: record descriptor */
 
1034
        ulint           i,      /* in: ith field */
 
1035
        ibool           val,    /* in: value to set */
 
1036
        mtr_t*          mtr)    /* in: mtr holding an X-latch to the page
 
1037
                                where rec is, or NULL; in the NULL case
 
1038
                                we do not write to log about the change */
 
1039
{
 
1040
        if (dict_table_is_comp(index->table)) {
 
1041
                rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
 
1042
        } else {
 
1043
                rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
 
1044
        }
 
1045
}
 
1046
 
 
1047
/**********************************************************
 
1048
Returns the offset of n - 1th field end if the record is stored in the 1-byte
 
1049
offsets form. If the field is SQL null, the flag is ORed in the returned
 
1050
value. This function and the 2-byte counterpart are defined here because the
 
1051
C-compiler was not able to sum negative and positive constant offsets, and
 
1052
warned of constant arithmetic overflow within the compiler. */
 
1053
UNIV_INLINE
 
1054
ulint
 
1055
rec_1_get_prev_field_end_info(
 
1056
/*==========================*/
 
1057
                        /* out: offset of the start of the PREVIOUS field, SQL
 
1058
                        null flag ORed */
 
1059
        rec_t*  rec,    /* in: record */
 
1060
        ulint   n)      /* in: field index */
 
1061
{
 
1062
        ut_ad(rec_get_1byte_offs_flag(rec));
 
1063
        ut_ad(n <= rec_get_n_fields_old(rec));
 
1064
 
 
1065
        return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
 
1066
}
 
1067
 
 
1068
/**********************************************************
 
1069
Returns the offset of n - 1th field end if the record is stored in the 2-byte
 
1070
offsets form. If the field is SQL null, the flag is ORed in the returned
 
1071
value. */
 
1072
UNIV_INLINE
 
1073
ulint
 
1074
rec_2_get_prev_field_end_info(
 
1075
/*==========================*/
 
1076
                        /* out: offset of the start of the PREVIOUS field, SQL
 
1077
                        null flag ORed */
 
1078
        rec_t*  rec,    /* in: record */
 
1079
        ulint   n)      /* in: field index */
 
1080
{
 
1081
        ut_ad(!rec_get_1byte_offs_flag(rec));
 
1082
        ut_ad(n <= rec_get_n_fields_old(rec));
 
1083
 
 
1084
        return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
 
1085
}
 
1086
 
 
1087
/**********************************************************
 
1088
Sets the field end info for the nth field if the record is stored in the
 
1089
1-byte format. */
 
1090
UNIV_INLINE
 
1091
void
 
1092
rec_1_set_field_end_info(
 
1093
/*=====================*/
 
1094
        rec_t*  rec,    /* in: record */
 
1095
        ulint   n,      /* in: field index */
 
1096
        ulint   info)   /* in: value to set */
 
1097
{
 
1098
        ut_ad(rec_get_1byte_offs_flag(rec));
 
1099
        ut_ad(n < rec_get_n_fields_old(rec));
 
1100
 
 
1101
        mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
 
1102
}
 
1103
 
 
1104
/**********************************************************
 
1105
Sets the field end info for the nth field if the record is stored in the
 
1106
2-byte format. */
 
1107
UNIV_INLINE
 
1108
void
 
1109
rec_2_set_field_end_info(
 
1110
/*=====================*/
 
1111
        rec_t*  rec,    /* in: record */
 
1112
        ulint   n,      /* in: field index */
 
1113
        ulint   info)   /* in: value to set */
 
1114
{
 
1115
        ut_ad(!rec_get_1byte_offs_flag(rec));
 
1116
        ut_ad(n < rec_get_n_fields_old(rec));
 
1117
 
 
1118
        mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
 
1119
}
 
1120
 
 
1121
/**********************************************************
 
1122
Returns the offset of nth field start if the record is stored in the 1-byte
 
1123
offsets form. */
 
1124
UNIV_INLINE
 
1125
ulint
 
1126
rec_1_get_field_start_offs(
 
1127
/*=======================*/
 
1128
                        /* out: offset of the start of the field */
 
1129
        rec_t*  rec,    /* in: record */
 
1130
        ulint   n)      /* in: field index */
 
1131
{
 
1132
        ut_ad(rec_get_1byte_offs_flag(rec));
 
1133
        ut_ad(n <= rec_get_n_fields_old(rec));
 
1134
 
 
1135
        if (n == 0) {
 
1136
 
 
1137
                return(0);
 
1138
        }
 
1139
 
 
1140
        return(rec_1_get_prev_field_end_info(rec, n)
 
1141
               & ~REC_1BYTE_SQL_NULL_MASK);
 
1142
}
 
1143
 
 
1144
/**********************************************************
 
1145
Returns the offset of nth field start if the record is stored in the 2-byte
 
1146
offsets form. */
 
1147
UNIV_INLINE
 
1148
ulint
 
1149
rec_2_get_field_start_offs(
 
1150
/*=======================*/
 
1151
                        /* out: offset of the start of the field */
 
1152
        rec_t*  rec,    /* in: record */
 
1153
        ulint   n)      /* in: field index */
 
1154
{
 
1155
        ut_ad(!rec_get_1byte_offs_flag(rec));
 
1156
        ut_ad(n <= rec_get_n_fields_old(rec));
 
1157
 
 
1158
        if (n == 0) {
 
1159
 
 
1160
                return(0);
 
1161
        }
 
1162
 
 
1163
        return(rec_2_get_prev_field_end_info(rec, n)
 
1164
               & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
 
1165
}
 
1166
 
 
1167
/**********************************************************
 
1168
The following function is used to read the offset of the start of a data field
 
1169
in the record. The start of an SQL null field is the end offset of the
 
1170
previous non-null field, or 0, if none exists. If n is the number of the last
 
1171
field + 1, then the end offset of the last field is returned. */
 
1172
UNIV_INLINE
 
1173
ulint
 
1174
rec_get_field_start_offs(
 
1175
/*=====================*/
 
1176
                        /* out: offset of the start of the field */
 
1177
        rec_t*  rec,    /* in: record */
 
1178
        ulint   n)      /* in: field index */
 
1179
{
 
1180
        ut_ad(rec);
 
1181
        ut_ad(n <= rec_get_n_fields_old(rec));
 
1182
 
 
1183
        if (n == 0) {
 
1184
 
 
1185
                return(0);
 
1186
        }
 
1187
 
 
1188
        if (rec_get_1byte_offs_flag(rec)) {
 
1189
 
 
1190
                return(rec_1_get_field_start_offs(rec, n));
 
1191
        }
 
1192
 
 
1193
        return(rec_2_get_field_start_offs(rec, n));
 
1194
}
 
1195
 
 
1196
/****************************************************************
 
1197
Gets the physical size of an old-style field.
 
1198
Also an SQL null may have a field of size > 0,
 
1199
if the data type is of a fixed size. */
 
1200
UNIV_INLINE
 
1201
ulint
 
1202
rec_get_nth_field_size(
 
1203
/*===================*/
 
1204
                        /* out: field size in bytes */
 
1205
        rec_t*  rec,    /* in: record */
 
1206
        ulint   n)      /* in: index of the field */
 
1207
{
 
1208
        ulint   os;
 
1209
        ulint   next_os;
 
1210
 
 
1211
        os = rec_get_field_start_offs(rec, n);
 
1212
        next_os = rec_get_field_start_offs(rec, n + 1);
 
1213
 
 
1214
        ut_ad(next_os - os < UNIV_PAGE_SIZE);
 
1215
 
 
1216
        return(next_os - os);
 
1217
}
 
1218
 
 
1219
/***************************************************************
 
1220
This is used to modify the value of an already existing field in a record.
 
1221
The previous value must have exactly the same size as the new value. If len
 
1222
is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
 
1223
records. For new-style records, len must not be UNIV_SQL_NULL. */
 
1224
UNIV_INLINE
 
1225
void
 
1226
rec_set_nth_field(
 
1227
/*==============*/
 
1228
        rec_t*          rec,    /* in: record */
 
1229
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
1230
        ulint           n,      /* in: index number of the field */
 
1231
        const void*     data,   /* in: pointer to the data
 
1232
                                if not SQL null */
 
1233
        ulint           len)    /* in: length of the data or UNIV_SQL_NULL.
 
1234
                                If not SQL null, must have the same
 
1235
                                length as the previous value.
 
1236
                                If SQL null, previous value must be
 
1237
                                SQL null. */
 
1238
{
 
1239
        byte*   data2;
 
1240
        ulint   len2;
 
1241
 
 
1242
        ut_ad(rec);
 
1243
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
1244
 
 
1245
        if (len == UNIV_SQL_NULL) {
 
1246
                ut_ad(!rec_offs_comp(offsets));
 
1247
                rec_set_nth_field_sql_null(rec, n);
 
1248
 
 
1249
                return;
 
1250
        }
 
1251
 
 
1252
        data2 = rec_get_nth_field(rec, offsets, n, &len2);
 
1253
        if (len2 == UNIV_SQL_NULL) {
 
1254
                ut_ad(!rec_offs_comp(offsets));
 
1255
                rec_set_nth_field_null_bit(rec, n, FALSE);
 
1256
                ut_ad(len == rec_get_nth_field_size(rec, n));
 
1257
        } else {
 
1258
                ut_ad(len2 == len);
 
1259
        }
 
1260
 
 
1261
        ut_memcpy(data2, data, len);
 
1262
}
 
1263
 
 
1264
/**************************************************************
 
1265
The following function returns the data size of an old-style physical
 
1266
record, that is the sum of field lengths. SQL null fields
 
1267
are counted as length 0 fields. The value returned by the function
 
1268
is the distance from record origin to record end in bytes. */
 
1269
UNIV_INLINE
 
1270
ulint
 
1271
rec_get_data_size_old(
 
1272
/*==================*/
 
1273
                                /* out: size */
 
1274
        rec_t*  rec)    /* in: physical record */
 
1275
{
 
1276
        ut_ad(rec);
 
1277
 
 
1278
        return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
 
1279
}
 
1280
 
 
1281
/**************************************************************
 
1282
The following function sets the number of fields in offsets. */
 
1283
UNIV_INLINE
 
1284
void
 
1285
rec_offs_set_n_fields(
 
1286
/*==================*/
 
1287
        ulint*  offsets,        /* in/out: array returned by
 
1288
                                rec_get_offsets() */
 
1289
        ulint   n_fields)       /* in: number of fields */
 
1290
{
 
1291
        ut_ad(offsets);
 
1292
        ut_ad(n_fields > 0);
 
1293
        ut_ad(n_fields <= REC_MAX_N_FIELDS);
 
1294
        ut_ad(n_fields + REC_OFFS_HEADER_SIZE
 
1295
              <= rec_offs_get_n_alloc(offsets));
 
1296
        offsets[1] = n_fields;
 
1297
}
 
1298
 
 
1299
/**************************************************************
 
1300
The following function returns the data size of a physical
 
1301
record, that is the sum of field lengths. SQL null fields
 
1302
are counted as length 0 fields. The value returned by the function
 
1303
is the distance from record origin to record end in bytes. */
 
1304
UNIV_INLINE
 
1305
ulint
 
1306
rec_offs_data_size(
 
1307
/*===============*/
 
1308
                                /* out: size */
 
1309
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1310
{
 
1311
        ulint   size;
 
1312
 
 
1313
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
1314
        size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
 
1315
                & REC_OFFS_MASK;
 
1316
        ut_ad(size < UNIV_PAGE_SIZE);
 
1317
        return(size);
 
1318
}
 
1319
 
 
1320
/**************************************************************
 
1321
Returns the total size of record minus data size of record. The value
 
1322
returned by the function is the distance from record start to record origin
 
1323
in bytes. */
 
1324
UNIV_INLINE
 
1325
ulint
 
1326
rec_offs_extra_size(
 
1327
/*================*/
 
1328
                                /* out: size */
 
1329
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1330
{
 
1331
        ulint   size;
 
1332
        ut_ad(rec_offs_validate(NULL, NULL, offsets));
 
1333
        size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT;
 
1334
        ut_ad(size < UNIV_PAGE_SIZE);
 
1335
        return(size);
 
1336
}
 
1337
 
 
1338
/**************************************************************
 
1339
Returns the total size of a physical record.  */
 
1340
UNIV_INLINE
 
1341
ulint
 
1342
rec_offs_size(
 
1343
/*==========*/
 
1344
                                /* out: size */
 
1345
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1346
{
 
1347
        return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
 
1348
}
 
1349
 
 
1350
/**************************************************************
 
1351
Returns a pointer to the end of the record. */
 
1352
UNIV_INLINE
 
1353
byte*
 
1354
rec_get_end(
 
1355
/*========*/
 
1356
                                /* out: pointer to end */
 
1357
        rec_t*          rec,    /* in: pointer to record */
 
1358
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1359
{
 
1360
        return(rec + rec_offs_data_size(offsets));
 
1361
}
 
1362
 
 
1363
/**************************************************************
 
1364
Returns a pointer to the start of the record. */
 
1365
UNIV_INLINE
 
1366
byte*
 
1367
rec_get_start(
 
1368
/*==========*/
 
1369
                                /* out: pointer to start */
 
1370
        rec_t*          rec,    /* in: pointer to record */
 
1371
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1372
{
 
1373
        return(rec - rec_offs_extra_size(offsets));
 
1374
}
 
1375
 
 
1376
/*******************************************************************
 
1377
Copies a physical record to a buffer. */
 
1378
UNIV_INLINE
 
1379
rec_t*
 
1380
rec_copy(
 
1381
/*=====*/
 
1382
                                /* out: pointer to the origin of the copy */
 
1383
        void*           buf,    /* in: buffer */
 
1384
        const rec_t*    rec,    /* in: physical record */
 
1385
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
1386
{
 
1387
        ulint   extra_len;
 
1388
        ulint   data_len;
 
1389
 
 
1390
        ut_ad(rec && buf);
 
1391
        ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
 
1392
        ut_ad(rec_validate((rec_t*) rec, offsets));
 
1393
 
 
1394
        extra_len = rec_offs_extra_size(offsets);
 
1395
        data_len = rec_offs_data_size(offsets);
 
1396
 
 
1397
        ut_memcpy(buf, rec - extra_len, extra_len + data_len);
 
1398
 
 
1399
        return((byte*)buf + extra_len);
 
1400
}
 
1401
 
 
1402
/**************************************************************
 
1403
Returns the extra size of an old-style physical record if we know its
 
1404
data size and number of fields. */
 
1405
UNIV_INLINE
 
1406
ulint
 
1407
rec_get_converted_extra_size(
 
1408
/*=========================*/
 
1409
                                /* out: extra size */
 
1410
        ulint   data_size,      /* in: data size */
 
1411
        ulint   n_fields)       /* in: number of fields */
 
1412
{
 
1413
        if (data_size <= REC_1BYTE_OFFS_LIMIT) {
 
1414
 
 
1415
                return(REC_N_OLD_EXTRA_BYTES + n_fields);
 
1416
        }
 
1417
 
 
1418
        return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
 
1419
}
 
1420
 
 
1421
/**************************************************************
 
1422
The following function returns the size of a data tuple when converted to
 
1423
a new-style physical record. */
 
1424
 
 
1425
ulint
 
1426
rec_get_converted_size_new(
 
1427
/*=======================*/
 
1428
                                /* out: size */
 
1429
        dict_index_t*   index,  /* in: record descriptor */
 
1430
        dtuple_t*       dtuple);/* in: data tuple */
 
1431
/**************************************************************
 
1432
The following function returns the size of a data tuple when converted to
 
1433
a physical record. */
 
1434
UNIV_INLINE
 
1435
ulint
 
1436
rec_get_converted_size(
 
1437
/*===================*/
 
1438
                                /* out: size */
 
1439
        dict_index_t*   index,  /* in: record descriptor */
 
1440
        dtuple_t*       dtuple) /* in: data tuple */
 
1441
{
 
1442
        ulint   data_size;
 
1443
        ulint   extra_size;
 
1444
 
 
1445
        ut_ad(index);
 
1446
        ut_ad(dtuple);
 
1447
        ut_ad(dtuple_check_typed(dtuple));
 
1448
 
 
1449
        ut_ad(index->type & DICT_UNIVERSAL
 
1450
              || dtuple_get_n_fields(dtuple)
 
1451
              == (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
 
1452
                   == REC_STATUS_NODE_PTR)
 
1453
                  ? dict_index_get_n_unique_in_tree(index) + 1
 
1454
                  : dict_index_get_n_fields(index)));
 
1455
 
 
1456
        if (dict_table_is_comp(index->table)) {
 
1457
                return(rec_get_converted_size_new(index, dtuple));
 
1458
        }
 
1459
 
 
1460
        data_size = dtuple_get_data_size(dtuple);
 
1461
 
 
1462
        extra_size = rec_get_converted_extra_size(
 
1463
                data_size, dtuple_get_n_fields(dtuple));
 
1464
 
 
1465
        return(data_size + extra_size);
 
1466
}
 
1467
 
 
1468
/****************************************************************
 
1469
Folds a prefix of a physical record to a ulint. Folds only existing fields,
 
1470
that is, checks that we do not run out of the record. */
 
1471
UNIV_INLINE
 
1472
ulint
 
1473
rec_fold(
 
1474
/*=====*/
 
1475
                                        /* out: the folded value */
 
1476
        rec_t*          rec,            /* in: the physical record */
 
1477
        const ulint*    offsets,        /* in: array returned by
 
1478
                                        rec_get_offsets() */
 
1479
        ulint           n_fields,       /* in: number of complete
 
1480
                                        fields to fold */
 
1481
        ulint           n_bytes,        /* in: number of bytes to fold
 
1482
                                        in an incomplete last field */
 
1483
        dulint          tree_id)        /* in: index tree id */
 
1484
{
 
1485
        ulint   i;
 
1486
        byte*   data;
 
1487
        ulint   len;
 
1488
        ulint   fold;
 
1489
        ulint   n_fields_rec;
 
1490
 
 
1491
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
1492
        ut_ad(rec_validate((rec_t*) rec, offsets));
 
1493
        ut_ad(n_fields + n_bytes > 0);
 
1494
 
 
1495
        n_fields_rec = rec_offs_n_fields(offsets);
 
1496
        ut_ad(n_fields <= n_fields_rec);
 
1497
        ut_ad(n_fields < n_fields_rec || n_bytes == 0);
 
1498
 
 
1499
        if (n_fields > n_fields_rec) {
 
1500
                n_fields = n_fields_rec;
 
1501
        }
 
1502
 
 
1503
        if (n_fields == n_fields_rec) {
 
1504
                n_bytes = 0;
 
1505
        }
 
1506
 
 
1507
        fold = ut_fold_dulint(tree_id);
 
1508
 
 
1509
        for (i = 0; i < n_fields; i++) {
 
1510
                data = rec_get_nth_field(rec, offsets, i, &len);
 
1511
 
 
1512
                if (len != UNIV_SQL_NULL) {
 
1513
                        fold = ut_fold_ulint_pair(fold,
 
1514
                                                  ut_fold_binary(data, len));
 
1515
                }
 
1516
        }
 
1517
 
 
1518
        if (n_bytes > 0) {
 
1519
                data = rec_get_nth_field(rec, offsets, i, &len);
 
1520
 
 
1521
                if (len != UNIV_SQL_NULL) {
 
1522
                        if (len > n_bytes) {
 
1523
                                len = n_bytes;
 
1524
                        }
 
1525
 
 
1526
                        fold = ut_fold_ulint_pair(fold,
 
1527
                                                  ut_fold_binary(data, len));
 
1528
                }
 
1529
        }
 
1530
 
 
1531
        return(fold);
 
1532
}