~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-06-28 16:17:36 UTC
  • mfrom: (1637.4.1 drizzle)
  • Revision ID: brian@gaz-20100628161736-eormhb2mnd551i2h
Merge unused

Show diffs side-by-side

added added

removed removed

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