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