1
/*****************************************************************************
3
Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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
17
*****************************************************************************/
19
/********************************************************************//**
20
@file include/rem0rec.h
23
Created 5/30/1994 Heikki Tuuri
24
*************************************************************************/
30
#include "data0data.h"
31
#include "rem0types.h"
32
#include "mtr0types.h"
33
#include "page0types.h"
35
/* Info bit denoting the predefined minimum record: this bit is set
36
if and only if the record is the first user record on a non-leaf
37
B-tree page that is the leftmost page on its level
38
(PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
39
#define REC_INFO_MIN_REC_FLAG 0x10UL
40
/* The deleted flag in info bits */
41
#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the
42
record has been delete marked */
44
/* Number of extra bytes in an old-style record,
45
in addition to the data and the offsets */
46
#define REC_N_OLD_EXTRA_BYTES 6
47
/* Number of extra bytes in a new-style record,
48
in addition to the data and the offsets */
49
#define REC_N_NEW_EXTRA_BYTES 5
51
/* Record status values */
52
#define REC_STATUS_ORDINARY 0
53
#define REC_STATUS_NODE_PTR 1
54
#define REC_STATUS_INFIMUM 2
55
#define REC_STATUS_SUPREMUM 3
57
/* The following four constants are needed in page0zip.c in order to
58
efficiently compress and decompress pages. */
60
/* The offset of heap_no in a compact record */
61
#define REC_NEW_HEAP_NO 4
62
/* The shift of heap_no in a compact record.
63
The status is stored in the low-order bits. */
64
#define REC_HEAP_NO_SHIFT 3
66
/* Length of a B-tree node pointer, in bytes */
67
#define REC_NODE_PTR_SIZE 4
70
/* Length of the rec_get_offsets() header */
71
# define REC_OFFS_HEADER_SIZE 4
72
#else /* UNIV_DEBUG */
73
/* Length of the rec_get_offsets() header */
74
# define REC_OFFS_HEADER_SIZE 2
75
#endif /* UNIV_DEBUG */
77
/* Number of elements that should be initially allocated for the
78
offsets[] array, first passed to rec_get_offsets() */
79
#define REC_OFFS_NORMAL_SIZE 100
80
#define REC_OFFS_SMALL_SIZE 10
82
/******************************************************//**
83
The following function is used to get the pointer of the next chained record
85
@return pointer to the next chained record, or NULL if none */
88
rec_get_next_ptr_const(
89
/*===================*/
90
const rec_t* rec, /*!< in: physical record */
91
ulint comp); /*!< in: nonzero=compact page format */
92
/******************************************************//**
93
The following function is used to get the pointer of the next chained record
95
@return pointer to the next chained record, or NULL if none */
100
rec_t* rec, /*!< in: physical record */
101
ulint comp); /*!< in: nonzero=compact page format */
102
/******************************************************//**
103
The following function is used to get the offset of the
104
next chained record on the same page.
105
@return the page offset of the next chained record, or 0 if none */
110
const rec_t* rec, /*!< in: physical record */
111
ulint comp); /*!< in: nonzero=compact page format */
112
/******************************************************//**
113
The following function is used to set the next record offset field
114
of an old-style record. */
117
rec_set_next_offs_old(
118
/*==================*/
119
rec_t* rec, /*!< in: old-style physical record */
120
ulint next); /*!< in: offset of the next record */
121
/******************************************************//**
122
The following function is used to set the next record offset field
123
of a new-style record. */
126
rec_set_next_offs_new(
127
/*==================*/
128
rec_t* rec, /*!< in/out: new-style physical record */
129
ulint next); /*!< in: offset of the next record */
130
/******************************************************//**
131
The following function is used to get the number of fields
132
in an old-style record.
133
@return number of data fields */
136
rec_get_n_fields_old(
137
/*=================*/
138
const rec_t* rec); /*!< in: physical record */
139
/******************************************************//**
140
The following function is used to get the number of fields
142
@return number of data fields */
147
const rec_t* rec, /*!< in: physical record */
148
const dict_index_t* index); /*!< in: record descriptor */
149
/******************************************************//**
150
The following function is used to get the number of records owned by the
151
previous directory record.
152
@return number of owned records */
157
const rec_t* rec); /*!< in: old-style physical record */
158
/******************************************************//**
159
The following function is used to set the number of owned records. */
164
rec_t* rec, /*!< in: old-style physical record */
165
ulint n_owned); /*!< in: the number of owned */
166
/******************************************************//**
167
The following function is used to get the number of records owned by the
168
previous directory record.
169
@return number of owned records */
174
const rec_t* rec); /*!< in: new-style physical record */
175
/******************************************************//**
176
The following function is used to set the number of owned records. */
181
rec_t* rec, /*!< in/out: new-style physical record */
182
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
183
ulint n_owned);/*!< in: the number of owned */
184
/******************************************************//**
185
The following function is used to retrieve the info bits of
192
const rec_t* rec, /*!< in: physical record */
193
ulint comp); /*!< in: nonzero=compact page format */
194
/******************************************************//**
195
The following function is used to set the info bits of a record. */
198
rec_set_info_bits_old(
199
/*==================*/
200
rec_t* rec, /*!< in: old-style physical record */
201
ulint bits); /*!< in: info bits */
202
/******************************************************//**
203
The following function is used to set the info bits of a record. */
206
rec_set_info_bits_new(
207
/*==================*/
208
rec_t* rec, /*!< in/out: new-style physical record */
209
ulint bits); /*!< in: info bits */
210
/******************************************************//**
211
The following function retrieves the status bits of a new-style record.
212
@return status bits */
217
const rec_t* rec); /*!< in: physical record */
219
/******************************************************//**
220
The following function is used to set the status bits of a new-style record. */
225
rec_t* rec, /*!< in/out: physical record */
226
ulint bits); /*!< in: info bits */
228
/******************************************************//**
229
The following function is used to retrieve the info and status
230
bits of a record. (Only compact records have status bits.)
234
rec_get_info_and_status_bits(
235
/*=========================*/
236
const rec_t* rec, /*!< in: physical record */
237
ulint comp); /*!< in: nonzero=compact page format */
238
/******************************************************//**
239
The following function is used to set the info and status
240
bits of a record. (Only compact records have status bits.) */
243
rec_set_info_and_status_bits(
244
/*=========================*/
245
rec_t* rec, /*!< in/out: compact physical record */
246
ulint bits); /*!< in: info bits */
248
/******************************************************//**
249
The following function tells if record is delete marked.
250
@return nonzero if delete marked */
253
rec_get_deleted_flag(
254
/*=================*/
255
const rec_t* rec, /*!< in: physical record */
256
ulint comp); /*!< in: nonzero=compact page format */
257
/******************************************************//**
258
The following function is used to set the deleted bit. */
261
rec_set_deleted_flag_old(
262
/*=====================*/
263
rec_t* rec, /*!< in: old-style physical record */
264
ulint flag); /*!< in: nonzero if delete marked */
265
/******************************************************//**
266
The following function is used to set the deleted bit. */
269
rec_set_deleted_flag_new(
270
/*=====================*/
271
rec_t* rec, /*!< in/out: new-style physical record */
272
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
273
ulint flag); /*!< in: nonzero if delete marked */
274
/******************************************************//**
275
The following function tells if a new-style record is a node pointer.
276
@return TRUE if node pointer */
279
rec_get_node_ptr_flag(
280
/*==================*/
281
const rec_t* rec); /*!< in: physical record */
282
/******************************************************//**
283
The following function is used to get the order number
284
of an old-style record in the heap of the index page.
285
@return heap order number */
290
const rec_t* rec); /*!< in: physical record */
291
/******************************************************//**
292
The following function is used to set the heap number
293
field in an old-style record. */
298
rec_t* rec, /*!< in: physical record */
299
ulint heap_no);/*!< in: the heap number */
300
/******************************************************//**
301
The following function is used to get the order number
302
of a new-style record in the heap of the index page.
303
@return heap order number */
308
const rec_t* rec); /*!< in: physical record */
309
/******************************************************//**
310
The following function is used to set the heap number
311
field in a new-style record. */
316
rec_t* rec, /*!< in/out: physical record */
317
ulint heap_no);/*!< in: the heap number */
318
/******************************************************//**
319
The following function is used to test whether the data offsets
320
in the record are stored in one-byte or two-byte format.
321
@return TRUE if 1-byte form */
324
rec_get_1byte_offs_flag(
325
/*====================*/
326
const rec_t* rec); /*!< in: physical record */
328
/******************************************************//**
329
Determine how many of the first n columns in a compact
330
physical record are stored externally.
331
@return number of externally stored columns */
334
rec_get_n_extern_new(
335
/*=================*/
336
const rec_t* rec, /*!< in: compact physical record */
337
dict_index_t* index, /*!< in: record descriptor */
338
ulint n); /*!< in: number of columns to scan */
340
/******************************************************//**
341
The following function determines the offsets to each field
342
in the record. It can reuse a previously allocated array.
343
@return the new offsets */
346
rec_get_offsets_func(
347
/*=================*/
348
const rec_t* rec, /*!< in: physical record */
349
const dict_index_t* index, /*!< in: record descriptor */
350
ulint* offsets,/*!< in/out: array consisting of
351
offsets[0] allocated elements,
352
or an array from rec_get_offsets(),
354
ulint n_fields,/*!< in: maximum number of
356
(ULINT_UNDEFINED if all fields) */
357
mem_heap_t** heap, /*!< in/out: memory heap */
358
const char* file, /*!< in: file name where called */
359
ulint line); /*!< in: line number where called */
361
#define rec_get_offsets(rec,index,offsets,n,heap) \
362
rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
364
/******************************************************//**
365
Determine the offset to each field in a leaf-page record
366
in ROW_FORMAT=COMPACT. This is a special case of
367
rec_init_offsets() and rec_get_offsets_func(). */
370
rec_init_offsets_comp_ordinary(
371
/*===========================*/
372
const rec_t* rec, /*!< in: physical record in
373
ROW_FORMAT=COMPACT */
374
ulint extra, /*!< in: number of bytes to reserve
375
between the record header and
377
(usually REC_N_NEW_EXTRA_BYTES) */
378
const dict_index_t* index, /*!< in: record descriptor */
379
ulint* offsets);/*!< in/out: array of offsets;
380
in: n=rec_offs_n_fields(offsets) */
382
/******************************************************//**
383
The following function determines the offsets to each field
384
in the record. It can reuse a previously allocated array. */
387
rec_get_offsets_reverse(
388
/*====================*/
389
const byte* extra, /*!< in: the extra bytes of a
390
compact record in reverse order,
391
excluding the fixed-size
392
REC_N_NEW_EXTRA_BYTES */
393
const dict_index_t* index, /*!< in: record descriptor */
394
ulint node_ptr,/*!< in: nonzero=node pointer,
396
ulint* offsets);/*!< in/out: array consisting of
397
offsets[0] allocated elements */
399
/************************************************************//**
400
Validates offsets returned by rec_get_offsets().
401
@return TRUE if valid */
406
const rec_t* rec, /*!< in: record or NULL */
407
const dict_index_t* index, /*!< in: record descriptor or NULL */
408
const ulint* offsets);/*!< in: array returned by
411
/************************************************************//**
412
Updates debug data in offsets, in order to avoid bogus
413
rec_offs_validate() failures. */
418
const rec_t* rec, /*!< in: record */
419
const dict_index_t* index, /*!< in: record descriptor */
420
ulint* offsets);/*!< in: array returned by
423
# define rec_offs_make_valid(rec, index, offsets) ((void) 0)
424
#endif /* UNIV_DEBUG */
426
/************************************************************//**
427
The following function is used to get the offset to the nth
428
data field in an old-style record.
429
@return offset to the field */
432
rec_get_nth_field_offs_old(
433
/*=======================*/
434
const rec_t* rec, /*!< in: record */
435
ulint n, /*!< in: index of the field */
436
ulint* len); /*!< out: length of the field; UNIV_SQL_NULL
438
#define rec_get_nth_field_old(rec, n, len) \
439
((rec) + rec_get_nth_field_offs_old(rec, n, len))
440
/************************************************************//**
441
Gets the physical size of an old-style field.
442
Also an SQL null may have a field of size > 0,
443
if the data type is of a fixed size.
444
@return field size in bytes */
447
rec_get_nth_field_size(
448
/*===================*/
449
const rec_t* rec, /*!< in: record */
450
ulint n); /*!< in: index of the field */
451
/************************************************************//**
452
The following function is used to get an offset to the nth
453
data field in a record.
454
@return offset from the origin of rec */
457
rec_get_nth_field_offs(
458
/*===================*/
459
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
460
ulint n, /*!< in: index of the field */
461
ulint* len); /*!< out: length of the field; UNIV_SQL_NULL
463
#define rec_get_nth_field(rec, offsets, n, len) \
464
((rec) + rec_get_nth_field_offs(offsets, n, len))
465
/******************************************************//**
466
Determine if the offsets are for a record in the new
468
@return nonzero if compact format */
473
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
474
/******************************************************//**
475
Determine if the offsets are for a record containing
476
externally stored columns.
477
@return nonzero if externally stored */
482
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
483
/******************************************************//**
484
Returns nonzero if the extern bit is set in nth field of rec.
485
@return nonzero if externally stored */
490
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
491
ulint n); /*!< in: nth field */
492
/******************************************************//**
493
Returns nonzero if the SQL NULL bit is set in nth field of rec.
494
@return nonzero if SQL NULL */
497
rec_offs_nth_sql_null(
498
/*==================*/
499
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
500
ulint n); /*!< in: nth field */
501
/******************************************************//**
502
Gets the physical size of a field.
503
@return length of field */
508
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
509
ulint n); /*!< in: nth field */
511
/******************************************************//**
512
Returns the number of extern bits set in a record.
513
@return number of externally stored fields */
518
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
519
/***********************************************************//**
520
This is used to modify the value of an already existing field in a record.
521
The previous value must have exactly the same size as the new value. If len
522
is UNIV_SQL_NULL then the field is treated as an SQL null.
523
For records in ROW_FORMAT=COMPACT (new-style records), len must not be
524
UNIV_SQL_NULL unless the field already is SQL null. */
529
rec_t* rec, /*!< in: record */
530
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
531
ulint n, /*!< in: index number of the field */
532
const void* data, /*!< in: pointer to the data if not SQL null */
533
ulint len); /*!< in: length of the data or UNIV_SQL_NULL */
534
/**********************************************************//**
535
The following function returns the data size of an old-style physical
536
record, that is the sum of field lengths. SQL null fields
537
are counted as length 0 fields. The value returned by the function
538
is the distance from record origin to record end in bytes.
542
rec_get_data_size_old(
543
/*==================*/
544
const rec_t* rec); /*!< in: physical record */
545
/**********************************************************//**
546
The following function returns the number of allocated elements
547
for an array of offsets.
548
@return number of elements */
551
rec_offs_get_n_alloc(
552
/*=================*/
553
const ulint* offsets);/*!< in: array for rec_get_offsets() */
554
/**********************************************************//**
555
The following function sets the number of allocated elements
556
for an array of offsets. */
559
rec_offs_set_n_alloc(
560
/*=================*/
561
ulint* offsets, /*!< out: array for rec_get_offsets(),
563
ulint n_alloc); /*!< in: number of elements */
564
#define rec_offs_init(offsets) \
565
rec_offs_set_n_alloc(offsets, (sizeof offsets) / sizeof *offsets)
566
/**********************************************************//**
567
The following function returns the number of fields in a record.
568
@return number of fields */
573
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
574
/**********************************************************//**
575
The following function returns the data size of a physical
576
record, that is the sum of field lengths. SQL null fields
577
are counted as length 0 fields. The value returned by the function
578
is the distance from record origin to record end in bytes.
584
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
585
/**********************************************************//**
586
Returns the total size of record minus data size of record.
587
The value returned by the function is the distance from record
588
start to record origin in bytes.
594
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
595
/**********************************************************//**
596
Returns the total size of a physical record.
602
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
603
/**********************************************************//**
604
Returns a pointer to the start of the record.
605
@return pointer to start */
610
rec_t* rec, /*!< in: pointer to record */
611
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
612
/**********************************************************//**
613
Returns a pointer to the end of the record.
614
@return pointer to end */
619
rec_t* rec, /*!< in: pointer to record */
620
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
621
/***************************************************************//**
622
Copies a physical record to a buffer.
623
@return pointer to the origin of the copy */
628
void* buf, /*!< in: buffer */
629
const rec_t* rec, /*!< in: physical record */
630
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
631
#ifndef UNIV_HOTBACKUP
632
/**************************************************************//**
633
Copies the first n fields of a physical record to a new physical record in
635
@return own: copied record */
638
rec_copy_prefix_to_buf(
639
/*===================*/
640
const rec_t* rec, /*!< in: physical record */
641
const dict_index_t* index, /*!< in: record descriptor */
642
ulint n_fields, /*!< in: number of fields
644
byte** buf, /*!< in/out: memory buffer
645
for the copied prefix,
647
ulint* buf_size); /*!< in/out: buffer size */
648
/************************************************************//**
649
Folds a prefix of a physical record to a ulint.
650
@return the folded value */
655
const rec_t* rec, /*!< in: the physical record */
656
const ulint* offsets, /*!< in: array returned by
658
ulint n_fields, /*!< in: number of complete
660
ulint n_bytes, /*!< in: number of bytes to fold
661
in an incomplete last field */
662
index_id_t tree_id) /*!< in: index tree id */
663
__attribute__((pure));
664
#endif /* !UNIV_HOTBACKUP */
665
/*********************************************************//**
666
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
669
rec_convert_dtuple_to_rec_comp(
670
/*===========================*/
671
rec_t* rec, /*!< in: origin of record */
672
ulint extra, /*!< in: number of bytes to
673
reserve between the record
674
header and the data payload
675
(normally REC_N_NEW_EXTRA_BYTES) */
676
const dict_index_t* index, /*!< in: record descriptor */
677
ulint status, /*!< in: status bits of the record */
678
const dfield_t* fields, /*!< in: array of data fields */
679
ulint n_fields);/*!< in: number of data fields */
680
/*********************************************************//**
681
Builds a physical record out of a data tuple and
682
stores it into the given buffer.
683
@return pointer to the origin of physical record */
686
rec_convert_dtuple_to_rec(
687
/*======================*/
688
byte* buf, /*!< in: start address of the
690
const dict_index_t* index, /*!< in: record descriptor */
691
const dtuple_t* dtuple, /*!< in: data tuple */
692
ulint n_ext); /*!< in: number of
693
externally stored columns */
694
/**********************************************************//**
695
Returns the extra size of an old-style physical record if we know its
696
data size and number of fields.
697
@return extra size */
700
rec_get_converted_extra_size(
701
/*=========================*/
702
ulint data_size, /*!< in: data size */
703
ulint n_fields, /*!< in: number of fields */
704
ulint n_ext) /*!< in: number of externally stored columns */
705
__attribute__((const));
706
/**********************************************************//**
707
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
708
@return total size */
711
rec_get_converted_size_comp_prefix(
712
/*===============================*/
713
const dict_index_t* index, /*!< in: record descriptor;
714
dict_table_is_comp() is
715
assumed to hold, even if
717
const dfield_t* fields, /*!< in: array of data fields */
718
ulint n_fields,/*!< in: number of data fields */
719
ulint* extra); /*!< out: extra size */
720
/**********************************************************//**
721
Determines the size of a data tuple in ROW_FORMAT=COMPACT.
722
@return total size */
725
rec_get_converted_size_comp(
726
/*========================*/
727
const dict_index_t* index, /*!< in: record descriptor;
728
dict_table_is_comp() is
729
assumed to hold, even if
731
ulint status, /*!< in: status bits of the record */
732
const dfield_t* fields, /*!< in: array of data fields */
733
ulint n_fields,/*!< in: number of data fields */
734
ulint* extra); /*!< out: extra size */
735
/**********************************************************//**
736
The following function returns the size of a data tuple when converted to
741
rec_get_converted_size(
742
/*===================*/
743
dict_index_t* index, /*!< in: record descriptor */
744
const dtuple_t* dtuple, /*!< in: data tuple */
745
ulint n_ext); /*!< in: number of externally stored columns */
746
#ifndef UNIV_HOTBACKUP
747
/**************************************************************//**
748
Copies the first n fields of a physical record to a data tuple.
749
The fields are copied to the memory heap. */
752
rec_copy_prefix_to_dtuple(
753
/*======================*/
754
dtuple_t* tuple, /*!< out: data tuple */
755
const rec_t* rec, /*!< in: physical record */
756
const dict_index_t* index, /*!< in: record descriptor */
757
ulint n_fields, /*!< in: number of fields
759
mem_heap_t* heap); /*!< in: memory heap */
760
#endif /* !UNIV_HOTBACKUP */
761
/***************************************************************//**
762
Validates the consistency of a physical record.
763
@return TRUE if ok */
768
const rec_t* rec, /*!< in: physical record */
769
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
770
/***************************************************************//**
771
Prints an old-style physical record. */
776
FILE* file, /*!< in: file where to print */
777
const rec_t* rec); /*!< in: physical record */
778
#ifndef UNIV_HOTBACKUP
779
/***************************************************************//**
780
Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
786
FILE* file, /*!< in: file where to print */
787
const rec_t* rec, /*!< in: physical record */
788
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
789
/***************************************************************//**
790
Prints a physical record. */
795
FILE* file, /*!< in: file where to print */
796
const rec_t* rec, /*!< in: physical record */
797
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
798
/***************************************************************//**
799
Prints a physical record. */
804
FILE* file, /*!< in: file where to print */
805
const rec_t* rec, /*!< in: physical record */
806
const dict_index_t* index); /*!< in: record descriptor */
807
#endif /* UNIV_HOTBACKUP */
809
#define REC_INFO_BITS 6 /* This is single byte bit-field */
811
/* Maximum lengths for the data in a physical record if the offsets
812
are given in one byte (resp. two byte) format. */
813
#define REC_1BYTE_OFFS_LIMIT 0x7FUL
814
#define REC_2BYTE_OFFS_LIMIT 0x7FFFUL
816
/* The data size of record must be smaller than this because we reserve
817
two upmost bits in a two byte offset for special purposes */
818
#define REC_MAX_DATA_SIZE (16 * 1024)
821
#include "rem0rec.ic"