MySQL 9.1.0
Source Code Documentation
rec.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1994, 2024, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file rem/rec.h
29 Record manager
30
31 Created 5/30/1994 Heikki Tuuri
32 *************************************************************************/
33
34/** NOTE: The functions in this file should only use functions from
35other files in library. The code in this file is used to make a library for
36external tools. */
37
38/**
39Extra Bytes in Redudant Row Format
40
41The extra bytes of the redundant row format (old row format) is explained here.
42It contains a total of 6 bytes that occurs before the record origin. These
43bits and bytes are accessed with reference to the record origin. So when we
44say 3rd byte, it means that it is 3rd byte from the record origin.
45
46 byte 6 byte 5 byte 4 byte 3 byte 2 byte 1
47[iiiioooo][hhhhhhhh][hhhhhfff][fffffffs][pppppppp][pppppppp]+
48
491. The + is the record origin.
502. The next record pointer is given by the bits marked as 'p'. This takes
51 2 bytes - 1st and 2nd byte.
523. One bit is used to indicate whether the field offsets array uses 1 byte or
53 2 bytes each. This is given by the bit 's' in 3rd byte.
544. The total number of fields is given by the bits marked as 'f'. It spans
55 the 4th and 3rd bytes. It uses a total of 10 bits.
565. The heap number of the record is given by the bits marked as 'h'. It spans
57 the 5th and 4th bytes. It uses a total of 13 bits.
586. The record owned (by dir slot) information is given by bits marked as 'o'.
59 It uses a total of 4 bits. It is available in the 6th byte.
607. The info bits are given by the bits marked as 'i'. It uses a total of 4
61 bits. It is available in the 6th byte.
62*/
63
64#ifndef rem_rec_h
65#define rem_rec_h
66
67#include "dict0boot.h"
68#include "dict0dict.h"
69
70/* Compact flag ORed to the extra size returned by rec_get_offsets() */
71constexpr uint32_t REC_OFFS_COMPACT = 1U << 31;
72/* SQL NULL flag in offsets returned by rec_get_offsets() */
73constexpr uint32_t REC_OFFS_SQL_NULL = 1U << 31;
74/* External flag in offsets returned by rec_get_offsets() */
75constexpr uint32_t REC_OFFS_EXTERNAL = 1 << 30;
76/* Default value flag in offsets returned by rec_get_offsets() */
77constexpr uint32_t REC_OFFS_DEFAULT = 1 << 29;
78/* An INSTANT DROP flag in offsets returned by rec_get_offsets() */
79constexpr uint32_t REC_OFFS_DROP = 1 << 28;
80/* Mask for offsets returned by rec_get_offsets() */
81constexpr uint32_t REC_OFFS_MASK = REC_OFFS_DROP - 1;
82
83/* The offset of heap_no in a compact record */
84constexpr uint32_t REC_NEW_HEAP_NO = 4;
85/* The shift of heap_no in a compact record.
86The status is stored in the low-order bits. */
87constexpr uint32_t REC_HEAP_NO_SHIFT = 3;
88
89/* We list the byte offsets from the origin of the record, the mask,
90and the shift needed to obtain each bit-field of the record. */
91
92constexpr uint32_t REC_NEXT = 2;
93constexpr uint32_t REC_NEXT_MASK = 0xFFFFUL;
94constexpr uint32_t REC_NEXT_SHIFT = 0;
95
96constexpr uint32_t REC_OLD_SHORT = 3; /* This is single byte bit-field */
97constexpr uint32_t REC_OLD_SHORT_MASK = 0x1UL;
98constexpr uint32_t REC_OLD_SHORT_SHIFT = 0;
99
100constexpr uint32_t REC_OLD_N_FIELDS = 4;
101constexpr uint32_t REC_OLD_N_FIELDS_MASK = 0x7FEUL;
102constexpr uint32_t REC_OLD_N_FIELDS_SHIFT = 1;
103
104constexpr uint32_t REC_NEW_STATUS = 3; /* This is single byte bit-field */
105constexpr uint32_t REC_NEW_STATUS_MASK = 0x7UL;
106constexpr uint32_t REC_NEW_STATUS_SHIFT = 0;
107
108constexpr uint32_t REC_OLD_HEAP_NO = 5;
109constexpr uint32_t REC_HEAP_NO_MASK = 0xFFF8UL;
110#if 0 /* defined in rem0rec.h for use of page0zip.cc */
111#define REC_NEW_HEAP_NO 4
112#define REC_HEAP_NO_SHIFT 3
113#endif
114
115constexpr uint32_t REC_OLD_N_OWNED = 6; /* This is single byte bit-field */
116constexpr uint32_t REC_NEW_N_OWNED = 5; /* This is single byte bit-field */
117constexpr uint32_t REC_N_OWNED_MASK = 0xFUL;
118constexpr uint32_t REC_N_OWNED_SHIFT = 0;
119
120constexpr uint32_t REC_OLD_INFO_BITS = 6; /* This is single byte bit-field */
121constexpr uint32_t REC_NEW_INFO_BITS = 5; /* This is single byte bit-field */
122constexpr uint32_t REC_TMP_INFO_BITS = 1; /* This is single byte bit-field */
123constexpr uint32_t REC_INFO_BITS_MASK = 0xF0UL;
124constexpr uint32_t REC_INFO_BITS_SHIFT = 0;
125
126static_assert((REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) ^
128 REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) ^
129 REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) ^
131 0xFFFFFFFFUL) == 0,
132 "sum of old-style masks != 0xFFFFFFFFUL");
133static_assert((REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) ^
134 REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) ^
135 REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) ^
137 0xFFFFFFUL) == 0,
138 "sum of new-style masks != 0xFFFFFFUL");
139
140/* Info bit denoting the predefined minimum record: this bit is set
141if and only if the record is the first user record on a non-leaf
142B-tree page that is the leftmost page on its level
143(PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
144constexpr uint32_t REC_INFO_MIN_REC_FLAG = 0x10UL;
145/** The deleted flag in info bits; when bit is set to 1, it means the record has
146 been delete marked */
147constexpr uint32_t REC_INFO_DELETED_FLAG = 0x20UL;
148/* Use this bit to indicate record has version */
149constexpr uint32_t REC_INFO_VERSION_FLAG = 0x40UL;
150/** The instant ADD COLUMN flag. When it is set to 1, it means this record
151was inserted/updated after an instant ADD COLUMN. */
152constexpr uint32_t REC_INFO_INSTANT_FLAG = 0x80UL;
153
154/* Number of extra bytes in an old-style record,
155in addition to the data and the offsets */
156constexpr uint32_t REC_N_OLD_EXTRA_BYTES = 6;
157/* Number of extra bytes in a new-style record,
158in addition to the data and the offsets */
159constexpr int32_t REC_N_NEW_EXTRA_BYTES = 5;
160/* Number of extra bytes in a new-style temporary record,
161in addition to the data and the offsets.
162This is used only after instant ADD COLUMN. */
163constexpr uint32_t REC_N_TMP_EXTRA_BYTES = 1;
164
165#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
166/** Maximum number of records in a page */
168
169/* We use decltype(A.load()) not decltype(A)::value_type, as some compilers
170don't have it implemented, even as they should have this with the C++17
171implementation. Maybe this will be available on all compilers with C++20. */
172static_assert(MAX_REC_PER_PAGE <=
173 std::numeric_limits<
174 decltype(buf_block_t::ahi_t::n_pointers.load())>::max());
175
176#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
177
178/* Record status values */
179constexpr uint32_t REC_STATUS_ORDINARY = 0;
180constexpr uint32_t REC_STATUS_NODE_PTR = 1;
181constexpr uint32_t REC_STATUS_INFIMUM = 2;
182constexpr uint32_t REC_STATUS_SUPREMUM = 3;
183
184/* The following four constants are needed in page0zip.cc in order to
185efficiently compress and decompress pages. */
186
187/* Length of a B-tree node pointer, in bytes */
188constexpr uint32_t REC_NODE_PTR_SIZE = 4;
189
190/** SQL null flag in a 1-byte offset of ROW_FORMAT=REDUNDANT records */
191constexpr uint32_t REC_1BYTE_SQL_NULL_MASK = 0x80UL;
192/** SQL null flag in a 2-byte offset of ROW_FORMAT=REDUNDANT records */
193constexpr uint32_t REC_2BYTE_SQL_NULL_MASK = 0x8000UL;
194
195/** In a 2-byte offset of ROW_FORMAT=REDUNDANT records, the second most
196significant bit denotes that the tail of a field is stored off-page. */
197constexpr uint32_t REC_2BYTE_EXTERN_MASK = 0x4000UL;
198
199#ifdef UNIV_DEBUG
200/* Length of the rec_get_offsets() header */
201constexpr uint32_t REC_OFFS_HEADER_SIZE = 4;
202#else /* UNIV_DEBUG */
203/* Length of the rec_get_offsets() header */
204constexpr uint32_t REC_OFFS_HEADER_SIZE = 2;
205#endif /* UNIV_DEBUG */
206
207/* Number of elements that should be initially allocated for the
208offsets[] array, first passed to rec_get_offsets() */
209constexpr uint32_t REC_OFFS_NORMAL_SIZE = 100;
210constexpr uint32_t REC_OFFS_SMALL_SIZE = 10;
211
212/** Instant state of a record. Determined by instant and version bit in info
213 * bits. */
215 /* Record is neither instant nor versioned: Instant: 0, Version: 0 */
217 /* Record is versioned but not instant: Instant: 0, Version: 1 */
219 /* Record is instant but not versioned: Instant: 1, Version: 0 */
221};
222
223/* Get the base address of offsets. The extra_size is stored at
224this position, and following positions hold the end offsets of
225the fields. */
226
227static inline const ulint *rec_offs_base(const ulint *offsets) {
228 return offsets + REC_OFFS_HEADER_SIZE;
229}
230
231static inline ulint *rec_offs_base(ulint *offsets) {
232 return offsets + REC_OFFS_HEADER_SIZE;
233}
234
235/** Number of fields flag which means it occupies two bytes */
236static const uint8_t REC_N_FIELDS_TWO_BYTES_FLAG = 0x80;
237
238/** Max number of fields which can be stored in one byte */
239static const uint8_t REC_N_FIELDS_ONE_BYTE_MAX = 0x7F;
240
241/** The following function determines the offsets to each field
242 in the record. It can reuse a previously allocated array.
243 Note that after instant ADD COLUMN, if this is a record
244 from clustered index, fields in the record may be less than
245 the fields defined in the clustered index. So the offsets
246 size is allocated according to the clustered index fields.
247 @param[in] rec physical record
248 @param[in] index record descriptor
249 @param[in,out] offsets array consisting of offsets[0] allocated elements, or an
250 array from rec_get_offsets(), or NULL
251 @param[in] n_fields maximum number of initialized fields (ULINT_UNDEFINED is
252 all fields)
253 @param[in] location location where called
254 @param[in,out] heap memory heap
255 @return the new offsets */
256[[nodiscard]] ulint *rec_get_offsets(const rec_t *rec,
257 const dict_index_t *index, ulint *offsets,
258 ulint n_fields, ut::Location location,
259 mem_heap_t **heap);
260
261/** The following function determines the offsets to each field
262 in the record. It can reuse a previously allocated array. */
264 const byte *extra, /*!< in: the extra bytes of a
265 compact record in reverse order,
266 excluding the fixed-size
267 REC_N_NEW_EXTRA_BYTES */
268 const dict_index_t *index, /*!< in: record descriptor */
269 ulint node_ptr, /*!< in: nonzero=node pointer,
270 0=leaf node */
271 ulint *offsets); /*!< in/out: array consisting of
272 offsets[0] allocated elements */
273
274/** Gets a bit field from within 1 byte. */
276 const rec_t *rec, /*!< in: pointer to record origin */
277 ulint offs, /*!< in: offset from the origin down */
278 ulint mask, /*!< in: mask used to filter bits */
279 ulint shift) /*!< in: shift right applied after masking */
280{
281 ut_ad(rec);
282
283 return ((mach_read_from_1(rec - offs) & mask) >> shift);
284}
285
286/** Gets a bit field from within 2 bytes. */
287static inline uint16_t rec_get_bit_field_2(
288 const rec_t *rec, /*!< in: pointer to record origin */
289 ulint offs, /*!< in: offset from the origin down */
290 ulint mask, /*!< in: mask used to filter bits */
291 ulint shift) /*!< in: shift right applied after masking */
292{
293 ut_ad(rec);
294
295 return ((mach_read_from_2(rec - offs) & mask) >> shift);
296}
297
298/** The following function retrieves the status bits of a new-style record.
299 @return status bits */
300[[nodiscard]] static inline ulint rec_get_status(
301 const rec_t *rec) /*!< in: physical record */
302{
303 ulint ret;
304
305 ut_ad(rec);
306
309 ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
310
311 return (ret);
312}
313
314#ifdef UNIV_DEBUG
315/** Check if the info bits are valid.
316@param[in] bits info bits to check
317@return true if valid */
318inline bool rec_info_bits_valid(ulint bits) {
319 return (0 == (bits & ~(REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG |
321}
322#endif /* UNIV_DEBUG */
323
324/** The following function is used to retrieve the info bits of a record.
325@param[in] rec physical record
326@param[in] comp nonzero=compact page format
327@return info bits */
328static inline ulint rec_get_info_bits(const rec_t *rec, ulint comp) {
329 const ulint val =
333 return (val);
334}
335
336/** The following function is used to retrieve the info bits of a temporary
337record.
338@param[in] rec physical record
339@return info bits */
340static inline ulint rec_get_info_bits_temp(const rec_t *rec) {
341 const ulint val = rec_get_bit_field_1(
344 return (val);
345}
346
347/** The following function is used to get the number of fields
348 in an old-style record, which is stored in the rec
349 @return number of data fields */
350[[nodiscard]] static inline uint16_t rec_get_n_fields_old_raw(
351 const rec_t *rec) /*!< in: physical record */
352{
353 uint16_t n_fields;
354
355 ut_ad(rec);
356
359
360 ut_ad(n_fields <= REC_MAX_N_FIELDS);
361 ut_ad(n_fields > 0);
362
363 return (n_fields);
364}
365
366/** The following function is used to get the number of fields
367in an old-style record. Have to consider the case that after
368instant ADD COLUMN, this record may have less fields than
369current index.
370@param[in] rec physical record
371@param[in] index index where the record resides
372@return number of data fields */
373[[nodiscard]] static inline uint16_t rec_get_n_fields_old(
374 const rec_t *rec, const dict_index_t *index) {
375 uint16_t n = rec_get_n_fields_old_raw(rec);
376
378 if (strcmp(index->name, RECOVERY_INDEX_TABLE_NAME) == 0) {
379 /* In recovery, index is not completely built. Skip validation. */
380 if (n > 1) /* For infimum/supremum, n is 1 */ {
381 n = static_cast<uint16_t>(dict_index_get_n_fields(index));
382 }
383 return n;
384 }
385
386 uint16_t n_uniq = dict_index_get_n_unique_in_tree_nonleaf(index);
387
388 ut_ad(index->is_clustered());
390 ut_ad(n_uniq > 0);
391 /* Only when it's infimum or supremum, n is 1.
392 If n is exact n_uniq, this should be a record copied with prefix during
393 search.
394 And if it's node pointer, n is n_uniq + 1, which should be always less
395 than the number of fields in any leaf page, even if the record in
396 leaf page is before instant ADD COLUMN. This is because any record in
397 leaf page must have at least n_uniq + 2 (system columns) fields */
398 ut_ad(n == 1 || n >= n_uniq);
399 ut_ad(static_cast<uint16_t>(dict_index_get_n_fields(index)) > n_uniq + 1);
400 if (n > n_uniq + 1) {
401 /* This is leaf node. If table has INSTANT columns, then it is possible
402 that record might not have all the fields in index. So get it now from
403 index. */
404#ifdef UNIV_DEBUG
405 if (index->has_instant_cols() && !index->has_row_versions()) {
407 ulint rec_diff = dict_index_get_n_fields(index) - n;
408 ulint col_diff = index->table->n_cols - index->table->n_instant_cols;
409 ut_ad(rec_diff <= col_diff);
410 }
411
412 if (n != dict_index_get_n_fields(index)) {
414 }
415#endif /* UNIV_DEBUG */
416 n = static_cast<uint16_t>(dict_index_get_n_fields(index));
417 }
418 }
419
420 return (n);
421}
422
423/** The following function is used to get the number of fields
424 in a record. If it's REDUNDANT record, the returned number
425 would be a logic one which considers the fact that after
426 instant ADD COLUMN, some records may have less fields than
427 index.
428 @return number of data fields */
430 const rec_t *rec, /*!< in: physical record */
431 const dict_index_t *index) /*!< in: record descriptor */
432{
433 ut_ad(rec);
434 ut_ad(index);
435
436 if (!dict_table_is_comp(index->table)) {
437 return (rec_get_n_fields_old(rec, index));
438 }
439
440 switch (rec_get_status(rec)) {
442 return (dict_index_get_n_fields(index));
444 return (dict_index_get_n_unique_in_tree(index) + 1);
447 return (1);
448 default:
449 ut_error;
450 }
451}
452
453/** Confirms the n_fields of the entry is sane with comparing the other
454record in the same page specified
455@param[in] index index
456@param[in] rec record of the same page
457@param[in] entry index entry
458@return true if n_fields is sane */
459static inline bool rec_n_fields_is_sane(dict_index_t *index, const rec_t *rec,
460 const dtuple_t *entry) {
461 return (rec_get_n_fields(rec, index) == dtuple_get_n_fields(entry)
462 /* a record for older SYS_INDEXES table
463 (missing merge_threshold column) is acceptable. */
464 || (index->table->id == DICT_INDEXES_ID &&
465 rec_get_n_fields(rec, index) == dtuple_get_n_fields(entry) - 1));
466}
467
468/** The following function returns the number of allocated elements
469 for an array of offsets.
470 @return number of elements */
471[[nodiscard]] static inline ulint rec_offs_get_n_alloc(
472 const ulint *offsets) /*!< in: array for rec_get_offsets() */
473{
474 ulint n_alloc;
475 ut_ad(offsets);
476 n_alloc = offsets[0];
477 ut_ad(n_alloc > REC_OFFS_HEADER_SIZE);
478 UNIV_MEM_ASSERT_W(offsets, n_alloc * sizeof *offsets);
479 return (n_alloc);
480}
481
482/** The following function sets the number of allocated elements
483 for an array of offsets. */
484static inline void rec_offs_set_n_alloc(
485 ulint *offsets, /*!< out: array for rec_get_offsets(),
486 must be allocated */
487 ulint n_alloc) /*!< in: number of elements */
488{
489 ut_ad(offsets);
490 ut_ad(n_alloc > REC_OFFS_HEADER_SIZE);
491 UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
492 offsets[0] = n_alloc;
493}
494
495/** The following function sets the number of fields in offsets. */
496static inline void rec_offs_set_n_fields(
497 ulint *offsets, /*!< in/out: array returned by
498 rec_get_offsets() */
499 ulint n_fields) /*!< in: number of fields */
500{
501 ut_ad(offsets);
502 ut_ad(n_fields > 0);
503 ut_ad(n_fields <= REC_MAX_N_FIELDS);
504 ut_ad(n_fields + REC_OFFS_HEADER_SIZE <= rec_offs_get_n_alloc(offsets));
505 offsets[1] = n_fields;
506}
507
508/** The following function returns the number of fields in a record.
509 @return number of fields */
510[[nodiscard]] static inline ulint rec_offs_n_fields(
511 const ulint *offsets) /*!< in: array returned by rec_get_offsets() */
512{
513 ulint n_fields;
514 ut_ad(offsets);
515 n_fields = offsets[1];
516 ut_ad(n_fields > 0);
517 ut_ad(n_fields <= REC_MAX_N_FIELDS);
518 ut_ad(n_fields + REC_OFFS_HEADER_SIZE <= rec_offs_get_n_alloc(offsets));
519 return (n_fields);
520}
521
522/** Determine the offset of a specified field in the record, when this
523field is a field added after an instant ADD COLUMN
524@param[in] index Clustered index where the record resides
525@param[in] n Nth field to get offset
526@param[in] offs Last offset before current field
527@return The offset of the specified field */
528static inline uint64_t rec_get_instant_offset(const dict_index_t *index,
529 ulint n, uint64_t offs) {
531
533 index->get_nth_default(n, &length);
534
535 if (length == UNIV_SQL_NULL) {
536 return (offs | REC_OFFS_DEFAULT | REC_OFFS_SQL_NULL);
537 } else {
538 return (offs | REC_OFFS_DEFAULT);
539 }
540}
541
542/** The following function determines the offsets to each field in the record.
543The offsets are written to a previously allocated array of ulint, where
544rec_offs_n_fields(offsets) has been initialized to the number of fields in the
545record. The rest of the array will be initialized by this function.
546- rec_offs_base(offsets)[0] will be set to the extra size
547 (if REC_OFFS_COMPACT is set, the record is in the new format;
548 if REC_OFFS_EXTERNAL is set, the record contains externally stored columns).
549- rec_offs_base(offsets)[1..n_fields] will be set to offsets past the end of
550 fields 0..n_fields, or to the beginning of fields 1..n_fields+1.
551- If the high-order bit of the offset at [i+1] is set (REC_OFFS_SQL_NULL),
552 the field i is NULL.
553- If the second high-order bit of the offset at [i+1] is set
554(REC_OFFS_EXTERNAL), the field i is being stored externally.
555@param[in] rec physical record
556@param[in] index record descriptor
557@param[in,out] offsets array of offsets */
558void rec_init_offsets(const rec_t *rec, const dict_index_t *index,
559 ulint *offsets);
560
561#ifdef UNIV_DEBUG
562/** Validates offsets returned by rec_get_offsets().
563@param[in] rec record whose offsets are being validated or nullptr.
564@param[in] index index to which record belongs or nullptr.
565@param[in] offsets the record offsets array returned by rec_get_offsets()
566@param[in] check_status if true, check status bits of the record.
567@return true if valid */
568[[nodiscard]] static inline bool rec_offs_validate(
569 const rec_t *rec, const dict_index_t *index, const ulint *offsets,
570 const bool check_status = true) {
571 ulint i = rec_offs_n_fields(offsets);
572 ulint last = ULINT_MAX;
573 ulint comp = *rec_offs_base(offsets) & REC_OFFS_COMPACT;
574
575 if (rec) {
576 /* The offsets array might be:
577 - specific to the `rec`, in which case its address is stored in offsets[2],
578 - cached and shared by many records, in which case we've passed rec=nullptr
579 when preparing the offsets array.
580 We use caching only for the ROW_FORMAT=COMPACT format. */
581 ut_ad((ulint)rec == offsets[2] || ((ulint) nullptr == offsets[2] &&
582 offsets == index->rec_cache.offsets));
583 if (!comp && index != nullptr) {
584 ut_a(rec_get_n_fields_old(rec, index) >= i);
585 }
586 }
587
588 if (index) {
589 ulint max_n_fields;
590 ut_ad((ulint)index == offsets[3]);
591 ulint n_fields = dict_index_get_n_fields(index);
592 ulint n_unique_in_tree = dict_index_get_n_unique_in_tree(index) + 1;
593 max_n_fields = std::max(n_fields, n_unique_in_tree);
594 if (!comp && rec != nullptr && rec_get_n_fields_old_raw(rec) < i) {
596 }
597
598 /* In the case of mrec_t the status will not be there. */
599 if (check_status) {
600 if (comp && rec) {
601 switch (rec_get_status(rec)) {
603 break;
605 max_n_fields = dict_index_get_n_unique_in_tree(index) + 1;
606 break;
609 max_n_fields = 1;
610 break;
611 default:
612 ut_error;
613 }
614 }
615 }
616
617 /* index->n_def == 0 for dummy indexes if !comp */
618 ut_a(!comp || index->n_def);
619 ut_a(!index->n_def || i <= max_n_fields);
620 }
621 while (i--) {
622 ulint curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
623 ut_a(curr <= last);
624 last = curr;
625 }
626 return true;
627}
628
629/** Updates debug data in offsets, in order to avoid bogus
630 rec_offs_validate() failures. */
631static inline void rec_offs_make_valid(
632 const rec_t *rec, /*!< in: record */
633 const dict_index_t *index, /*!< in: record descriptor */
634 ulint *offsets) /*!< in: array returned by
635 rec_get_offsets() */
636{
637 /* offsets are either intended for this particular rec, or to be cached */
638 ut_ad(rec || offsets == index->rec_cache.offsets);
639 ut_ad(index);
640 ut_ad(offsets);
641 ut_ad(rec == nullptr ||
642 rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
643 offsets[2] = (ulint)rec;
644 offsets[3] = (ulint)index;
645}
646
647/** Check if the given two record offsets are identical.
648@param[in] offsets1 field offsets of a record
649@param[in] offsets2 field offsets of a record
650@return true if they are identical, false otherwise. */
651bool rec_offs_cmp(ulint *offsets1, ulint *offsets2);
652
653/** Print the record offsets.
654@param[in] out the output stream to which offsets are printed.
655@param[in] offsets the field offsets of the record.
656@return the output stream. */
657std::ostream &rec_offs_print(std::ostream &out, const ulint *offsets);
658#else
659#define rec_offs_make_valid(rec, index, offsets) ((void)0)
660#endif /* UNIV_DEBUG */
661
662/** The following function tells if a new-style record is instant record.
663@param[in] rec new-style record
664@return true if it is instant affected */
665static inline bool rec_get_instant_flag_new(const rec_t *rec) {
666 ulint info = rec_get_info_bits(rec, true);
667 return ((info & REC_INFO_INSTANT_FLAG) != 0);
668}
669
670/** The following function tells if a new-style temp record is instant record.
671@param[in] rec new-style temp record
672@return true if it is instant affected */
673static inline bool rec_get_instant_flag_new_temp(const rec_t *rec) {
674 ulint info = rec_get_info_bits_temp(rec);
675 return ((info & REC_INFO_INSTANT_FLAG) != 0);
676}
677
678/** A simplified variant rec_init_offsets(rec, index, offsets) for the case in
679which the rec contains only fixed-length columns and non-NULL values in them,
680thus we can compute the offsets without looking at the rec. Such offsets can be
681cached and reused for many recs which don't contain NULLs.
682@see rec_init_offsets for more details
683@param[in] index The index for which we want to cache the fixed offsets
684@param[in,out] offsets The already allocated array to store the offsets.
685 It should already have been initialized with
686 rec_offs_set_n_alloc() and rec_offs_set_n_fields() before
687 the call.
688 This function will fill all the other elements. */
689inline void rec_init_fixed_offsets(const dict_index_t *index, ulint *offsets) {
691
692 rec_offs_make_valid(nullptr, index, offsets);
693 rec_offs_base(offsets)[0] =
696 const auto n_fields = rec_offs_n_fields(offsets);
697 auto field_end = rec_offs_base(offsets) + 1;
698 for (size_t i = 0; i < n_fields; i++) {
699 field_end[i] = (i ? field_end[i - 1] : 0) + index->get_field(i)->fixed_len;
700 }
701}
702
703/** The following function tells if a new-style record is versioned.
704@param[in] rec new-style (COMPACT/DYNAMIC) record
705@return true if it is versioned */
706static inline bool rec_new_is_versioned(const rec_t *rec) {
707 ulint info = rec_get_info_bits(rec, true);
708 return ((info & REC_INFO_VERSION_FLAG) != 0);
709}
710
711/** The following function tells if an old-style record is versioned.
712@param[in] rec old-style (REDUNDANT) record
713@return true if it's versioned */
714static inline bool rec_old_is_versioned(const rec_t *rec) {
715 ulint info = rec_get_info_bits(rec, false);
716 return ((info & REC_INFO_VERSION_FLAG) != 0);
717}
718
719/** The following function tells if a temporary record is versioned.
720@param[in] rec new-style temporary record
721@return true if it's instant affected */
722static inline bool rec_new_temp_is_versioned(const rec_t *rec) {
723 ulint info = rec_get_info_bits_temp(rec);
724 return ((info & REC_INFO_VERSION_FLAG) != 0);
725}
726
727/** Get the number of fields for one new style leaf page record.
728This is only needed for table after instant ADD COLUMN.
729@param[in] rec leaf page record
730@param[in] extra_bytes extra bytes of this record
731@param[in,out] length length of number of fields
732@return number of fields */
733static inline uint32_t rec_get_n_fields_instant(const rec_t *rec,
734 const ulint extra_bytes,
735 uint16_t *length) {
736 uint16_t n_fields;
737 const byte *ptr;
738
739 ptr = rec - (extra_bytes + 1);
740
741 if ((*ptr & REC_N_FIELDS_TWO_BYTES_FLAG) == 0) {
742 *length = 1;
743 return (*ptr);
744 }
745
746 *length = 2;
747 n_fields = ((*ptr-- & REC_N_FIELDS_ONE_BYTE_MAX) << 8);
748 n_fields |= *ptr;
749 ut_ad(n_fields < REC_MAX_N_FIELDS);
750 ut_ad(n_fields != 0);
751
752 return (n_fields);
753}
754
755/* For INSTANT ADD/DROP, we may have following 5 types of rec for table :
756 +----------------------------------------------------------------------------+
757 | SCENARIO | STATE |
758 |----------------------------------+------------+---------+------------------|
759 | Row property | V <= 8.0.28| Bit set | Stored on row |
760 +----------------------------------+------------+---------+------------------+
761 | INSERTED before 1st INSTANT ADD | Y | NONE | N/A |
762 |----------------------------------+------------+---------+------------------|
763 | INSERTED after 1st INSTANT ADD | Y | INSTANT | # of fields |
764 |----------------------------------+------------+---------+------------------|
765 | INSERTED before INSTANT ADD/DROP | Y | VERSION | Version = 0 |
766 |----------------------------------+------------+---------+------------------|
767 | INSERTED before INSTANT ADD/DROP | N | NONE | N/A |
768 |----------------------------------+------------+---------+------------------|
769 | INSERTED after INSTANT ADD/DROP | Y/N | VERSION | row version |
770 +----------------------------------------------------------------------------+
771*/
773 /* Record was inserted before first instant add done in the earlier
774 implementation. */
776 /* Record was inserted after first instant add done in the earlier
777 implementation. */
779 /* Record was inserted after upgrade but before first instant add done in the
780 new implementation. */
782 /* Record was inserted before first instant add/drop done in the new
783 implementation. */
785 /* Record was inserted after first instant add/drop done in the new
786 implementation. */
788 /* Record belongs to table with no verison no instant */
790 NONE
792
794 const dict_index_t *index, const rec_t *rec, bool temp) {
795 ut_ad(dict_table_is_comp(index->table) || temp);
796
797 if (!index->has_instant_cols_or_row_versions()) {
799 }
800
801 /* Position just before info-bits where version will be there if any */
802 const byte *v_ptr =
803 (byte *)rec -
805 const bool is_versioned =
807 const row_version_t version =
808 (is_versioned) ? static_cast<row_version_t>(*v_ptr) : INVALID_ROW_VERSION;
809
810 const bool is_instant = (temp) ? rec_get_instant_flag_new_temp(rec)
812
813 /* Only one of the two bits could be set */
814 DBUG_EXECUTE_IF("innodb_rec_instant_version_bit_set", {
815 ib::error() << "Record has both instant and version bit set in Table '"
816 << index->table_name << "', Index '" << index->name()
817 << "'. This indicates that the table may be corrupt. Please "
818 "run CHECK TABLE before proceeding.";
819 });
820
821 if (is_versioned && is_instant) {
822 ib::error() << "Record has both instant and version bit set in Table '"
823 << index->table_name << "', Index '" << index->name()
824 << "'. This indicates that the table may be corrupt. Please "
825 "run CHECK TABLE before proceeding.";
826 }
827 ut_ad(!is_versioned || !is_instant);
828
829 enum REC_INSERT_STATE rec_insert_state = REC_INSERT_STATE::NONE;
830 if (is_versioned) {
832 if (version == 0) {
833 ut_ad(index->has_instant_cols());
834 rec_insert_state =
836 } else {
837 ut_ad(index->has_row_versions());
839 }
840 } else if (is_instant) {
841 ut_ad(index->table->has_instant_cols());
843 } else if (index->table->has_instant_cols()) {
845 } else {
847 }
848
849 ut_ad(rec_insert_state != REC_INSERT_STATE::NONE);
850 return rec_insert_state;
851}
852
853/* Following function is to set NULLS and LENS pointers correctly for a temp
854record generated for a record from REDUNDANT FORAMT
855@param[in] index record descriptor
856@param[in,out] rec temp record
857@param[out] n_null number of nullable columns in record
858@param[out] nulls pointer to nullbit map in temp record
859@param[out] lens pointer to lens in temp record
860@returns the row version stored in record or nondefault fields in record */
862 const dict_index_t *index, const rec_t *rec, uint16_t *n_null,
863 const byte **nulls, const byte **lens, uint16_t &non_default_fields,
864 row_version_t &row_version) {
866
867 non_default_fields = static_cast<uint16_t>(dict_index_get_n_fields(index));
868
869 row_version = INVALID_ROW_VERSION;
870
871 /* Set nulls just before the record */
872 *nulls = rec - 1;
873
874 enum REC_INSERT_STATE rec_insert_state =
875 get_rec_insert_state(index, rec, true);
876
877 if (rec_insert_state == INSERTED_INTO_TABLE_WITH_NO_INSTANT_NO_VERSION) {
878 *n_null = index->n_nullable;
879 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
880 return rec_insert_state;
881 }
882
883 /* info-bits must be present. Shift nulls before that. */
884 *nulls -= REC_N_TMP_EXTRA_BYTES;
885
886 switch (rec_insert_state) {
890 *n_null = index->get_nullable_in_version(0);
891 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
892 } break;
893
896 /* Read the version information */
897 row_version = (uint8_t)(**nulls);
898 ut_a(is_valid_row_version(row_version));
899
900 /* Shift nulls before the record version */
901 *nulls -= 1;
902 *n_null = index->get_nullable_in_version(row_version);
903 } break;
904
906 default:
907 ut_a(0);
908 }
909
910 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
911 return rec_insert_state;
912}
913
914/** Determines the information about null bytes and variable length bytes
915for a new-style temporary record
916@param[in] rec physical record
917@param[in] index index where the record resides
918@param[out] nulls the start of null bytes
919@param[out] lens the start of variable length bytes
920@param[out] n_null number of null fields
921@param[out] non_default_fields non default fields from record
922@param[out] row_version row version of the record
923@return the row inserted state */
925 const rec_t *rec, const dict_index_t *index, const byte **nulls,
926 const byte **lens, uint16_t *n_null, uint16_t &non_default_fields,
927 row_version_t &row_version) {
928 /* Following is the format for TEMP record.
929 +----+----+-------------------+--------------------+
930 | OP | ES |<-- Extra info --> | F1 | F2 | ... | Fn|
931 +----+----+-------------------+--------------------+
932 |
933 v
934 +--------------------+-------+---------+-----------+
935 | LN | ... | L2 | L1 | nulls | version | info-bits |
936 +--------------------+-------+---------+-----------+
937 <------ LENS ------>
938
939 where
940 info-bits => Present iff table has INSTANT/VERSION
941 version => version number iff version bit is set.
942 */
943
944 /* Redundant format */
945 if (!dict_table_is_comp(index->table)) {
946 return init_nulls_lens_for_temp_redundant(index, rec, n_null, nulls, lens,
947 non_default_fields, row_version);
948 }
949
950 non_default_fields = static_cast<uint16_t>(dict_index_get_n_fields(index));
951
952 row_version = INVALID_ROW_VERSION;
953
954 /* Set nulls just before the record */
955 *nulls = rec - 1;
956
957 const enum REC_INSERT_STATE rec_insert_state =
958 get_rec_insert_state(index, rec, true);
959
960 if (rec_insert_state == INSERTED_INTO_TABLE_WITH_NO_INSTANT_NO_VERSION) {
961 *n_null = index->n_nullable;
962 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
963 return rec_insert_state;
964 }
965
966 /* info-bits must be present. Shift nulls before that. */
967 *nulls -= REC_N_TMP_EXTRA_BYTES;
968
969 switch (rec_insert_state) {
972 /* Read the version information */
973 row_version = (uint8_t)(**nulls);
974 ut_a(is_valid_row_version(row_version));
975
976 /* Shift nulls before the record version */
977 *nulls -= 1;
978
979 *n_null = index->get_nullable_in_version(row_version);
980 } break;
981
983 /* Row inserted after first instant ADD COLUMN V1 */
984 ut_ad(index->table->has_instant_cols());
985 uint16_t length;
986 non_default_fields =
988 ut_ad(length == 1 || length == 2);
989
990 /* Shift nulls before "number of fields" */
991 *nulls -= length;
992 *n_null = index->get_n_nullable_before(non_default_fields);
993 } break;
994
996 *n_null = index->get_nullable_before_instant_add_drop();
997 non_default_fields = index->get_instant_fields();
998 } break;
999
1001 /* Row inserted before first INSTANT ADD/DROP in V2 */
1002 *n_null = index->get_nullable_before_instant_add_drop();
1003 } break;
1004
1006 default:
1007 ut_a(0);
1008 }
1009
1010 /* Position lens */
1011 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
1012
1013 return (rec_insert_state);
1014}
1015
1016/** Determines the information about null bytes and variable length bytes
1017for a new style record
1018@param[in] rec physical record
1019@param[in] index index where the record resides
1020@param[out] nulls the start of null bytes
1021@param[out] lens the start of variable length bytes
1022@param[out] n_null number of null fields
1023@param[out] non_default_fields non default fields from record
1024@param[out] row_version row version of the record
1025@return number of fields with no default or the row version of record */
1027 const rec_t *rec, const dict_index_t *index, const byte **nulls,
1028 const byte **lens, uint16_t *n_null, uint16_t &non_default_fields,
1029 row_version_t &row_version) {
1030 non_default_fields = static_cast<uint16_t>(dict_index_get_n_fields(index));
1031
1032 row_version = INVALID_ROW_VERSION;
1033
1034 /* Position nulls */
1035 *nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1036
1037 const enum REC_INSERT_STATE rec_insert_state =
1038 get_rec_insert_state(index, rec, false);
1039
1040 switch (rec_insert_state) {
1044
1045 *n_null = index->n_nullable;
1046 } break;
1047
1050 /* Read the row version from record */
1051 row_version = (uint8_t)(**nulls);
1052 ut_ad(is_valid_row_version(row_version));
1053
1054#ifdef UNIV_DEBUG
1055 if (strcmp(index->name, RECOVERY_INDEX_TABLE_NAME) != 0) {
1056 if (row_version > 0) {
1057 /* Row inserted after first instant ADD/DROP COLUMN V2 */
1058 ut_ad(index->table->has_row_versions());
1059 } else {
1060 /* Upgraded table. Row inserted before V2 INSTANT ADD/DROP */
1061 ut_ad(index->table->is_upgraded_instant());
1062 }
1063 }
1064#endif
1065
1066 /* Reposition nulls to skip version */
1067 *nulls -= 1;
1068 *n_null = index->get_nullable_in_version(row_version);
1069 } break;
1070
1072 /* Row inserted after first instant ADD COLUMN V1 */
1073 uint16_t length;
1074 non_default_fields =
1076 ut_ad(length == 1 || length == 2);
1077
1078 /* Reposition nulls to skip number of fields */
1079 *nulls -= length;
1080 *n_null = index->calculate_n_instant_nullable(non_default_fields);
1081 } break;
1082
1084 *n_null = index->get_nullable_before_instant_add_drop();
1085 non_default_fields = index->get_instant_fields();
1086 } break;
1087
1089 /* Row inserted before first INSTANT ADD/DROP in V2 */
1090 *n_null = index->get_nullable_before_instant_add_drop();
1091 } break;
1092
1093 default:
1094 ut_ad(false);
1095 }
1096
1097 /* Position lens */
1098 *lens = *nulls - UT_BITS_IN_BYTES(*n_null);
1099
1100 /* Return record version or non_default_field stored */
1101 return (rec_insert_state);
1102}
1103
1104/** Determine the offset to each field in a leaf-page record in
1105ROW_FORMAT=COMPACT. This is a special case of rec_init_offsets() and
1106rec_get_offsets().
1107@param[in] rec physical record in ROW_FORMAT=COMPACT
1108@param[in] temp whether to use the format for temporary files in index
1109 creation
1110@param[in] index record descriptor
1111@param[in,out] offsets array of offsets
1112@note This long method is made inline because it is on performance sensitive hot
1113path. One must run performance tests if they intend to improve this method. */
1114inline void rec_init_offsets_comp_ordinary(const rec_t *rec, bool temp,
1115 const dict_index_t *index,
1116 ulint *offsets) {
1117#ifdef UNIV_DEBUG
1118 /* We cannot invoke rec_offs_make_valid() here if temp=true.
1119 Similarly, rec_offs_validate() will fail in that case, because
1120 it invokes rec_get_status(). */
1121 offsets[2] = (ulint)rec;
1122 offsets[3] = (ulint)index;
1123#endif /* UNIV_DEBUG */
1124
1125 const byte *nulls = nullptr;
1126 const byte *lens = nullptr;
1127 uint16_t n_null = 0;
1128 enum REC_INSERT_STATE rec_insert_state = REC_INSERT_STATE::NONE;
1129 row_version_t row_version = INVALID_ROW_VERSION;
1130 uint16_t non_default_fields = 0;
1131
1132 if (temp) {
1133 rec_insert_state = rec_init_null_and_len_temp(
1134 rec, index, &nulls, &lens, &n_null, non_default_fields, row_version);
1135 } else {
1136 rec_insert_state = rec_init_null_and_len_comp(
1137 rec, index, &nulls, &lens, &n_null, non_default_fields, row_version);
1138 }
1139
1140 ut_ad(temp || dict_table_is_comp(index->table));
1141
1142 if (temp) {
1143 if (dict_table_is_comp(index->table)) {
1144 /* No need to do adjust fixed_len=0. We only need to
1145 adjust it for ROW_FORMAT=REDUNDANT. */
1146 temp = false;
1147 } else {
1148 /* Redundant temp row. Old instant record is logged as version 0. */
1149 if (rec_insert_state == INSERTED_BEFORE_INSTANT_ADD_OLD_IMPLEMENTATION ||
1152 ut_ad(row_version == INVALID_ROW_VERSION);
1153 }
1154 }
1155 }
1156
1157 /* read the lengths of fields 0..n */
1158 ulint offs = 0;
1159 ulint any_ext = 0;
1160 ulint null_mask = 1;
1161 uint16_t i = 0;
1162 do {
1163 /* Fields are stored on disk in version they are added in and are
1164 maintained in fields_array in the same order. Get the right field. */
1165 const dict_field_t *field = index->get_physical_field(i);
1166 const dict_col_t *col = field->col;
1167 uint64_t len;
1168
1169 switch (rec_insert_state) {
1172 break;
1173
1175 ut_ad(row_version == INVALID_ROW_VERSION || row_version == 0);
1176 ut_ad(index->has_row_versions() || temp);
1177 /* Record has to be interpreted in v0. */
1178 row_version = 0;
1179 }
1180 [[fallthrough]];
1183 ut_ad(is_valid_row_version(row_version));
1184 /* A record may have version=0 if it's from upgrade table */
1185 ut_ad(index->has_row_versions() ||
1186 (index->table->is_upgraded_instant() && row_version == 0));
1187
1188 /* Based on the record version and column information, see if this
1189 column is there in this record or not. */
1190 if (col->is_dropped_in_or_before(row_version)) {
1191 /* This columns is dropped before or on this row version so its data
1192 won't be there on row. So no need to store the length. Instead, store
1193 offs ORed with REC_OFFS_DROP to indicate the same. */
1194 len = offs | REC_OFFS_DROP;
1195 goto resolved;
1196
1197 /* NOTE : Existing rows, which have data for this column, would still
1198 need to process this column, so don't skip and store the correct
1199 length there. Though it will be skipped while fetching row. */
1200 } else if (col->is_added_after(row_version)) {
1201 /* This columns is added after this row version. In this case no need
1202 to store the length. Instead store only if it is NULL or DEFAULT
1203 value. */
1204 len = rec_get_instant_offset(index, i, offs);
1205
1206 goto resolved;
1207 }
1208 } break;
1209
1212 ut_ad(non_default_fields > 0);
1213 ut_ad(index->has_instant_cols());
1214 ut_ad(!is_valid_row_version(row_version));
1215
1216 if (i >= non_default_fields) {
1217 /* This would be the case when column doesn't exists in the row. In
1218 this case we need not to store the length. Instead we store only if
1219 the column is NULL or DEFAULT value. */
1220 len = rec_get_instant_offset(index, i, offs);
1221
1222 goto resolved;
1223 }
1224
1225 /* Note : Even if the column has been dropped, this row in V1 would
1226 definitely have the value of this column. */
1227 } break;
1228
1229 default:
1230 ut_ad(false);
1231 }
1232
1233 if (!(col->prtype & DATA_NOT_NULL)) {
1234 /* nullable field => read the null flag */
1235 ut_ad(n_null--);
1236
1237 if (UNIV_UNLIKELY(!(byte)null_mask)) {
1238 nulls--;
1239 null_mask = 1;
1240 }
1241
1242 if (*nulls & null_mask) {
1243 null_mask <<= 1;
1244 /* No length is stored for NULL fields.
1245 We do not advance offs, and we set
1246 the length to zero and enable the
1247 SQL NULL flag in offsets[]. */
1248 len = offs | REC_OFFS_SQL_NULL;
1249 goto resolved;
1250 }
1251 null_mask <<= 1;
1252 }
1253
1254 if (!field->fixed_len || (temp && !col->get_fixed_size(temp))) {
1255 ut_ad(col->mtype != DATA_POINT);
1256 /* Variable-length field: read the length */
1257 len = *lens--;
1258 /* If the maximum length of the field is up
1259 to 255 bytes, the actual length is always
1260 stored in one byte. If the maximum length is
1261 more than 255 bytes, the actual length is
1262 stored in one byte for 0..127. The length
1263 will be encoded in two bytes when it is 128 or
1264 more, or when the field is stored externally. */
1265 if (DATA_BIG_COL(col)) {
1266 if (len & 0x80) {
1267 /* 1exxxxxxx xxxxxxxx */
1268 len <<= 8;
1269 len |= *lens--;
1270
1271 offs += len & 0x3fff;
1272 if (UNIV_UNLIKELY(len & 0x4000)) {
1273 ut_ad(index->is_clustered());
1274 any_ext = REC_OFFS_EXTERNAL;
1275 len = offs | REC_OFFS_EXTERNAL;
1276 } else {
1277 len = offs;
1278 }
1279
1280 goto resolved;
1281 }
1282 }
1283
1284 len = offs += len;
1285 } else {
1286 len = offs += field->fixed_len;
1287 }
1288 resolved:
1289 rec_offs_base(offsets)[i + 1] = len;
1290 } while (++i < rec_offs_n_fields(offsets));
1291
1292 *rec_offs_base(offsets) = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
1293}
1294
1295/** The following function is used to test whether the data offsets in the
1296 record are stored in one-byte or two-byte format.
1297 @return true if 1-byte form */
1298[[nodiscard]] static inline bool rec_get_1byte_offs_flag(
1299 const rec_t *rec) /*!< in: physical record */
1300{
1303}
1304
1305#endif
The class error is used to emit error messages.
Definition: ut0log.h:231
static ulint dtuple_get_n_fields(const dtuple_t *tuple)
Gets number of fields in a data tuple.
constexpr uint32_t DATA_POINT
geometry datatype of fixed length POINT
Definition: data0type.h:107
constexpr uint32_t DATA_NOT_NULL
this is ORed to the precise type when the column is declared as NOT NULL
Definition: data0type.h:207
#define DATA_BIG_COL(col)
Definition: data0type.h:286
Data dictionary creation and booting.
constexpr uint32_t DICT_INDEXES_ID
Definition: dict0boot.h:97
Data dictionary system.
static uint16_t dict_index_get_n_unique_in_tree_nonleaf(const dict_index_t *index)
Gets the number of fields on nonleaf page level in the internal representation of an index which uniq...
static bool dict_table_is_comp(const dict_table_t *table)
Check whether the table uses the compact page format.
static ulint dict_index_get_n_unique_in_tree(const dict_index_t *index)
Gets the number of fields in the internal representation of an index which uniquely determine the pos...
static ulint dict_index_get_n_fields(const dict_index_t *index)
Gets the number of fields in the internal representation of an index, including fields added by the d...
static bool is_valid_row_version(const row_version_t version)
Definition: dict0mem.h:422
constexpr char RECOVERY_INDEX_TABLE_NAME[]
index/table name used while applying REDO logs during recovery
Definition: dict0mem.h:89
static bool is_instant(const Alter_inplace_info *ha_alter_info)
Determine if this is an instant ALTER TABLE.
Definition: handler0alter.cc:920
static uint16_t mach_read_from_2(const byte *b)
The following function is used to fetch data from 2 consecutive bytes.
static uint8_t mach_read_from_1(const byte *b)
The following function is used to fetch data from one byte.
static mi_bit_type mask[]
Definition: mi_packrec.cc:141
#define DBUG_EXECUTE_IF(keyword, a1)
Definition: my_dbug.h:171
bool length(const dd::Spatial_reference_system *srs, const Geometry *g1, double *length, bool *null) noexcept
Computes the length of linestrings and multilinestrings.
Definition: length.cc:76
bool rec_info_bits_valid(ulint bits)
Check if the info bits are valid.
Definition: rec.h:318
constexpr uint32_t REC_INFO_INSTANT_FLAG
The instant ADD COLUMN flag.
Definition: rec.h:152
static const uint8_t REC_N_FIELDS_TWO_BYTES_FLAG
Number of fields flag which means it occupies two bytes.
Definition: rec.h:236
static uint16_t rec_get_bit_field_2(const rec_t *rec, ulint offs, ulint mask, ulint shift)
Gets a bit field from within 2 bytes.
Definition: rec.h:287
constexpr uint32_t REC_N_OWNED_MASK
Definition: rec.h:117
constexpr uint32_t REC_OFFS_EXTERNAL
Definition: rec.h:75
constexpr uint32_t REC_OFFS_HEADER_SIZE
Definition: rec.h:201
constexpr uint32_t REC_OFFS_DEFAULT
Definition: rec.h:77
constexpr uint32_t REC_NEW_HEAP_NO
Definition: rec.h:84
void rec_init_offsets_comp_ordinary(const rec_t *rec, bool temp, const dict_index_t *index, ulint *offsets)
Determine the offset to each field in a leaf-page record in ROW_FORMAT=COMPACT.
Definition: rec.h:1114
void rec_init_fixed_offsets(const dict_index_t *index, ulint *offsets)
A simplified variant rec_init_offsets(rec, index, offsets) for the case in which the rec contains onl...
Definition: rec.h:689
static enum REC_INSERT_STATE rec_init_null_and_len_temp(const rec_t *rec, const dict_index_t *index, const byte **nulls, const byte **lens, uint16_t *n_null, uint16_t &non_default_fields, row_version_t &row_version)
Determines the information about null bytes and variable length bytes for a new-style temporary recor...
Definition: rec.h:924
static bool rec_get_instant_flag_new_temp(const rec_t *rec)
The following function tells if a new-style temp record is instant record.
Definition: rec.h:673
constexpr uint32_t REC_NEXT
Definition: rec.h:92
constexpr uint32_t REC_N_OLD_EXTRA_BYTES
Definition: rec.h:156
constexpr uint32_t REC_STATUS_SUPREMUM
Definition: rec.h:182
constexpr uint32_t REC_NODE_PTR_SIZE
Definition: rec.h:188
constexpr uint32_t REC_INFO_BITS_SHIFT
Definition: rec.h:124
constexpr uint32_t REC_OFFS_DROP
Definition: rec.h:79
static enum REC_INSERT_STATE rec_init_null_and_len_comp(const rec_t *rec, const dict_index_t *index, const byte **nulls, const byte **lens, uint16_t *n_null, uint16_t &non_default_fields, row_version_t &row_version)
Determines the information about null bytes and variable length bytes for a new style record.
Definition: rec.h:1026
constexpr uint32_t REC_INFO_MIN_REC_FLAG
Definition: rec.h:144
static ulint rec_get_info_bits(const rec_t *rec, ulint comp)
The following function is used to retrieve the info bits of a record.
Definition: rec.h:328
void rec_init_offsets(const rec_t *rec, const dict_index_t *index, ulint *offsets)
The following function determines the offsets to each field in the record.
Definition: rec.cc:348
constexpr uint32_t REC_NEW_INFO_BITS
Definition: rec.h:121
constexpr uint32_t REC_OLD_INFO_BITS
Definition: rec.h:120
constexpr uint32_t REC_OFFS_MASK
Definition: rec.h:81
constexpr uint32_t REC_OLD_SHORT_MASK
Definition: rec.h:97
constexpr uint32_t REC_OLD_SHORT_SHIFT
Definition: rec.h:98
Rec_instant_state
Instant state of a record.
Definition: rec.h:214
constexpr uint32_t REC_INFO_BITS_MASK
Definition: rec.h:123
static ulint rec_get_info_bits_temp(const rec_t *rec)
The following function is used to retrieve the info bits of a temporary record.
Definition: rec.h:340
static uint64_t rec_get_instant_offset(const dict_index_t *index, ulint n, uint64_t offs)
Determine the offset of a specified field in the record, when this field is a field added after an in...
Definition: rec.h:528
static const uint8_t REC_N_FIELDS_ONE_BYTE_MAX
Max number of fields which can be stored in one byte.
Definition: rec.h:239
constexpr uint32_t REC_HEAP_NO_MASK
Definition: rec.h:109
REC_INSERT_STATE
Definition: rec.h:772
@ INSERTED_AFTER_UPGRADE_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION
Definition: rec.h:781
@ INSERTED_AFTER_INSTANT_ADD_OLD_IMPLEMENTATION
Definition: rec.h:778
@ INSERTED_AFTER_INSTANT_ADD_NEW_IMPLEMENTATION
Definition: rec.h:787
@ INSERTED_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION
Definition: rec.h:784
@ INSERTED_INTO_TABLE_WITH_NO_INSTANT_NO_VERSION
Definition: rec.h:789
@ NONE
Definition: rec.h:790
@ INSERTED_BEFORE_INSTANT_ADD_OLD_IMPLEMENTATION
Definition: rec.h:775
constexpr uint32_t REC_TMP_INFO_BITS
Definition: rec.h:122
constexpr uint32_t REC_HEAP_NO_SHIFT
Definition: rec.h:87
constexpr uint32_t REC_STATUS_ORDINARY
Definition: rec.h:179
static enum REC_INSERT_STATE get_rec_insert_state(const dict_index_t *index, const rec_t *rec, bool temp)
Definition: rec.h:793
static ulint rec_offs_get_n_alloc(const ulint *offsets)
The following function returns the number of allocated elements for an array of offsets.
Definition: rec.h:471
constexpr uint32_t REC_STATUS_INFIMUM
Definition: rec.h:181
constexpr uint32_t REC_NEW_STATUS
Definition: rec.h:104
static void rec_offs_make_valid(const rec_t *rec, const dict_index_t *index, ulint *offsets)
Updates debug data in offsets, in order to avoid bogus rec_offs_validate() failures.
Definition: rec.h:631
static bool rec_new_is_versioned(const rec_t *rec)
The following function tells if a new-style record is versioned.
Definition: rec.h:706
constexpr uint32_t REC_INFO_DELETED_FLAG
The deleted flag in info bits; when bit is set to 1, it means the record has been delete marked.
Definition: rec.h:147
static uint16_t rec_get_n_fields_old(const rec_t *rec, const dict_index_t *index)
The following function is used to get the number of fields in an old-style record.
Definition: rec.h:373
constexpr uint32_t REC_1BYTE_SQL_NULL_MASK
SQL null flag in a 1-byte offset of ROW_FORMAT=REDUNDANT records.
Definition: rec.h:191
constexpr uint32_t REC_OLD_N_FIELDS
Definition: rec.h:100
constexpr auto MAX_REC_PER_PAGE
Maximum number of records in a page.
Definition: rec.h:167
constexpr uint32_t REC_OFFS_COMPACT
NOTE: The functions in this file should only use functions from other files in library.
Definition: rec.h:71
static void rec_offs_set_n_alloc(ulint *offsets, ulint n_alloc)
The following function sets the number of allocated elements for an array of offsets.
Definition: rec.h:484
static bool rec_offs_validate(const rec_t *rec, const dict_index_t *index, const ulint *offsets, const bool check_status=true)
Validates offsets returned by rec_get_offsets().
Definition: rec.h:568
static bool rec_new_temp_is_versioned(const rec_t *rec)
The following function tells if a temporary record is versioned.
Definition: rec.h:722
constexpr uint32_t REC_NEW_STATUS_MASK
Definition: rec.h:105
constexpr uint32_t REC_OFFS_SQL_NULL
Definition: rec.h:73
constexpr uint32_t REC_N_TMP_EXTRA_BYTES
Definition: rec.h:163
constexpr uint32_t REC_OLD_N_OWNED
Definition: rec.h:115
static ulint rec_offs_n_fields(const ulint *offsets)
The following function returns the number of fields in a record.
Definition: rec.h:510
static const ulint * rec_offs_base(const ulint *offsets)
Definition: rec.h:227
constexpr int32_t REC_N_NEW_EXTRA_BYTES
Definition: rec.h:159
static enum REC_INSERT_STATE init_nulls_lens_for_temp_redundant(const dict_index_t *index, const rec_t *rec, uint16_t *n_null, const byte **nulls, const byte **lens, uint16_t &non_default_fields, row_version_t &row_version)
Definition: rec.h:861
static uint16_t rec_get_n_fields_old_raw(const rec_t *rec)
The following function is used to get the number of fields in an old-style record,...
Definition: rec.h:350
constexpr uint32_t REC_NEXT_MASK
Definition: rec.h:93
constexpr uint32_t REC_2BYTE_SQL_NULL_MASK
SQL null flag in a 2-byte offset of ROW_FORMAT=REDUNDANT records.
Definition: rec.h:193
ulint * rec_get_offsets(const rec_t *rec, const dict_index_t *index, ulint *offsets, ulint n_fields, ut::Location location, mem_heap_t **heap)
The following function determines the offsets to each field in the record.
Definition: rec.cc:359
constexpr uint32_t REC_INFO_VERSION_FLAG
Definition: rec.h:149
constexpr uint32_t REC_NEW_N_OWNED
Definition: rec.h:116
constexpr uint32_t REC_OLD_N_FIELDS_SHIFT
Definition: rec.h:102
constexpr uint32_t REC_OLD_HEAP_NO
Definition: rec.h:108
static bool rec_old_is_versioned(const rec_t *rec)
The following function tells if an old-style record is versioned.
Definition: rec.h:714
static bool rec_get_1byte_offs_flag(const rec_t *rec)
The following function is used to test whether the data offsets in the record are stored in one-byte ...
Definition: rec.h:1298
void rec_get_offsets_reverse(const byte *extra, const dict_index_t *index, ulint node_ptr, ulint *offsets)
The following function determines the offsets to each field in the record.
Definition: rec.cc:416
constexpr uint32_t REC_N_OWNED_SHIFT
Definition: rec.h:118
static uint32_t rec_get_n_fields_instant(const rec_t *rec, const ulint extra_bytes, uint16_t *length)
Get the number of fields for one new style leaf page record.
Definition: rec.h:733
constexpr uint32_t REC_STATUS_NODE_PTR
Definition: rec.h:180
static bool rec_n_fields_is_sane(dict_index_t *index, const rec_t *rec, const dtuple_t *entry)
Confirms the n_fields of the entry is sane with comparing the other record in the same page specified...
Definition: rec.h:459
constexpr uint32_t REC_OLD_SHORT
Definition: rec.h:96
constexpr uint32_t REC_NEXT_SHIFT
Definition: rec.h:94
static void rec_offs_set_n_fields(ulint *offsets, ulint n_fields)
The following function sets the number of fields in offsets.
Definition: rec.h:496
constexpr uint32_t REC_OFFS_NORMAL_SIZE
Definition: rec.h:209
static ulint rec_get_bit_field_1(const rec_t *rec, ulint offs, ulint mask, ulint shift)
Gets a bit field from within 1 byte.
Definition: rec.h:275
constexpr uint32_t REC_2BYTE_EXTERN_MASK
In a 2-byte offset of ROW_FORMAT=REDUNDANT records, the second most significant bit denotes that the ...
Definition: rec.h:197
constexpr uint32_t REC_NEW_STATUS_SHIFT
Definition: rec.h:106
bool rec_offs_cmp(ulint *offsets1, ulint *offsets2)
Check if the given two record offsets are identical.
Definition: rec.cc:535
static ulint rec_get_n_fields(const rec_t *rec, const dict_index_t *index)
The following function is used to get the number of fields in a record.
Definition: rec.h:429
std::ostream & rec_offs_print(std::ostream &out, const ulint *offsets)
Print the record offsets.
Definition: rec.cc:567
static ulint rec_get_status(const rec_t *rec)
The following function retrieves the status bits of a new-style record.
Definition: rec.h:300
static bool rec_get_instant_flag_new(const rec_t *rec)
The following function tells if a new-style record is instant record.
Definition: rec.h:665
constexpr uint32_t REC_OLD_N_FIELDS_MASK
Definition: rec.h:101
constexpr uint32_t REC_OFFS_SMALL_SIZE
Definition: rec.h:210
const row_version_t INVALID_ROW_VERSION
Definition: rem0types.h:56
byte rec_t
Definition: rem0types.h:41
constexpr uint32_t REC_MAX_N_FIELDS
Definition: rem0types.h:59
uint16_t row_version_t
Definition: rem0types.h:53
required uint64 version
Definition: replication_group_member_actions.proto:41
Definition: completion_hash.h:35
std::atomic< uint16_t > n_pointers
Used in debugging.
Definition: buf0buf.h:1830
Data structure for a column in a table.
Definition: dict0mem.h:484
bool is_dropped_in_or_before(row_version_t version) const
Check if column is dropped before the given version.
Definition: dict0mem.h:735
unsigned mtype
main data type
Definition: dict0mem.h:501
ulint get_fixed_size(ulint comp) const
Returns the size of a fixed size column, 0 if not a fixed size column.
Definition: dict0mem.h:693
bool is_added_after(row_version_t version) const
Check if column is added after the current version.
Definition: dict0mem.h:748
unsigned prtype
precise type; MySQL data type, charset code, flags to indicate nullability, signedness,...
Definition: dict0mem.h:494
Data structure for a field in an index.
Definition: dict0mem.h:890
dict_col_t * col
pointer to the table column
Definition: dict0mem.h:893
unsigned fixed_len
0 or the fixed length of the column if smaller than DICT_ANTELOPE_MAX_INDEX_COL_LEN
Definition: dict0mem.h:903
Data structure for an index.
Definition: dict0mem.h:1041
uint32_t get_n_nullable_before(uint32_t nth) const
Returns the number of nullable fields before specified nth field.
Definition: dict0mem.h:1363
const char * table_name
table name
Definition: dict0mem.h:1052
id_name_t name
index name
Definition: dict0mem.h:1049
const byte * get_nth_default(ulint nth, ulint *length) const
Get the default value of nth field and its length if exists.
Definition: dict0mem.h:1570
uint32_t get_nullable_in_version(row_version_t version) const
Return nullable in a specific row version.
Definition: dict0mem.h:1431
bool has_instant_cols_or_row_versions() const
check if either instant or versioned.
Definition: dict0mem.h:1347
dict_field_t * get_physical_field(size_t pos) const
Gets the nth physical pos field.
Definition: dict0mem.h:1483
uint32_t get_instant_fields() const
Returns the number of fields before first instant ADD COLUMN.
Definition: dict0mem.ic:92
dict_field_t * get_field(ulint pos) const
Gets the nth field of an index.
Definition: dict0mem.h:1497
uint16_t get_nullable_before_instant_add_drop() const
Get the nullable fields before any INSTANT ADD/DROP.
Definition: dict0mem.h:1251
size_t calculate_n_instant_nullable(size_t _n_fields) const
Definition: dict0mem.h:1390
unsigned n_def
number of fields defined so far
Definition: dict0mem.h:1098
unsigned n_nullable
number of nullable fields
Definition: dict0mem.h:1107
rec_cache_t rec_cache
cache the field that needs to be re-computed on each insert.
Definition: dict0mem.h:1220
bool has_row_versions() const
Check whether index belongs to a table having row versions.
Definition: dict0mem.h:1343
bool is_clustered() const
Definition: dict0mem.h:1306
bool has_instant_cols() const
Check whether index has any instantly added columns.
Definition: dict0mem.h:1339
dict_table_t * table
back pointer to table
Definition: dict0mem.h:1055
bool has_instant_cols() const
Definition: dict0mem.h:2489
bool has_row_versions() const
Definition: dict0mem.h:2474
unsigned n_cols
Number of non-virtual columns.
Definition: dict0mem.h:2046
unsigned n_instant_cols
Number of non-virtual columns before first instant ADD COLUMN, including the system columns like n_co...
Definition: dict0mem.h:2051
table_id_t id
Id of the table.
Definition: dict0mem.h:1965
bool is_upgraded_instant() const
Checks if table is upgraded table with INSTANT ADD columns in V1.
Definition: dict0mem.h:2546
Structure for an SQL data tuple of fields (logical record)
Definition: data0data.h:696
The info structure stored at the beginning of a heap block.
Definition: mem0mem.h:302
Part of traditional "extra" column or related hierarchical property.
Definition: opt_explain_format.h:267
const ulint * offsets
Holds reference to cached offsets for record.
Definition: dict0mem.h:977
Definition: ut0core.h:36
#define UNIV_MEM_ASSERT_W(addr, size)
Definition: univ.i:618
#define UNIV_UNLIKELY(cond)
Definition: univ.i:521
constexpr uint32_t UNIV_SQL_NULL
The following number as the length of a logical field means that the field has the SQL NULL as its va...
Definition: univ.i:463
#define UNIV_MEM_ASSERT_AND_ALLOC(addr, size)
Definition: univ.i:630
constexpr ulint ULINT_MAX
Maximum value for a ulint.
Definition: univ.i:440
unsigned long int ulint
Definition: univ.i:406
constexpr size_t UNIV_PAGE_SIZE_MAX
Maximum page size InnoDB currently supports.
Definition: univ.i:323
#define ut_error
Abort execution.
Definition: ut0dbg.h:101
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:105
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:93
#define UT_BITS_IN_BYTES(b)
Determine how many bytes (groups of 8 bits) are needed to store the given number of bits.
Definition: ut0ut.h:198
int n
Definition: xcom_base.cc:509