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