1
/************************************************************************
4
(c) 1994-1996 Innobase Oy
6
Created 5/30/1994 Heikki Tuuri
7
*************************************************************************/
13
#include "data0data.h"
14
#include "rem0types.h"
15
#include "mtr0types.h"
16
#include "page0types.h"
18
/* Info bit denoting the predefined minimum record: this bit is set
19
if and only if the record is the first user record on a non-leaf
20
B-tree page that is the leftmost page on its level
21
(PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
22
#define REC_INFO_MIN_REC_FLAG 0x10UL
23
/* The deleted flag in info bits */
24
#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the
25
record has been delete marked */
27
/* Number of extra bytes in an old-style record,
28
in addition to the data and the offsets */
29
#define REC_N_OLD_EXTRA_BYTES 6
30
/* Number of extra bytes in a new-style record,
31
in addition to the data and the offsets */
32
#define REC_N_NEW_EXTRA_BYTES 5
34
/* Record status values */
35
#define REC_STATUS_ORDINARY 0
36
#define REC_STATUS_NODE_PTR 1
37
#define REC_STATUS_INFIMUM 2
38
#define REC_STATUS_SUPREMUM 3
40
/* The following four constants are needed in page0zip.c in order to
41
efficiently compress and decompress pages. */
43
/* The offset of heap_no in a compact record */
44
#define REC_NEW_HEAP_NO 4
45
/* The shift of heap_no in a compact record.
46
The status is stored in the low-order bits. */
47
#define REC_HEAP_NO_SHIFT 3
49
/* Length of a B-tree node pointer, in bytes */
50
#define REC_NODE_PTR_SIZE 4
53
/* Length of the rec_get_offsets() header */
54
# define REC_OFFS_HEADER_SIZE 4
55
#else /* UNIV_DEBUG */
56
/* Length of the rec_get_offsets() header */
57
# define REC_OFFS_HEADER_SIZE 2
58
#endif /* UNIV_DEBUG */
60
/* Number of elements that should be initially allocated for the
61
offsets[] array, first passed to rec_get_offsets() */
62
#define REC_OFFS_NORMAL_SIZE 100
63
#define REC_OFFS_SMALL_SIZE 10
65
/**********************************************************
66
The following function is used to get the pointer of the next chained record
70
rec_get_next_ptr_const(
71
/*===================*/
72
/* out: pointer to the next chained record, or
74
const rec_t* rec, /* in: physical record */
75
ulint comp); /* in: nonzero=compact page format */
76
/**********************************************************
77
The following function is used to get the pointer of the next chained record
83
/* out: pointer to the next chained record, or
85
rec_t* rec, /* in: physical record */
86
ulint comp); /* in: nonzero=compact page format */
87
/**********************************************************
88
The following function is used to get the offset of the
89
next chained record on the same page. */
94
/* out: the page offset of the next
95
chained record, or 0 if none */
96
const rec_t* rec, /* in: physical record */
97
ulint comp); /* in: nonzero=compact page format */
98
/**********************************************************
99
The following function is used to set the next record offset field
100
of an old-style record. */
103
rec_set_next_offs_old(
104
/*==================*/
105
rec_t* rec, /* in: old-style physical record */
106
ulint next); /* in: offset of the next record */
107
/**********************************************************
108
The following function is used to set the next record offset field
109
of a new-style record. */
112
rec_set_next_offs_new(
113
/*==================*/
114
rec_t* rec, /* in/out: new-style physical record */
115
ulint next); /* in: offset of the next record */
116
/**********************************************************
117
The following function is used to get the number of fields
118
in an old-style record. */
121
rec_get_n_fields_old(
122
/*=================*/
123
/* out: number of data fields */
124
const rec_t* rec); /* in: physical record */
125
/**********************************************************
126
The following function is used to get the number of fields
132
/* out: number of data fields */
133
const rec_t* rec, /* in: physical record */
134
const dict_index_t* index); /* in: record descriptor */
135
/**********************************************************
136
The following function is used to get the number of records owned by the
137
previous directory record. */
142
/* out: number of owned records */
143
const rec_t* rec); /* in: old-style physical record */
144
/**********************************************************
145
The following function is used to set the number of owned records. */
150
/* out: TRUE on success */
151
rec_t* rec, /* in: old-style physical record */
152
ulint n_owned); /* in: the number of owned */
153
/**********************************************************
154
The following function is used to get the number of records owned by the
155
previous directory record. */
160
/* out: number of owned records */
161
const rec_t* rec); /* in: new-style physical record */
162
/**********************************************************
163
The following function is used to set the number of owned records. */
168
rec_t* rec, /* in/out: new-style physical record */
169
page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
170
ulint n_owned);/* in: the number of owned */
171
/**********************************************************
172
The following function is used to retrieve the info bits of
179
const rec_t* rec, /* in: physical record */
180
ulint comp); /* in: nonzero=compact page format */
181
/**********************************************************
182
The following function is used to set the info bits of a record. */
185
rec_set_info_bits_old(
186
/*==================*/
187
rec_t* rec, /* in: old-style physical record */
188
ulint bits); /* in: info bits */
189
/**********************************************************
190
The following function is used to set the info bits of a record. */
193
rec_set_info_bits_new(
194
/*==================*/
195
rec_t* rec, /* in/out: new-style physical record */
196
ulint bits); /* in: info bits */
197
/**********************************************************
198
The following function retrieves the status bits of a new-style record. */
203
/* out: status bits */
204
const rec_t* rec); /* in: physical record */
206
/**********************************************************
207
The following function is used to set the status bits of a new-style record. */
212
rec_t* rec, /* in/out: physical record */
213
ulint bits); /* in: info bits */
215
/**********************************************************
216
The following function is used to retrieve the info and status
217
bits of a record. (Only compact records have status bits.) */
220
rec_get_info_and_status_bits(
221
/*=========================*/
223
const rec_t* rec, /* in: physical record */
224
ulint comp); /* in: nonzero=compact page format */
225
/**********************************************************
226
The following function is used to set the info and status
227
bits of a record. (Only compact records have status bits.) */
230
rec_set_info_and_status_bits(
231
/*=========================*/
232
rec_t* rec, /* in/out: compact physical record */
233
ulint bits); /* in: info bits */
235
/**********************************************************
236
The following function tells if record is delete marked. */
239
rec_get_deleted_flag(
240
/*=================*/
241
/* out: nonzero if delete marked */
242
const rec_t* rec, /* in: physical record */
243
ulint comp); /* in: nonzero=compact page format */
244
/**********************************************************
245
The following function is used to set the deleted bit. */
248
rec_set_deleted_flag_old(
249
/*=====================*/
250
rec_t* rec, /* in: old-style physical record */
251
ulint flag); /* in: nonzero if delete marked */
252
/**********************************************************
253
The following function is used to set the deleted bit. */
256
rec_set_deleted_flag_new(
257
/*=====================*/
258
rec_t* rec, /* in/out: new-style physical record */
259
page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
260
ulint flag); /* in: nonzero if delete marked */
261
/**********************************************************
262
The following function tells if a new-style record is a node pointer. */
265
rec_get_node_ptr_flag(
266
/*==================*/
267
/* out: TRUE if node pointer */
268
const rec_t* rec); /* in: physical record */
269
/**********************************************************
270
The following function is used to get the order number
271
of an old-style record in the heap of the index page. */
276
/* out: heap order number */
277
const rec_t* rec); /* in: physical record */
278
/**********************************************************
279
The following function is used to set the heap number
280
field in an old-style record. */
285
rec_t* rec, /* in: physical record */
286
ulint heap_no);/* in: the heap number */
287
/**********************************************************
288
The following function is used to get the order number
289
of a new-style record in the heap of the index page. */
294
/* out: heap order number */
295
const rec_t* rec); /* in: physical record */
296
/**********************************************************
297
The following function is used to set the heap number
298
field in a new-style record. */
303
rec_t* rec, /* in/out: physical record */
304
ulint heap_no);/* in: the heap number */
305
/**********************************************************
306
The following function is used to test whether the data offsets
307
in the record are stored in one-byte or two-byte format. */
310
rec_get_1byte_offs_flag(
311
/*====================*/
312
/* out: TRUE if 1-byte form */
313
const rec_t* rec); /* in: physical record */
315
/**********************************************************
316
Determine how many of the first n columns in a compact
317
physical record are stored externally. */
320
rec_get_n_extern_new(
321
/*=================*/
322
/* out: number of externally stored columns */
323
const rec_t* rec, /* in: compact physical record */
324
dict_index_t* index, /* in: record descriptor */
325
ulint n); /* in: number of columns to scan */
327
/**********************************************************
328
The following function determines the offsets to each field
329
in the record. It can reuse a previously allocated array. */
332
rec_get_offsets_func(
333
/*=================*/
334
/* out: the new offsets */
335
const rec_t* rec, /* in: physical record */
336
const dict_index_t* index, /* in: record descriptor */
337
ulint* offsets,/* in/out: array consisting of
338
offsets[0] allocated elements,
339
or an array from rec_get_offsets(),
341
ulint n_fields,/* in: maximum number of
343
(ULINT_UNDEFINED if all fields) */
344
mem_heap_t** heap, /* in/out: memory heap */
345
const char* file, /* in: file name where called */
346
ulint line); /* in: line number where called */
348
#define rec_get_offsets(rec,index,offsets,n,heap) \
349
rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
351
/**********************************************************
352
Determine the offset to each field in a leaf-page record
353
in ROW_FORMAT=COMPACT. This is a special case of
354
rec_init_offsets() and rec_get_offsets_func(). */
357
rec_init_offsets_comp_ordinary(
358
/*===========================*/
359
const rec_t* rec, /* in: physical record in
360
ROW_FORMAT=COMPACT */
361
ulint extra, /* in: number of bytes to reserve
362
between the record header and
364
(usually REC_N_NEW_EXTRA_BYTES) */
365
const dict_index_t* index, /* in: record descriptor */
366
ulint* offsets);/* in/out: array of offsets;
367
in: n=rec_offs_n_fields(offsets) */
369
/**********************************************************
370
The following function determines the offsets to each field
371
in the record. It can reuse a previously allocated array. */
374
rec_get_offsets_reverse(
375
/*====================*/
376
const byte* extra, /* in: the extra bytes of a
377
compact record in reverse order,
378
excluding the fixed-size
379
REC_N_NEW_EXTRA_BYTES */
380
const dict_index_t* index, /* in: record descriptor */
381
ulint node_ptr,/* in: nonzero=node pointer,
383
ulint* offsets);/* in/out: array consisting of
384
offsets[0] allocated elements */
386
/****************************************************************
387
Validates offsets returned by rec_get_offsets(). */
392
/* out: TRUE if valid */
393
const rec_t* rec, /* in: record or NULL */
394
const dict_index_t* index, /* in: record descriptor or NULL */
395
const ulint* offsets);/* in: array returned by
398
/****************************************************************
399
Updates debug data in offsets, in order to avoid bogus
400
rec_offs_validate() failures. */
405
const rec_t* rec, /* in: record */
406
const dict_index_t* index, /* in: record descriptor */
407
ulint* offsets);/* in: array returned by
410
# define rec_offs_make_valid(rec, index, offsets) ((void) 0)
411
#endif /* UNIV_DEBUG */
413
/****************************************************************
414
The following function is used to get the offset to the nth
415
data field in an old-style record. */
418
rec_get_nth_field_offs_old(
419
/*=======================*/
420
/* out: offset to the field */
421
const rec_t* rec, /* in: record */
422
ulint n, /* in: index of the field */
423
ulint* len); /* out: length of the field; UNIV_SQL_NULL
425
#define rec_get_nth_field_old(rec, n, len) \
426
((rec) + rec_get_nth_field_offs_old(rec, n, len))
427
/****************************************************************
428
Gets the physical size of an old-style field.
429
Also an SQL null may have a field of size > 0,
430
if the data type is of a fixed size. */
433
rec_get_nth_field_size(
434
/*===================*/
435
/* out: field size in bytes */
436
const rec_t* rec, /* in: record */
437
ulint n); /* in: index of the field */
438
/****************************************************************
439
The following function is used to get an offset to the nth
440
data field in a record. */
443
rec_get_nth_field_offs(
444
/*===================*/
445
/* out: offset from the origin of rec */
446
const ulint* offsets,/* in: array returned by rec_get_offsets() */
447
ulint n, /* in: index of the field */
448
ulint* len); /* out: length of the field; UNIV_SQL_NULL
450
#define rec_get_nth_field(rec, offsets, n, len) \
451
((rec) + rec_get_nth_field_offs(offsets, n, len))
452
/**********************************************************
453
Determine if the offsets are for a record in the new
459
/* out: nonzero if compact format */
460
const ulint* offsets);/* in: array returned by rec_get_offsets() */
461
/**********************************************************
462
Determine if the offsets are for a record containing
463
externally stored columns. */
468
/* out: nonzero if externally stored */
469
const ulint* offsets);/* in: array returned by rec_get_offsets() */
470
/**********************************************************
471
Returns nonzero if the extern bit is set in nth field of rec. */
476
/* out: nonzero if externally stored */
477
const ulint* offsets,/* in: array returned by rec_get_offsets() */
478
ulint n); /* in: nth field */
479
/**********************************************************
480
Returns nonzero if the SQL NULL bit is set in nth field of rec. */
483
rec_offs_nth_sql_null(
484
/*==================*/
485
/* out: nonzero if SQL NULL */
486
const ulint* offsets,/* in: array returned by rec_get_offsets() */
487
ulint n); /* in: nth field */
488
/**********************************************************
489
Gets the physical size of a field. */
494
/* out: length of field */
495
const ulint* offsets,/* in: array returned by rec_get_offsets() */
496
ulint n); /* in: nth field */
498
/**********************************************************
499
Returns the number of extern bits set in a record. */
504
/* out: number of externally stored fields */
505
const ulint* offsets);/* in: array returned by rec_get_offsets() */
506
/***************************************************************
507
This is used to modify the value of an already existing field in a record.
508
The previous value must have exactly the same size as the new value. If len
509
is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
510
records. For new-style records, len must not be UNIV_SQL_NULL. */
515
rec_t* rec, /* in: record */
516
const ulint* offsets,/* in: array returned by rec_get_offsets() */
517
ulint n, /* in: index number of the field */
518
const void* data, /* in: pointer to the data if not SQL null */
519
ulint len); /* in: length of the data or UNIV_SQL_NULL.
520
If not SQL null, must have the same
521
length as the previous value.
522
If SQL null, previous value must be
524
/**************************************************************
525
The following function returns the data size of an old-style physical
526
record, that is the sum of field lengths. SQL null fields
527
are counted as length 0 fields. The value returned by the function
528
is the distance from record origin to record end in bytes. */
531
rec_get_data_size_old(
532
/*==================*/
534
const rec_t* rec); /* in: physical record */
535
/**************************************************************
536
The following function returns the number of allocated elements
537
for an array of offsets. */
540
rec_offs_get_n_alloc(
541
/*=================*/
542
/* out: number of elements */
543
const ulint* offsets);/* in: array for rec_get_offsets() */
544
/**************************************************************
545
The following function sets the number of allocated elements
546
for an array of offsets. */
549
rec_offs_set_n_alloc(
550
/*=================*/
551
ulint* offsets, /* out: array for rec_get_offsets(),
553
ulint n_alloc); /* in: number of elements */
554
#define rec_offs_init(offsets) \
555
rec_offs_set_n_alloc(offsets, (sizeof offsets) / sizeof *offsets)
556
/**************************************************************
557
The following function returns the number of fields in a record. */
562
/* out: number of fields */
563
const ulint* offsets);/* in: array returned by rec_get_offsets() */
564
/**************************************************************
565
The following function returns the data size of a physical
566
record, that is the sum of field lengths. SQL null fields
567
are counted as length 0 fields. The value returned by the function
568
is the distance from record origin to record end in bytes. */
574
const ulint* offsets);/* in: array returned by rec_get_offsets() */
575
/**************************************************************
576
Returns the total size of record minus data size of record.
577
The value returned by the function is the distance from record
578
start to record origin in bytes. */
584
const ulint* offsets);/* in: array returned by rec_get_offsets() */
585
/**************************************************************
586
Returns the total size of a physical record. */
592
const ulint* offsets);/* in: array returned by rec_get_offsets() */
593
/**************************************************************
594
Returns a pointer to the start of the record. */
599
/* out: pointer to start */
600
rec_t* rec, /* in: pointer to record */
601
const ulint* offsets);/* in: array returned by rec_get_offsets() */
602
/**************************************************************
603
Returns a pointer to the end of the record. */
608
/* out: pointer to end */
609
rec_t* rec, /* in: pointer to record */
610
const ulint* offsets);/* in: array returned by rec_get_offsets() */
611
/*******************************************************************
612
Copies a physical record to a buffer. */
617
/* out: pointer to the origin of the copy */
618
void* buf, /* in: buffer */
619
const rec_t* rec, /* in: physical record */
620
const ulint* offsets);/* in: array returned by rec_get_offsets() */
621
/******************************************************************
622
Copies the first n fields of a physical record to a new physical record in
626
rec_copy_prefix_to_buf(
627
/*===================*/
628
/* out, own: copied record */
629
const rec_t* rec, /* in: physical record */
630
const dict_index_t* index, /* in: record descriptor */
631
ulint n_fields, /* in: number of fields
633
byte** buf, /* in/out: memory buffer
634
for the copied prefix,
636
ulint* buf_size); /* in/out: buffer size */
637
/****************************************************************
638
Folds a prefix of a physical record to a ulint. */
643
/* out: the folded value */
644
const rec_t* rec, /* in: the physical record */
645
const ulint* offsets, /* in: array returned by
647
ulint n_fields, /* in: number of complete
649
ulint n_bytes, /* in: number of bytes to fold
650
in an incomplete last field */
651
dulint tree_id) /* in: index tree id */
652
__attribute__((pure));
653
/*************************************************************
654
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
657
rec_convert_dtuple_to_rec_comp(
658
/*===========================*/
659
rec_t* rec, /* in: origin of record */
660
ulint extra, /* in: number of bytes to
661
reserve between the record
662
header and the data payload
663
(normally REC_N_NEW_EXTRA_BYTES) */
664
const dict_index_t* index, /* in: record descriptor */
665
ulint status, /* in: status bits of the record */
666
const dfield_t* fields, /* in: array of data fields */
667
ulint n_fields);/* in: number of data fields */
668
/*************************************************************
669
Builds a physical record out of a data tuple and
670
stores it into the given buffer. */
673
rec_convert_dtuple_to_rec(
674
/*======================*/
675
/* out: pointer to the origin
676
of physical record */
677
byte* buf, /* in: start address of the
679
const dict_index_t* index, /* in: record descriptor */
680
const dtuple_t* dtuple, /* in: data tuple */
681
ulint n_ext); /* in: number of
682
externally stored columns */
683
/**************************************************************
684
Returns the extra size of an old-style physical record if we know its
685
data size and number of fields. */
688
rec_get_converted_extra_size(
689
/*=========================*/
690
/* out: extra size */
691
ulint data_size, /* in: data size */
692
ulint n_fields, /* in: number of fields */
693
ulint n_ext) /* in: number of externally stored columns */
694
__attribute__((__const__));
695
/**************************************************************
696
Determines the size of a data tuple in ROW_FORMAT=COMPACT. */
699
rec_get_converted_size_comp(
700
/*========================*/
701
/* out: total size */
702
const dict_index_t* index, /* in: record descriptor;
703
dict_table_is_comp() is
704
assumed to hold, even if
706
ulint status, /* in: status bits of the record */
707
const dfield_t* fields, /* in: array of data fields */
708
ulint n_fields,/* in: number of data fields */
709
ulint* extra); /* out: extra size */
710
/**************************************************************
711
The following function returns the size of a data tuple when converted to
712
a physical record. */
715
rec_get_converted_size(
716
/*===================*/
718
dict_index_t* index, /* in: record descriptor */
719
const dtuple_t* dtuple, /* in: data tuple */
720
ulint n_ext); /* in: number of externally stored columns */
721
/******************************************************************
722
Copies the first n fields of a physical record to a data tuple.
723
The fields are copied to the memory heap. */
726
rec_copy_prefix_to_dtuple(
727
/*======================*/
728
dtuple_t* tuple, /* out: data tuple */
729
const rec_t* rec, /* in: physical record */
730
const dict_index_t* index, /* in: record descriptor */
731
ulint n_fields, /* in: number of fields
733
mem_heap_t* heap); /* in: memory heap */
734
/*******************************************************************
735
Validates the consistency of a physical record. */
740
/* out: TRUE if ok */
741
const rec_t* rec, /* in: physical record */
742
const ulint* offsets);/* in: array returned by rec_get_offsets() */
743
/*******************************************************************
744
Prints an old-style physical record. */
749
FILE* file, /* in: file where to print */
750
const rec_t* rec); /* in: physical record */
751
/*******************************************************************
752
Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
758
FILE* file, /* in: file where to print */
759
const rec_t* rec, /* in: physical record */
760
const ulint* offsets);/* in: array returned by rec_get_offsets() */
761
/*******************************************************************
762
Prints a physical record. */
767
FILE* file, /* in: file where to print */
768
const rec_t* rec, /* in: physical record */
769
const ulint* offsets);/* in: array returned by rec_get_offsets() */
770
/*******************************************************************
771
Prints a physical record. */
776
FILE* file, /* in: file where to print */
777
const rec_t* rec, /* in: physical record */
778
dict_index_t* index); /* in: record descriptor */
780
#define REC_INFO_BITS 6 /* This is single byte bit-field */
782
/* Maximum lengths for the data in a physical record if the offsets
783
are given in one byte (resp. two byte) format. */
784
#define REC_1BYTE_OFFS_LIMIT 0x7FUL
785
#define REC_2BYTE_OFFS_LIMIT 0x7FFFUL
787
/* The data size of record must be smaller than this because we reserve
788
two upmost bits in a two byte offset for special purposes */
789
#define REC_MAX_DATA_SIZE (16 * 1024)
792
#include "rem0rec.ic"