MySQL 9.1.0
Source Code Documentation
rem0lrec.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2021, 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/** @file include/rem0lrec.h
28 Record manager.
29 This file contains low level functions which deals with physical index of
30 fields in a physical record.
31
32 After INSTANT ADD/DROP feature, fields index on logical record might not be
33 same as field index on physical record. So a wrapper (rem0wrec.h) is
34 implemented which translates logical index to physical index. And then
35 functions of this file are called with physical index of the field.
36
37 Created 13/08/2021 Mayank Prasad
38*****************************************************************************/
39
40#ifndef rem0lrec_h
41#define rem0lrec_h
42
43#include "rem0rec.h"
44
45/** Set nth field value to SQL NULL.
46@param[in,out] rec record
47@param[in] n index of the field. */
48static inline void rec_set_nth_field_sql_null_low(rec_t *rec, ulint n);
49
50/** Returns nonzero if the SQL NULL bit is set in nth field of rec.
51@param[in] offsets array returned by rec_get_offsets()
52@param[in] n index of the field.
53@return nonzero if SQL NULL */
54static inline ulint rec_offs_nth_sql_null_low(const ulint *offsets, ulint n);
55
56/** Read the offset of the start of a data field in the record. The start of an
57SQL null field is the end offset of the previous non-null field, or 0, if none
58exists. If n is the number of the last field + 1, then the end offset of the
59last field is returned.
60@param[in] rec record
61@param[in] n index of the field
62@return offset of the start of the field */
63static inline ulint rec_get_field_start_offs_low(const rec_t *rec, ulint n);
64
65/** Returns the offset of nth field start if the record is stored in the 1-byte
66offsets form.
67@param[in] rec record
68@param[in] n index of the field
69@return offset of the start of the field */
70static inline ulint rec_1_get_field_start_offs_low(const rec_t *rec, ulint n);
71
72/** Returns the offset of nth field end if the record is stored in the 1-byte
73offsets form. If the field is SQL null, the flag is ORed in the returned value.
74@param[in] rec record
75@param[in] n index of the field
76@return offset of the start of the field, SQL null flag ORed */
77static inline ulint rec_1_get_field_end_info_low(const rec_t *rec, ulint n);
78
79/** Sets the field end info for the nth field if the record is stored in the
801-byte format.
81@param[in,out] rec record
82@param[in] n index of the field
83@param[in] info value to set */
84static inline void rec_1_set_field_end_info_low(rec_t *rec, ulint n,
85 ulint info);
86/** Returns the offset of nth field start if the record is stored in the 2-byte
87offsets form.
88@param[in] rec record
89@param[in] n index of the field
90@return offset of the start of the field */
91static inline ulint rec_2_get_field_start_offs_low(const rec_t *rec, ulint n);
92
93/** Returns the offset of nth field end if the record is stored in the 2-byte
94offsets form. If the field is SQL null, the flag is ORed in the returned value.
95@param[in] rec record
96@param[in] n index of the field
97@return offset of the start of the field, SQL null flag and extern storage flag
98ORed */
99static inline ulint rec_2_get_field_end_info_low(const rec_t *rec, ulint n);
100
101/** Sets the field end info for the nth field if the record is stored in the
1022-byte format.
103@param[in] rec record
104@param[in] n index of the field
105@param[out] info end info */
106static inline void rec_2_set_field_end_info_low(rec_t *rec, ulint n,
107 ulint info);
108
109/** Sets the value of the ith field SQL null bit of an old-style record.
110@param[in] rec record
111@param[in] i index of the field
112@param[in] val value to set */
113static inline void rec_set_nth_field_null_bit_low(rec_t *rec, ulint i,
114 bool val);
115
116/** Gets the physical size of an old-style field.
117Also an SQL null may have a field of size > 0, if the data type is of a fixed
118size.
119@param[in] rec record
120@param[in] n index of the field
121@return field size in bytes */
122static inline ulint rec_get_nth_field_size_low(const rec_t *rec, ulint n) {
123 ulint os;
124 ulint next_os;
125
127 next_os = rec_get_field_start_offs_low(rec, n + 1);
128
129 ut_ad(next_os - os < UNIV_PAGE_SIZE);
130
131 return (next_os - os);
132}
133
134/** The following function is used to get the offset to the nth
135data field in an old-style record.
136@param[in] rec record
137@param[in] n index of the field
138@param[out] len length of the field; UNIV_SQL_NULL if SQL null;
139@return offset to the field */
141 ulint *len) {
142 ulint os;
143 ulint next_os;
144
145 ut_ad(len);
146 ut_a(rec);
148
149 if (rec_get_1byte_offs_flag(rec)) {
151
152 next_os = rec_1_get_field_end_info_low(rec, n);
153
154 if (next_os & REC_1BYTE_SQL_NULL_MASK) {
155 *len = UNIV_SQL_NULL;
156
157 return (os);
158 }
159
160 next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
161 } else {
163
164 next_os = rec_2_get_field_end_info_low(rec, n);
165
166 if (next_os & REC_2BYTE_SQL_NULL_MASK) {
167 *len = UNIV_SQL_NULL;
168
169 return (os);
170 }
171
172 next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK);
173 }
174
175 *len = next_os - os;
176
177 ut_ad(*len < UNIV_PAGE_SIZE);
178
179 return (os);
180}
181
182/** Mark the nth field as externally stored.
183@param[in] offsets array returned by rec_get_offsets()
184@param[in] n index of the field */
185static inline void rec_offs_make_nth_extern_low(ulint *offsets, const ulint n) {
187 rec_offs_base(offsets)[1 + n] |= REC_OFFS_EXTERNAL;
188}
189
190static inline ulint rec_offs_nth_sql_null_low(const ulint *offsets, ulint n) {
191 return (rec_offs_base(offsets)[1 + n] & REC_OFFS_SQL_NULL);
192}
193
194/** Returns nonzero if the default bit is set in nth field of rec.
195@param[in] offsets array returned by rec_get_offsets()
196@param[in] n index of the field
197@return nonzero if default bit is set */
198static inline ulint rec_offs_nth_default_low(const ulint *offsets, ulint n) {
199 return (rec_offs_base(offsets)[1 + n] & REC_OFFS_DEFAULT);
200}
201
202/** Gets the physical size of a field.
203@param[in] offsets array returned by rec_get_offsets()
204@param[in] n index of the field
205@return length of field */
206static inline ulint rec_offs_nth_size_low(const ulint *offsets, ulint n) {
207 if (!n) {
208 return (rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
209 }
210 return ((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n]) &
212}
213
214/** This is used to modify the value of an already existing field in a record.
215The previous value must have exactly the same size as the new value. If len
216is UNIV_SQL_NULL then the field is treated as an SQL null.
217For records in ROW_FORMAT=COMPACT (new-style records), len must not be
218UNIV_SQL_NULL unless the field already is SQL null.
219@param[in] rec record
220@param[in] offsets array returned by rec_get_offsets()
221@param[in] n index of the field
222@param[in] data pointer to the data if not SQL null
223@param[in] len length of the data or UNIV_SQL_NULL */
224static inline void rec_set_nth_field_low(rec_t *rec, const ulint *offsets,
225 ulint n, const void *data, ulint len) {
226 byte *data2;
227 ulint len2;
228
229 ut_ad(rec);
230 ut_ad(rec_offs_validate(rec, nullptr, offsets));
231
232 auto fn = [&](const ulint *offsets, ulint n) {
233 ulint n_drop = 0;
234 for (size_t i = 0; i < n; i++) {
235 ulint len = rec_offs_base(offsets)[1 + i];
236 if (len & REC_OFFS_DROP) {
237 n_drop++;
238 }
239 }
240 return n_drop;
241 };
242
243 if (len == UNIV_SQL_NULL) {
244 if (!rec_offs_nth_sql_null_low(offsets, n)) {
245 ut_a(!rec_offs_comp(offsets));
246 ulint n_drop = rec_old_is_versioned(rec) ? fn(offsets, n) : 0;
247 rec_set_nth_field_sql_null_low(rec, n - n_drop);
248 }
249
250 return;
251 }
252
253 ut_ad(!rec_offs_nth_default_low(offsets, n));
254
255 /* nullptr for index as n is physical here */
256 data2 = rec_get_nth_field(nullptr, rec, offsets, n, &len2);
257
258 if (len2 == UNIV_SQL_NULL) {
259 ut_ad(!rec_offs_comp(offsets));
260 ulint n_drop = rec_old_is_versioned(rec) ? fn(offsets, n) : 0;
261 rec_set_nth_field_null_bit_low(rec, n - n_drop, false);
262 ut_ad(len == rec_get_nth_field_size_low(rec, n - n_drop));
263 } else {
264 ut_ad(len2 == len);
265 }
266
267 ut_memcpy(data2, data, len);
268}
269
270static inline void rec_set_nth_field_sql_null_low(rec_t *rec, ulint n) {
271 ulint offset;
272
273 offset = rec_get_field_start_offs_low(rec, n);
274
276
278}
279
280static inline void rec_set_nth_field_null_bit_low(rec_t *rec, ulint i,
281 bool val) {
282 ulint info;
283
284 if (rec_get_1byte_offs_flag(rec)) {
285 info = rec_1_get_field_end_info_low(rec, i);
286
287 if (val) {
288 info = info | REC_1BYTE_SQL_NULL_MASK;
289 } else {
290 info = info & ~REC_1BYTE_SQL_NULL_MASK;
291 }
292
293 rec_1_set_field_end_info_low(rec, i, info);
294
295 return;
296 }
297
298 info = rec_2_get_field_end_info_low(rec, i);
299
300 if (val) {
301 info = info | REC_2BYTE_SQL_NULL_MASK;
302 } else {
303 info = info & ~REC_2BYTE_SQL_NULL_MASK;
304 }
305
306 rec_2_set_field_end_info_low(rec, i, info);
307}
308
309static inline ulint rec_get_field_start_offs_low(const rec_t *rec, ulint n) {
310 ut_ad(rec);
312
313 if (n == 0) {
314 return (0);
315 }
316
317 if (rec_get_1byte_offs_flag(rec)) {
318 return (rec_1_get_field_start_offs_low(rec, n));
319 }
320
321 return (rec_2_get_field_start_offs_low(rec, n));
322}
323
327
328 if (n == 0) {
329 return (0);
330 }
331
333}
334
338
339 if (n == 0) {
340 return (0);
341 }
342
343 return (rec_2_get_prev_field_end_info(rec, n) &
345}
346
347static inline ulint rec_1_get_field_end_info_low(const rec_t *rec, ulint n) {
350
351 uint32_t version_size = 0;
352 if (rec_old_is_versioned(rec)) {
353 version_size = 1;
354 }
355
356 return (
357 mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + version_size + n + 1)));
358}
359
360static inline ulint rec_2_get_field_end_info_low(const rec_t *rec, ulint n) {
363
364 uint32_t version_size = 0;
365 if (rec_old_is_versioned(rec)) {
366 version_size = 1;
367 }
368
369 return (mach_read_from_2(rec -
370 (REC_N_OLD_EXTRA_BYTES + version_size + 2 * n + 2)));
371}
372
373static inline void rec_1_set_field_end_info_low(rec_t *rec, ulint n,
374 ulint info) {
377
378 uint32_t version_length = 0;
379 if (rec_old_is_versioned(rec)) {
380 version_length = 1;
381 }
382
383 mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + version_length + n + 1), info);
384}
385
386static inline void rec_2_set_field_end_info_low(rec_t *rec, ulint n,
387 ulint info) {
390
391 uint32_t version_length = 0;
392 if (rec_old_is_versioned(rec)) {
393 version_length = 1;
394 }
395
396 mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + version_length + 2 * n + 2),
397 info);
398}
399
400#endif
static void data_write_sql_null(byte *data, ulint len)
Writes an SQL null field full of zeros.
static uint16_t mach_read_from_2(const byte *b)
The following function is used to fetch data from 2 consecutive bytes.
static void mach_write_to_2(byte *b, ulint n)
The following function is used to store data in two consecutive bytes.
static void mach_write_to_1(byte *b, ulint n)
The following function is used to store data in one byte.
static uint8_t mach_read_from_1(const byte *b)
The following function is used to fetch data from one byte.
constexpr uint32_t REC_OFFS_EXTERNAL
Definition: rec.h:75
constexpr uint32_t REC_OFFS_DEFAULT
Definition: rec.h:77
constexpr uint32_t REC_N_OLD_EXTRA_BYTES
Definition: rec.h:156
constexpr uint32_t REC_OFFS_DROP
Definition: rec.h:79
constexpr uint32_t REC_OFFS_MASK
Definition: rec.h:81
constexpr uint32_t REC_1BYTE_SQL_NULL_MASK
SQL null flag in a 1-byte offset of ROW_FORMAT=REDUNDANT records.
Definition: rec.h:191
static bool rec_offs_validate(const rec_t *rec, const dict_index_t *index, const ulint *offsets, const bool check_status=true)
Validates offsets returned by rec_get_offsets().
Definition: rec.h:568
constexpr uint32_t REC_OFFS_SQL_NULL
Definition: rec.h:73
static const ulint * rec_offs_base(const ulint *offsets)
Definition: rec.h:227
static uint16_t rec_get_n_fields_old_raw(const rec_t *rec)
The following function is used to get the number of fields in an old-style record,...
Definition: rec.h:350
constexpr uint32_t REC_2BYTE_SQL_NULL_MASK
SQL null flag in a 2-byte offset of ROW_FORMAT=REDUNDANT records.
Definition: rec.h:193
static bool rec_old_is_versioned(const rec_t *rec)
The following function tells if an old-style record is versioned.
Definition: rec.h:714
static bool rec_get_1byte_offs_flag(const rec_t *rec)
The following function is used to test whether the data offsets in the record are stored in one-byte ...
Definition: rec.h:1298
constexpr uint32_t REC_2BYTE_EXTERN_MASK
In a 2-byte offset of ROW_FORMAT=REDUNDANT records, the second most significant bit denotes that the ...
Definition: rec.h:197
static void rec_set_nth_field_null_bit_low(rec_t *rec, ulint i, bool val)
Sets the value of the ith field SQL null bit of an old-style record.
Definition: rem0lrec.h:280
static ulint rec_get_nth_field_offs_old_low(const rec_t *rec, ulint n, ulint *len)
The following function is used to get the offset to the nth data field in an old-style record.
Definition: rem0lrec.h:140
static ulint rec_2_get_field_start_offs_low(const rec_t *rec, ulint n)
Returns the offset of nth field start if the record is stored in the 2-byte offsets form.
Definition: rem0lrec.h:335
static ulint rec_offs_nth_sql_null_low(const ulint *offsets, ulint n)
Returns nonzero if the SQL NULL bit is set in nth field of rec.
Definition: rem0lrec.h:190
static void rec_set_nth_field_low(rec_t *rec, const ulint *offsets, ulint n, const void *data, ulint len)
This is used to modify the value of an already existing field in a record.
Definition: rem0lrec.h:224
static ulint rec_1_get_field_end_info_low(const rec_t *rec, ulint n)
Returns the offset of nth field end if the record is stored in the 1-byte offsets form.
Definition: rem0lrec.h:347
static ulint rec_1_get_field_start_offs_low(const rec_t *rec, ulint n)
Returns the offset of nth field start if the record is stored in the 1-byte offsets form.
Definition: rem0lrec.h:324
static ulint rec_offs_nth_default_low(const ulint *offsets, ulint n)
Returns nonzero if the default bit is set in nth field of rec.
Definition: rem0lrec.h:198
static void rec_set_nth_field_sql_null_low(rec_t *rec, ulint n)
Set nth field value to SQL NULL.
Definition: rem0lrec.h:270
static ulint rec_get_field_start_offs_low(const rec_t *rec, ulint n)
Read the offset of the start of a data field in the record.
Definition: rem0lrec.h:309
static void rec_2_set_field_end_info_low(rec_t *rec, ulint n, ulint info)
Sets the field end info for the nth field if the record is stored in the 2-byte format.
Definition: rem0lrec.h:386
static void rec_offs_make_nth_extern_low(ulint *offsets, const ulint n)
Mark the nth field as externally stored.
Definition: rem0lrec.h:185
static void rec_1_set_field_end_info_low(rec_t *rec, ulint n, ulint info)
Sets the field end info for the nth field if the record is stored in the 1-byte format.
Definition: rem0lrec.h:373
static ulint rec_get_nth_field_size_low(const rec_t *rec, ulint n)
Gets the physical size of an old-style field.
Definition: rem0lrec.h:122
static ulint rec_2_get_field_end_info_low(const rec_t *rec, ulint n)
Returns the offset of nth field end if the record is stored in the 2-byte offsets form.
Definition: rem0lrec.h:360
static ulint rec_offs_nth_size_low(const ulint *offsets, ulint n)
Gets the physical size of a field.
Definition: rem0lrec.h:206
Record manager.
static bool rec_offs_comp(const ulint *offsets)
Determine if the offsets are for a record in the new compact format.
static ulint rec_2_get_prev_field_end_info(const rec_t *rec, ulint n)
Returns the offset of n - 1th field end if the record is stored in the 2-byte offsets form.
Definition: rem0rec.ic:642
static ulint rec_1_get_prev_field_end_info(const rec_t *rec, ulint n)
Returns the offset of n - 1th field end if the record is stored in the 1-byte offsets form.
Definition: rem0rec.ic:623
byte rec_t
Definition: rem0types.h:41
const byte * rec_get_nth_field(const dict_index_t *index, const rec_t *rec, const ulint *offsets, ulint n, ulint *len)
Gets the value of the specified field in the record.
Definition: rem0wrec.h:108
#define UNIV_PAGE_SIZE
The universal page size of the database.
Definition: univ.i:294
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
unsigned long int ulint
Definition: univ.i:406
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:105
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:93
static void * ut_memcpy(void *dest, const void *src, ulint n)
Wrapper for memcpy(3).
int n
Definition: xcom_base.cc:509