1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /********************************************************************//** |
21 | @file include/rem0rec.h |
22 | Record manager |
23 | |
24 | Created 5/30/1994 Heikki Tuuri |
25 | *************************************************************************/ |
26 | |
27 | #ifndef rem0rec_h |
28 | #define rem0rec_h |
29 | |
30 | #ifndef UNIV_INNOCHECKSUM |
31 | #include "univ.i" |
32 | #include "data0data.h" |
33 | #include "rem0types.h" |
34 | #include "mtr0types.h" |
35 | #include "page0types.h" |
36 | #include "dict0dict.h" |
37 | #include "trx0types.h" |
38 | #endif /*! UNIV_INNOCHECKSUM */ |
39 | #include <ostream> |
40 | #include <sstream> |
41 | |
42 | /* Info bit denoting the predefined minimum record: this bit is set |
43 | if and only if the record is the first user record on a non-leaf |
44 | B-tree page that is the leftmost page on its level |
45 | (PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */ |
46 | #define REC_INFO_MIN_REC_FLAG 0x10UL |
47 | /* The deleted flag in info bits */ |
48 | #define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the |
49 | record has been delete marked */ |
50 | |
51 | /* Number of extra bytes in an old-style record, |
52 | in addition to the data and the offsets */ |
53 | #define 6 |
54 | /* Number of extra bytes in a new-style record, |
55 | in addition to the data and the offsets */ |
56 | #define 5 |
57 | |
58 | /** Record status values for ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED */ |
59 | enum rec_comp_status_t { |
60 | /** User record (PAGE_LEVEL=0, heap>=PAGE_HEAP_NO_USER_LOW) */ |
61 | REC_STATUS_ORDINARY = 0, |
62 | /** Node pointer record (PAGE_LEVEL>=0, heap>=PAGE_HEAP_NO_USER_LOW) */ |
63 | REC_STATUS_NODE_PTR = 1, |
64 | /** The page infimum pseudo-record (heap=PAGE_HEAP_NO_INFIMUM) */ |
65 | REC_STATUS_INFIMUM = 2, |
66 | /** The page supremum pseudo-record (heap=PAGE_HEAP_NO_SUPREMUM) */ |
67 | REC_STATUS_SUPREMUM = 3, |
68 | /** Clustered index record that has been inserted or updated |
69 | after instant ADD COLUMN (more than dict_index_t::n_core_fields) */ |
70 | REC_STATUS_COLUMNS_ADDED = 4 |
71 | }; |
72 | |
73 | /** The dtuple_t::info_bits of the 'default row' record. |
74 | @see rec_is_default_row() */ |
75 | static const byte REC_INFO_DEFAULT_ROW |
76 | = REC_INFO_MIN_REC_FLAG | REC_STATUS_COLUMNS_ADDED; |
77 | |
78 | #define REC_NEW_STATUS 3 /* This is single byte bit-field */ |
79 | #define REC_NEW_STATUS_MASK 0x7UL |
80 | #define REC_NEW_STATUS_SHIFT 0 |
81 | |
82 | /* The following four constants are needed in page0zip.cc in order to |
83 | efficiently compress and decompress pages. */ |
84 | |
85 | /* The offset of heap_no in a compact record */ |
86 | #define REC_NEW_HEAP_NO 4 |
87 | /* The shift of heap_no in a compact record. |
88 | The status is stored in the low-order bits. */ |
89 | #define REC_HEAP_NO_SHIFT 3 |
90 | |
91 | /* Length of a B-tree node pointer, in bytes */ |
92 | #define REC_NODE_PTR_SIZE 4 |
93 | |
94 | /** SQL null flag in a 1-byte offset of ROW_FORMAT=REDUNDANT records */ |
95 | #define REC_1BYTE_SQL_NULL_MASK 0x80UL |
96 | /** SQL null flag in a 2-byte offset of ROW_FORMAT=REDUNDANT records */ |
97 | #define REC_2BYTE_SQL_NULL_MASK 0x8000UL |
98 | |
99 | /** In a 2-byte offset of ROW_FORMAT=REDUNDANT records, the second most |
100 | significant bit denotes that the tail of a field is stored off-page. */ |
101 | #define REC_2BYTE_EXTERN_MASK 0x4000UL |
102 | |
103 | #ifdef UNIV_DEBUG |
104 | /* Length of the rec_get_offsets() header */ |
105 | # define REC_OFFS_HEADER_SIZE 4 |
106 | #else /* UNIV_DEBUG */ |
107 | /* Length of the rec_get_offsets() header */ |
108 | # define 2 |
109 | #endif /* UNIV_DEBUG */ |
110 | |
111 | /* Number of elements that should be initially allocated for the |
112 | offsets[] array, first passed to rec_get_offsets() */ |
113 | #define REC_OFFS_NORMAL_SIZE OFFS_IN_REC_NORMAL_SIZE |
114 | #define REC_OFFS_SMALL_SIZE 10 |
115 | |
116 | /** Get the base address of offsets. The extra_size is stored at |
117 | this position, and following positions hold the end offsets of |
118 | the fields. */ |
119 | #define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE) |
120 | |
121 | /** Compact flag ORed to the extra size returned by rec_get_offsets() */ |
122 | const ulint REC_OFFS_COMPACT = ~(ulint(~0) >> 1); |
123 | /** SQL NULL flag in offsets returned by rec_get_offsets() */ |
124 | const ulint REC_OFFS_SQL_NULL = REC_OFFS_COMPACT; |
125 | /** External flag in offsets returned by rec_get_offsets() */ |
126 | const ulint REC_OFFS_EXTERNAL = REC_OFFS_COMPACT >> 1; |
127 | /** Default value flag in offsets returned by rec_get_offsets() */ |
128 | const ulint REC_OFFS_DEFAULT = REC_OFFS_COMPACT >> 2; |
129 | /** Mask for offsets returned by rec_get_offsets() */ |
130 | const ulint REC_OFFS_MASK = REC_OFFS_DEFAULT - 1; |
131 | |
132 | #ifndef UNIV_INNOCHECKSUM |
133 | /******************************************************//** |
134 | The following function is used to get the pointer of the next chained record |
135 | on the same page. |
136 | @return pointer to the next chained record, or NULL if none */ |
137 | UNIV_INLINE |
138 | const rec_t* |
139 | rec_get_next_ptr_const( |
140 | /*===================*/ |
141 | const rec_t* rec, /*!< in: physical record */ |
142 | ulint comp) /*!< in: nonzero=compact page format */ |
143 | MY_ATTRIBUTE((warn_unused_result)); |
144 | /******************************************************//** |
145 | The following function is used to get the pointer of the next chained record |
146 | on the same page. |
147 | @return pointer to the next chained record, or NULL if none */ |
148 | UNIV_INLINE |
149 | rec_t* |
150 | rec_get_next_ptr( |
151 | /*=============*/ |
152 | rec_t* rec, /*!< in: physical record */ |
153 | ulint comp) /*!< in: nonzero=compact page format */ |
154 | MY_ATTRIBUTE((warn_unused_result)); |
155 | /******************************************************//** |
156 | The following function is used to get the offset of the |
157 | next chained record on the same page. |
158 | @return the page offset of the next chained record, or 0 if none */ |
159 | UNIV_INLINE |
160 | ulint |
161 | rec_get_next_offs( |
162 | /*==============*/ |
163 | const rec_t* rec, /*!< in: physical record */ |
164 | ulint comp) /*!< in: nonzero=compact page format */ |
165 | MY_ATTRIBUTE((warn_unused_result)); |
166 | /******************************************************//** |
167 | The following function is used to set the next record offset field |
168 | of an old-style record. */ |
169 | UNIV_INLINE |
170 | void |
171 | rec_set_next_offs_old( |
172 | /*==================*/ |
173 | rec_t* rec, /*!< in: old-style physical record */ |
174 | ulint next) /*!< in: offset of the next record */ |
175 | MY_ATTRIBUTE((nonnull)); |
176 | /******************************************************//** |
177 | The following function is used to set the next record offset field |
178 | of a new-style record. */ |
179 | UNIV_INLINE |
180 | void |
181 | rec_set_next_offs_new( |
182 | /*==================*/ |
183 | rec_t* rec, /*!< in/out: new-style physical record */ |
184 | ulint next) /*!< in: offset of the next record */ |
185 | MY_ATTRIBUTE((nonnull)); |
186 | /******************************************************//** |
187 | The following function is used to get the number of fields |
188 | in an old-style record. |
189 | @return number of data fields */ |
190 | UNIV_INLINE |
191 | ulint |
192 | rec_get_n_fields_old( |
193 | /*=================*/ |
194 | const rec_t* rec) /*!< in: physical record */ |
195 | MY_ATTRIBUTE((warn_unused_result)); |
196 | /******************************************************//** |
197 | The following function is used to get the number of fields |
198 | in a record. |
199 | @return number of data fields */ |
200 | UNIV_INLINE |
201 | ulint |
202 | rec_get_n_fields( |
203 | /*=============*/ |
204 | const rec_t* rec, /*!< in: physical record */ |
205 | const dict_index_t* index) /*!< in: record descriptor */ |
206 | MY_ATTRIBUTE((warn_unused_result)); |
207 | |
208 | /** Confirms the n_fields of the entry is sane with comparing the other |
209 | record in the same page specified |
210 | @param[in] index index |
211 | @param[in] rec record of the same page |
212 | @param[in] entry index entry |
213 | @return true if n_fields is sane */ |
214 | UNIV_INLINE |
215 | bool |
216 | rec_n_fields_is_sane( |
217 | dict_index_t* index, |
218 | const rec_t* rec, |
219 | const dtuple_t* entry) |
220 | MY_ATTRIBUTE((warn_unused_result)); |
221 | |
222 | /******************************************************//** |
223 | The following function is used to get the number of records owned by the |
224 | previous directory record. |
225 | @return number of owned records */ |
226 | UNIV_INLINE |
227 | ulint |
228 | rec_get_n_owned_old( |
229 | /*================*/ |
230 | const rec_t* rec) /*!< in: old-style physical record */ |
231 | MY_ATTRIBUTE((warn_unused_result)); |
232 | /******************************************************//** |
233 | The following function is used to set the number of owned records. */ |
234 | UNIV_INLINE |
235 | void |
236 | rec_set_n_owned_old( |
237 | /*================*/ |
238 | rec_t* rec, /*!< in: old-style physical record */ |
239 | ulint n_owned) /*!< in: the number of owned */ |
240 | MY_ATTRIBUTE((nonnull)); |
241 | /******************************************************//** |
242 | The following function is used to get the number of records owned by the |
243 | previous directory record. |
244 | @return number of owned records */ |
245 | UNIV_INLINE |
246 | ulint |
247 | rec_get_n_owned_new( |
248 | /*================*/ |
249 | const rec_t* rec) /*!< in: new-style physical record */ |
250 | MY_ATTRIBUTE((warn_unused_result)); |
251 | /******************************************************//** |
252 | The following function is used to set the number of owned records. */ |
253 | UNIV_INLINE |
254 | void |
255 | rec_set_n_owned_new( |
256 | /*================*/ |
257 | rec_t* rec, /*!< in/out: new-style physical record */ |
258 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
259 | ulint n_owned)/*!< in: the number of owned */ |
260 | MY_ATTRIBUTE((nonnull(1))); |
261 | /******************************************************//** |
262 | The following function is used to retrieve the info bits of |
263 | a record. |
264 | @return info bits */ |
265 | UNIV_INLINE |
266 | ulint |
267 | rec_get_info_bits( |
268 | /*==============*/ |
269 | const rec_t* rec, /*!< in: physical record */ |
270 | ulint comp) /*!< in: nonzero=compact page format */ |
271 | MY_ATTRIBUTE((warn_unused_result)); |
272 | /******************************************************//** |
273 | The following function is used to set the info bits of a record. */ |
274 | UNIV_INLINE |
275 | void |
276 | rec_set_info_bits_old( |
277 | /*==================*/ |
278 | rec_t* rec, /*!< in: old-style physical record */ |
279 | ulint bits) /*!< in: info bits */ |
280 | MY_ATTRIBUTE((nonnull)); |
281 | /******************************************************//** |
282 | The following function is used to set the info bits of a record. */ |
283 | UNIV_INLINE |
284 | void |
285 | rec_set_info_bits_new( |
286 | /*==================*/ |
287 | rec_t* rec, /*!< in/out: new-style physical record */ |
288 | ulint bits) /*!< in: info bits */ |
289 | MY_ATTRIBUTE((nonnull)); |
290 | |
291 | /** Determine the status bits of a non-REDUNDANT record. |
292 | @param[in] rec ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED record |
293 | @return status bits */ |
294 | inline |
295 | rec_comp_status_t |
296 | rec_get_status(const rec_t* rec) |
297 | { |
298 | byte bits = rec[-REC_NEW_STATUS] & REC_NEW_STATUS_MASK; |
299 | ut_ad(bits <= REC_STATUS_COLUMNS_ADDED); |
300 | return static_cast<rec_comp_status_t>(bits); |
301 | } |
302 | |
303 | /** Set the status bits of a non-REDUNDANT record. |
304 | @param[in,out] rec ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED record |
305 | @param[in] bits status bits */ |
306 | inline |
307 | void |
308 | rec_set_status(rec_t* rec, byte bits) |
309 | { |
310 | ut_ad(bits <= REC_STATUS_COLUMNS_ADDED); |
311 | rec[-REC_NEW_STATUS] = (rec[-REC_NEW_STATUS] & ~REC_NEW_STATUS_MASK) |
312 | | bits; |
313 | } |
314 | |
315 | /******************************************************//** |
316 | The following function is used to retrieve the info and status |
317 | bits of a record. (Only compact records have status bits.) |
318 | @return info bits */ |
319 | UNIV_INLINE |
320 | ulint |
321 | rec_get_info_and_status_bits( |
322 | /*=========================*/ |
323 | const rec_t* rec, /*!< in: physical record */ |
324 | ulint comp) /*!< in: nonzero=compact page format */ |
325 | MY_ATTRIBUTE((warn_unused_result)); |
326 | /******************************************************//** |
327 | The following function is used to set the info and status |
328 | bits of a record. (Only compact records have status bits.) */ |
329 | UNIV_INLINE |
330 | void |
331 | rec_set_info_and_status_bits( |
332 | /*=========================*/ |
333 | rec_t* rec, /*!< in/out: compact physical record */ |
334 | ulint bits) /*!< in: info bits */ |
335 | MY_ATTRIBUTE((nonnull)); |
336 | |
337 | /******************************************************//** |
338 | The following function tells if record is delete marked. |
339 | @return nonzero if delete marked */ |
340 | UNIV_INLINE |
341 | ulint |
342 | rec_get_deleted_flag( |
343 | /*=================*/ |
344 | const rec_t* rec, /*!< in: physical record */ |
345 | ulint comp) /*!< in: nonzero=compact page format */ |
346 | MY_ATTRIBUTE((warn_unused_result)); |
347 | /******************************************************//** |
348 | The following function is used to set the deleted bit. */ |
349 | UNIV_INLINE |
350 | void |
351 | rec_set_deleted_flag_old( |
352 | /*=====================*/ |
353 | rec_t* rec, /*!< in: old-style physical record */ |
354 | ulint flag) /*!< in: nonzero if delete marked */ |
355 | MY_ATTRIBUTE((nonnull)); |
356 | /******************************************************//** |
357 | The following function is used to set the deleted bit. */ |
358 | UNIV_INLINE |
359 | void |
360 | rec_set_deleted_flag_new( |
361 | /*=====================*/ |
362 | rec_t* rec, /*!< in/out: new-style physical record */ |
363 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
364 | ulint flag) /*!< in: nonzero if delete marked */ |
365 | MY_ATTRIBUTE((nonnull(1))); |
366 | /******************************************************//** |
367 | The following function tells if a new-style record is a node pointer. |
368 | @return TRUE if node pointer */ |
369 | UNIV_INLINE |
370 | bool |
371 | rec_get_node_ptr_flag( |
372 | /*==================*/ |
373 | const rec_t* rec) /*!< in: physical record */ |
374 | MY_ATTRIBUTE((warn_unused_result)); |
375 | /******************************************************//** |
376 | The following function is used to get the order number |
377 | of an old-style record in the heap of the index page. |
378 | @return heap order number */ |
379 | UNIV_INLINE |
380 | ulint |
381 | rec_get_heap_no_old( |
382 | /*================*/ |
383 | const rec_t* rec) /*!< in: physical record */ |
384 | MY_ATTRIBUTE((warn_unused_result)); |
385 | /******************************************************//** |
386 | The following function is used to set the heap number |
387 | field in an old-style record. */ |
388 | UNIV_INLINE |
389 | void |
390 | rec_set_heap_no_old( |
391 | /*================*/ |
392 | rec_t* rec, /*!< in: physical record */ |
393 | ulint heap_no)/*!< in: the heap number */ |
394 | MY_ATTRIBUTE((nonnull)); |
395 | /******************************************************//** |
396 | The following function is used to get the order number |
397 | of a new-style record in the heap of the index page. |
398 | @return heap order number */ |
399 | UNIV_INLINE |
400 | ulint |
401 | rec_get_heap_no_new( |
402 | /*================*/ |
403 | const rec_t* rec) /*!< in: physical record */ |
404 | MY_ATTRIBUTE((warn_unused_result)); |
405 | /******************************************************//** |
406 | The following function is used to set the heap number |
407 | field in a new-style record. */ |
408 | UNIV_INLINE |
409 | void |
410 | rec_set_heap_no_new( |
411 | /*================*/ |
412 | rec_t* rec, /*!< in/out: physical record */ |
413 | ulint heap_no)/*!< in: the heap number */ |
414 | MY_ATTRIBUTE((nonnull)); |
415 | /******************************************************//** |
416 | The following function is used to test whether the data offsets |
417 | in the record are stored in one-byte or two-byte format. |
418 | @return TRUE if 1-byte form */ |
419 | UNIV_INLINE |
420 | ibool |
421 | rec_get_1byte_offs_flag( |
422 | /*====================*/ |
423 | const rec_t* rec) /*!< in: physical record */ |
424 | MY_ATTRIBUTE((warn_unused_result)); |
425 | |
426 | /******************************************************//** |
427 | The following function is used to set the 1-byte offsets flag. */ |
428 | UNIV_INLINE |
429 | void |
430 | rec_set_1byte_offs_flag( |
431 | /*====================*/ |
432 | rec_t* rec, /*!< in: physical record */ |
433 | ibool flag) /*!< in: TRUE if 1byte form */ |
434 | MY_ATTRIBUTE((nonnull)); |
435 | |
436 | /******************************************************//** |
437 | Returns the offset of nth field end if the record is stored in the 1-byte |
438 | offsets form. If the field is SQL null, the flag is ORed in the returned |
439 | value. |
440 | @return offset of the start of the field, SQL null flag ORed */ |
441 | UNIV_INLINE |
442 | ulint |
443 | rec_1_get_field_end_info( |
444 | /*=====================*/ |
445 | const rec_t* rec, /*!< in: record */ |
446 | ulint n) /*!< in: field index */ |
447 | MY_ATTRIBUTE((warn_unused_result)); |
448 | |
449 | /******************************************************//** |
450 | Returns the offset of nth field end if the record is stored in the 2-byte |
451 | offsets form. If the field is SQL null, the flag is ORed in the returned |
452 | value. |
453 | @return offset of the start of the field, SQL null flag and extern |
454 | storage flag ORed */ |
455 | UNIV_INLINE |
456 | ulint |
457 | rec_2_get_field_end_info( |
458 | /*=====================*/ |
459 | const rec_t* rec, /*!< in: record */ |
460 | ulint n) /*!< in: field index */ |
461 | MY_ATTRIBUTE((warn_unused_result)); |
462 | |
463 | /******************************************************//** |
464 | Returns nonzero if the field is stored off-page. |
465 | @retval 0 if the field is stored in-page |
466 | @retval REC_2BYTE_EXTERN_MASK if the field is stored externally */ |
467 | UNIV_INLINE |
468 | ulint |
469 | rec_2_is_field_extern( |
470 | /*==================*/ |
471 | const rec_t* rec, /*!< in: record */ |
472 | ulint n) /*!< in: field index */ |
473 | MY_ATTRIBUTE((warn_unused_result)); |
474 | |
475 | /******************************************************//** |
476 | Determine how many of the first n columns in a compact |
477 | physical record are stored externally. |
478 | @return number of externally stored columns */ |
479 | ulint |
480 | rec_get_n_extern_new( |
481 | /*=================*/ |
482 | const rec_t* rec, /*!< in: compact physical record */ |
483 | const dict_index_t* index, /*!< in: record descriptor */ |
484 | ulint n) /*!< in: number of columns to scan */ |
485 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
486 | |
487 | /** Determine the offsets to each field in an index record. |
488 | @param[in] rec physical record |
489 | @param[in] index the index that the record belongs to |
490 | @param[in,out] offsets array comprising offsets[0] allocated elements, |
491 | or an array from rec_get_offsets(), or NULL |
492 | @param[in] leaf whether this is a leaf-page record |
493 | @param[in] n_fields maximum number of offsets to compute |
494 | (ULINT_UNDEFINED to compute all offsets) |
495 | @param[in,out] heap memory heap |
496 | @return the new offsets */ |
497 | ulint* |
498 | rec_get_offsets_func( |
499 | const rec_t* rec, |
500 | const dict_index_t* index, |
501 | ulint* offsets, |
502 | bool leaf, |
503 | ulint n_fields, |
504 | #ifdef UNIV_DEBUG |
505 | const char* file, /*!< in: file name where called */ |
506 | unsigned line, /*!< in: line number where called */ |
507 | #endif /* UNIV_DEBUG */ |
508 | mem_heap_t** heap) /*!< in/out: memory heap */ |
509 | #ifdef UNIV_DEBUG |
510 | MY_ATTRIBUTE((nonnull(1,2,6,8),warn_unused_result)); |
511 | #else /* UNIV_DEBUG */ |
512 | MY_ATTRIBUTE((nonnull(1,2,6),warn_unused_result)); |
513 | #endif /* UNIV_DEBUG */ |
514 | |
515 | #ifdef UNIV_DEBUG |
516 | # define rec_get_offsets(rec, index, offsets, leaf, n, heap) \ |
517 | rec_get_offsets_func(rec,index,offsets,leaf,n,__FILE__,__LINE__,heap) |
518 | #else /* UNIV_DEBUG */ |
519 | # define rec_get_offsets(rec, index, offsets, leaf, n, heap) \ |
520 | rec_get_offsets_func(rec, index, offsets, leaf, n, heap) |
521 | #endif /* UNIV_DEBUG */ |
522 | |
523 | /******************************************************//** |
524 | The following function determines the offsets to each field |
525 | in the record. It can reuse a previously allocated array. */ |
526 | void |
527 | rec_get_offsets_reverse( |
528 | /*====================*/ |
529 | const byte* extra, /*!< in: the extra bytes of a |
530 | compact record in reverse order, |
531 | excluding the fixed-size |
532 | REC_N_NEW_EXTRA_BYTES */ |
533 | const dict_index_t* index, /*!< in: record descriptor */ |
534 | ulint node_ptr,/*!< in: nonzero=node pointer, |
535 | 0=leaf node */ |
536 | ulint* offsets)/*!< in/out: array consisting of |
537 | offsets[0] allocated elements */ |
538 | MY_ATTRIBUTE((nonnull)); |
539 | #ifdef UNIV_DEBUG |
540 | /** Validate offsets returned by rec_get_offsets(). |
541 | @param[in] rec record, or NULL |
542 | @param[in] index the index that the record belongs in, or NULL |
543 | @param[in,out] offsets the offsets of the record |
544 | @return true */ |
545 | bool |
546 | rec_offs_validate( |
547 | const rec_t* rec, |
548 | const dict_index_t* index, |
549 | const ulint* offsets) |
550 | MY_ATTRIBUTE((nonnull(3), warn_unused_result)); |
551 | /** Update debug data in offsets, in order to tame rec_offs_validate(). |
552 | @param[in] rec record |
553 | @param[in] index the index that the record belongs in |
554 | @param[in] leaf whether the record resides in a leaf page |
555 | @param[in,out] offsets offsets from rec_get_offsets() to adjust */ |
556 | void |
557 | rec_offs_make_valid( |
558 | const rec_t* rec, |
559 | const dict_index_t* index, |
560 | bool leaf, |
561 | ulint* offsets) |
562 | MY_ATTRIBUTE((nonnull)); |
563 | #else |
564 | # define rec_offs_make_valid(rec, index, leaf, offsets) |
565 | #endif /* UNIV_DEBUG */ |
566 | |
567 | /************************************************************//** |
568 | The following function is used to get the offset to the nth |
569 | data field in an old-style record. |
570 | @return offset to the field */ |
571 | ulint |
572 | rec_get_nth_field_offs_old( |
573 | /*=======================*/ |
574 | const rec_t* rec, /*!< in: record */ |
575 | ulint n, /*!< in: index of the field */ |
576 | ulint* len) /*!< out: length of the field; UNIV_SQL_NULL |
577 | if SQL null */ |
578 | MY_ATTRIBUTE((nonnull)); |
579 | #define rec_get_nth_field_old(rec, n, len) \ |
580 | ((rec) + rec_get_nth_field_offs_old(rec, n, len)) |
581 | /************************************************************//** |
582 | Gets the physical size of an old-style field. |
583 | Also an SQL null may have a field of size > 0, |
584 | if the data type is of a fixed size. |
585 | @return field size in bytes */ |
586 | UNIV_INLINE |
587 | ulint |
588 | rec_get_nth_field_size( |
589 | /*===================*/ |
590 | const rec_t* rec, /*!< in: record */ |
591 | ulint n) /*!< in: index of the field */ |
592 | MY_ATTRIBUTE((warn_unused_result)); |
593 | /************************************************************//** |
594 | The following function is used to get an offset to the nth |
595 | data field in a record. |
596 | @return offset from the origin of rec */ |
597 | UNIV_INLINE |
598 | ulint |
599 | rec_get_nth_field_offs( |
600 | /*===================*/ |
601 | const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
602 | ulint n, /*!< in: index of the field */ |
603 | ulint* len) /*!< out: length of the field; UNIV_SQL_NULL |
604 | if SQL null */ |
605 | MY_ATTRIBUTE((nonnull)); |
606 | #define rec_get_nth_field(rec, offsets, n, len) \ |
607 | ((rec) + rec_get_nth_field_offs(offsets, n, len)) |
608 | |
609 | /******************************************************//** |
610 | Determine if the offsets are for a record containing null BLOB pointers. |
611 | @return first field containing a null BLOB pointer, or NULL if none found */ |
612 | UNIV_INLINE |
613 | const byte* |
614 | rec_offs_any_null_extern( |
615 | /*=====================*/ |
616 | const rec_t* rec, /*!< in: record */ |
617 | const ulint* offsets) /*!< in: rec_get_offsets(rec) */ |
618 | MY_ATTRIBUTE((warn_unused_result)); |
619 | |
620 | /******************************************************//** |
621 | Returns nonzero if the extern bit is set in nth field of rec. |
622 | @return nonzero if externally stored */ |
623 | UNIV_INLINE |
624 | ulint |
625 | rec_offs_nth_extern_old( |
626 | /*================*/ |
627 | const rec_t* rec, /*!< in: record */ |
628 | ulint n /*!< in: index of the field */) |
629 | MY_ATTRIBUTE((warn_unused_result)); |
630 | |
631 | /** Mark the nth field as externally stored. |
632 | @param[in] offsets array returned by rec_get_offsets() |
633 | @param[in] n nth field */ |
634 | void |
635 | rec_offs_make_nth_extern( |
636 | ulint* offsets, |
637 | const ulint n); |
638 | |
639 | /** Determine the number of allocated elements for an array of offsets. |
640 | @param[in] offsets offsets after rec_offs_set_n_alloc() |
641 | @return number of elements */ |
642 | inline |
643 | ulint |
644 | rec_offs_get_n_alloc(const ulint* offsets) |
645 | { |
646 | ulint n_alloc; |
647 | ut_ad(offsets); |
648 | n_alloc = offsets[0]; |
649 | ut_ad(n_alloc > REC_OFFS_HEADER_SIZE); |
650 | UNIV_MEM_ASSERT_W(offsets, n_alloc * sizeof *offsets); |
651 | return(n_alloc); |
652 | } |
653 | |
654 | /** Determine the number of fields for which offsets have been initialized. |
655 | @param[in] offsets rec_get_offsets() |
656 | @return number of fields */ |
657 | inline |
658 | ulint |
659 | rec_offs_n_fields(const ulint* offsets) |
660 | { |
661 | ulint n_fields; |
662 | ut_ad(offsets); |
663 | n_fields = offsets[1]; |
664 | ut_ad(n_fields > 0); |
665 | ut_ad(n_fields <= REC_MAX_N_FIELDS); |
666 | ut_ad(n_fields + REC_OFFS_HEADER_SIZE |
667 | <= rec_offs_get_n_alloc(offsets)); |
668 | return(n_fields); |
669 | } |
670 | |
671 | /** Get a flag of a record field. |
672 | @param[in] offsets rec_get_offsets() |
673 | @param[in] n nth field |
674 | @param[in] flag flag to extract |
675 | @return the flag of the record field */ |
676 | inline |
677 | ulint |
678 | rec_offs_nth_flag(const ulint* offsets, ulint n, ulint flag) |
679 | { |
680 | ut_ad(rec_offs_validate(NULL, NULL, offsets)); |
681 | ut_ad(n < rec_offs_n_fields(offsets)); |
682 | /* The DEFAULT, NULL, EXTERNAL flags are mutually exclusive. */ |
683 | ut_ad(ut_is_2pow(rec_offs_base(offsets)[1 + n] |
684 | & (REC_OFFS_DEFAULT |
685 | | REC_OFFS_SQL_NULL |
686 | | REC_OFFS_EXTERNAL))); |
687 | return rec_offs_base(offsets)[1 + n] & flag; |
688 | } |
689 | |
690 | /** Determine if a record field is missing |
691 | (should be replaced by dict_index_t::instant_field_value()). |
692 | @param[in] offsets rec_get_offsets() |
693 | @param[in] n nth field |
694 | @return nonzero if default bit is set */ |
695 | inline |
696 | ulint |
697 | rec_offs_nth_default(const ulint* offsets, ulint n) |
698 | { |
699 | return rec_offs_nth_flag(offsets, n, REC_OFFS_DEFAULT); |
700 | } |
701 | |
702 | /** Determine if a record field is SQL NULL |
703 | (should be replaced by dict_index_t::instant_field_value()). |
704 | @param[in] offsets rec_get_offsets() |
705 | @param[in] n nth field |
706 | @return nonzero if SQL NULL set */ |
707 | inline |
708 | ulint |
709 | rec_offs_nth_sql_null(const ulint* offsets, ulint n) |
710 | { |
711 | return rec_offs_nth_flag(offsets, n, REC_OFFS_SQL_NULL); |
712 | } |
713 | |
714 | /** Determine if a record field is stored off-page. |
715 | @param[in] offsets rec_get_offsets() |
716 | @param[in] n nth field |
717 | Returns nonzero if the extern bit is set in nth field of rec. |
718 | @return nonzero if externally stored */ |
719 | inline |
720 | ulint |
721 | rec_offs_nth_extern(const ulint* offsets, ulint n) |
722 | { |
723 | return rec_offs_nth_flag(offsets, n, REC_OFFS_EXTERNAL); |
724 | } |
725 | |
726 | /** Get a global flag of a record. |
727 | @param[in] offsets rec_get_offsets() |
728 | @param[in] flag flag to extract |
729 | @return the flag of the record field */ |
730 | inline |
731 | ulint |
732 | rec_offs_any_flag(const ulint* offsets, ulint flag) |
733 | { |
734 | ut_ad(rec_offs_validate(NULL, NULL, offsets)); |
735 | return *rec_offs_base(offsets) & flag; |
736 | } |
737 | |
738 | /** Determine if the offsets are for a record containing off-page columns. |
739 | @param[in] offsets rec_get_offsets() |
740 | @return nonzero if any off-page columns exist */ |
741 | inline bool rec_offs_any_extern(const ulint* offsets) |
742 | { |
743 | return rec_offs_any_flag(offsets, REC_OFFS_EXTERNAL); |
744 | } |
745 | |
746 | /** Determine if the offsets are for a record that is missing fields. |
747 | @param[in] offsets rec_get_offsets() |
748 | @return nonzero if any fields need to be replaced with |
749 | dict_index_t::instant_field_value() */ |
750 | inline |
751 | ulint |
752 | rec_offs_any_default(const ulint* offsets) |
753 | { |
754 | return rec_offs_any_flag(offsets, REC_OFFS_DEFAULT); |
755 | } |
756 | |
757 | /** Determine if the offsets are for other than ROW_FORMAT=REDUNDANT. |
758 | @param[in] offsets rec_get_offsets() |
759 | @return nonzero if ROW_FORMAT is COMPACT,DYNAMIC or COMPRESSED |
760 | @retval 0 if ROW_FORMAT=REDUNDANT */ |
761 | inline |
762 | ulint |
763 | rec_offs_comp(const ulint* offsets) |
764 | { |
765 | ut_ad(rec_offs_validate(NULL, NULL, offsets)); |
766 | return(*rec_offs_base(offsets) & REC_OFFS_COMPACT); |
767 | } |
768 | |
769 | /** Determine if the record is the 'default row' pseudo-record |
770 | in the clustered index. |
771 | @param[in] rec leaf page record |
772 | @param[in] index index of the record |
773 | @return whether the record is the 'default row' pseudo-record */ |
774 | inline |
775 | bool |
776 | rec_is_default_row(const rec_t* rec, const dict_index_t* index) |
777 | { |
778 | bool is = rec_get_info_bits(rec, dict_table_is_comp(index->table)) |
779 | & REC_INFO_MIN_REC_FLAG; |
780 | ut_ad(!is || index->is_instant()); |
781 | ut_ad(!is || !dict_table_is_comp(index->table) |
782 | || rec_get_status(rec) == REC_STATUS_COLUMNS_ADDED); |
783 | return is; |
784 | } |
785 | |
786 | /** Get the nth field from an index. |
787 | @param[in] rec index record |
788 | @param[in] index index |
789 | @param[in] offsets rec_get_offsets(rec, index) |
790 | @param[in] n field number |
791 | @param[out] len length of the field in bytes, or UNIV_SQL_NULL |
792 | @return a read-only copy of the index field */ |
793 | inline |
794 | const byte* |
795 | rec_get_nth_cfield( |
796 | const rec_t* rec, |
797 | const dict_index_t* index, |
798 | const ulint* offsets, |
799 | ulint n, |
800 | ulint* len) |
801 | { |
802 | ut_ad(rec_offs_validate(rec, index, offsets)); |
803 | if (!rec_offs_nth_default(offsets, n)) { |
804 | return rec_get_nth_field(rec, offsets, n, len); |
805 | } |
806 | return index->instant_field_value(n, len); |
807 | } |
808 | |
809 | /******************************************************//** |
810 | Gets the physical size of a field. |
811 | @return length of field */ |
812 | UNIV_INLINE |
813 | ulint |
814 | rec_offs_nth_size( |
815 | /*==============*/ |
816 | const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
817 | ulint n) /*!< in: nth field */ |
818 | MY_ATTRIBUTE((warn_unused_result)); |
819 | |
820 | /******************************************************//** |
821 | Returns the number of extern bits set in a record. |
822 | @return number of externally stored fields */ |
823 | UNIV_INLINE |
824 | ulint |
825 | rec_offs_n_extern( |
826 | /*==============*/ |
827 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
828 | MY_ATTRIBUTE((warn_unused_result)); |
829 | /***********************************************************//** |
830 | This is used to modify the value of an already existing field in a record. |
831 | The previous value must have exactly the same size as the new value. If len |
832 | is UNIV_SQL_NULL then the field is treated as an SQL null. |
833 | For records in ROW_FORMAT=COMPACT (new-style records), len must not be |
834 | UNIV_SQL_NULL unless the field already is SQL null. */ |
835 | UNIV_INLINE |
836 | void |
837 | rec_set_nth_field( |
838 | /*==============*/ |
839 | rec_t* rec, /*!< in: record */ |
840 | const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
841 | ulint n, /*!< in: index number of the field */ |
842 | const void* data, /*!< in: pointer to the data if not SQL null */ |
843 | ulint len) /*!< in: length of the data or UNIV_SQL_NULL. |
844 | If not SQL null, must have the same |
845 | length as the previous value. |
846 | If SQL null, previous value must be |
847 | SQL null. */ |
848 | MY_ATTRIBUTE((nonnull(1,2))); |
849 | /**********************************************************//** |
850 | The following function returns the data size of an old-style physical |
851 | record, that is the sum of field lengths. SQL null fields |
852 | are counted as length 0 fields. The value returned by the function |
853 | is the distance from record origin to record end in bytes. |
854 | @return size */ |
855 | UNIV_INLINE |
856 | ulint |
857 | rec_get_data_size_old( |
858 | /*==================*/ |
859 | const rec_t* rec) /*!< in: physical record */ |
860 | MY_ATTRIBUTE((warn_unused_result)); |
861 | /**********************************************************//** |
862 | The following function sets the number of allocated elements |
863 | for an array of offsets. */ |
864 | UNIV_INLINE |
865 | void |
866 | rec_offs_set_n_alloc( |
867 | /*=================*/ |
868 | ulint* offsets, /*!< out: array for rec_get_offsets(), |
869 | must be allocated */ |
870 | ulint n_alloc) /*!< in: number of elements */ |
871 | MY_ATTRIBUTE((nonnull)); |
872 | #define rec_offs_init(offsets) \ |
873 | rec_offs_set_n_alloc(offsets, (sizeof offsets) / sizeof *offsets) |
874 | /**********************************************************//** |
875 | The following function returns the data size of a physical |
876 | record, that is the sum of field lengths. SQL null fields |
877 | are counted as length 0 fields. The value returned by the function |
878 | is the distance from record origin to record end in bytes. |
879 | @return size */ |
880 | UNIV_INLINE |
881 | ulint |
882 | rec_offs_data_size( |
883 | /*===============*/ |
884 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
885 | MY_ATTRIBUTE((warn_unused_result)); |
886 | /**********************************************************//** |
887 | Returns the total size of record minus data size of record. |
888 | The value returned by the function is the distance from record |
889 | start to record origin in bytes. |
890 | @return size */ |
891 | UNIV_INLINE |
892 | ulint |
893 | rec_offs_extra_size( |
894 | /*================*/ |
895 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
896 | MY_ATTRIBUTE((warn_unused_result)); |
897 | /**********************************************************//** |
898 | Returns the total size of a physical record. |
899 | @return size */ |
900 | UNIV_INLINE |
901 | ulint |
902 | rec_offs_size( |
903 | /*==========*/ |
904 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
905 | MY_ATTRIBUTE((warn_unused_result)); |
906 | #ifdef UNIV_DEBUG |
907 | /**********************************************************//** |
908 | Returns a pointer to the start of the record. |
909 | @return pointer to start */ |
910 | UNIV_INLINE |
911 | byte* |
912 | rec_get_start( |
913 | /*==========*/ |
914 | const rec_t* rec, /*!< in: pointer to record */ |
915 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
916 | MY_ATTRIBUTE((warn_unused_result)); |
917 | /**********************************************************//** |
918 | Returns a pointer to the end of the record. |
919 | @return pointer to end */ |
920 | UNIV_INLINE |
921 | byte* |
922 | rec_get_end( |
923 | /*========*/ |
924 | const rec_t* rec, /*!< in: pointer to record */ |
925 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
926 | MY_ATTRIBUTE((warn_unused_result)); |
927 | #else /* UNIV_DEBUG */ |
928 | # define rec_get_start(rec, offsets) ((rec) - rec_offs_extra_size(offsets)) |
929 | # define rec_get_end(rec, offsets) ((rec) + rec_offs_data_size(offsets)) |
930 | #endif /* UNIV_DEBUG */ |
931 | |
932 | /** Copy a physical record to a buffer. |
933 | @param[in] buf buffer |
934 | @param[in] rec physical record |
935 | @param[in] offsets array returned by rec_get_offsets() |
936 | @return pointer to the origin of the copy */ |
937 | UNIV_INLINE |
938 | rec_t* |
939 | rec_copy( |
940 | void* buf, |
941 | const rec_t* rec, |
942 | const ulint* offsets); |
943 | |
944 | /** Determine the size of a data tuple prefix in a temporary file. |
945 | @param[in] index clustered or secondary index |
946 | @param[in] fields data fields |
947 | @param[in] n_fields number of data fields |
948 | @param[out] extra record header size |
949 | @param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED |
950 | @return total size, in bytes */ |
951 | ulint |
952 | rec_get_converted_size_temp( |
953 | const dict_index_t* index, |
954 | const dfield_t* fields, |
955 | ulint n_fields, |
956 | ulint* extra, |
957 | rec_comp_status_t status = REC_STATUS_ORDINARY) |
958 | MY_ATTRIBUTE((warn_unused_result, nonnull)); |
959 | |
960 | /** Determine the offset to each field in temporary file. |
961 | @param[in] rec temporary file record |
962 | @param[in] index index of that the record belongs to |
963 | @param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets) |
964 | @param[in] n_core number of core fields (index->n_core_fields) |
965 | @param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED */ |
966 | void |
967 | rec_init_offsets_temp( |
968 | const rec_t* rec, |
969 | const dict_index_t* index, |
970 | ulint* offsets, |
971 | ulint n_core, |
972 | rec_comp_status_t status = REC_STATUS_ORDINARY) |
973 | MY_ATTRIBUTE((nonnull)); |
974 | /** Determine the offset to each field in temporary file. |
975 | @param[in] rec temporary file record |
976 | @param[in] index index of that the record belongs to |
977 | @param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets) |
978 | */ |
979 | void |
980 | rec_init_offsets_temp( |
981 | const rec_t* rec, |
982 | const dict_index_t* index, |
983 | ulint* offsets) |
984 | MY_ATTRIBUTE((nonnull)); |
985 | |
986 | /** Convert a data tuple prefix to the temporary file format. |
987 | @param[out] rec record in temporary file format |
988 | @param[in] index clustered or secondary index |
989 | @param[in] fields data fields |
990 | @param[in] n_fields number of data fields |
991 | @param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED |
992 | */ |
993 | void |
994 | rec_convert_dtuple_to_temp( |
995 | rec_t* rec, |
996 | const dict_index_t* index, |
997 | const dfield_t* fields, |
998 | ulint n_fields, |
999 | rec_comp_status_t status = REC_STATUS_ORDINARY) |
1000 | MY_ATTRIBUTE((nonnull)); |
1001 | |
1002 | /**************************************************************//** |
1003 | Copies the first n fields of a physical record to a new physical record in |
1004 | a buffer. |
1005 | @return own: copied record */ |
1006 | rec_t* |
1007 | rec_copy_prefix_to_buf( |
1008 | /*===================*/ |
1009 | const rec_t* rec, /*!< in: physical record */ |
1010 | const dict_index_t* index, /*!< in: record descriptor */ |
1011 | ulint n_fields, /*!< in: number of fields |
1012 | to copy */ |
1013 | byte** buf, /*!< in/out: memory buffer |
1014 | for the copied prefix, |
1015 | or NULL */ |
1016 | ulint* buf_size) /*!< in/out: buffer size */ |
1017 | MY_ATTRIBUTE((nonnull)); |
1018 | /*********************************************************//** |
1019 | Builds a physical record out of a data tuple and |
1020 | stores it into the given buffer. |
1021 | @return pointer to the origin of physical record */ |
1022 | rec_t* |
1023 | rec_convert_dtuple_to_rec( |
1024 | /*======================*/ |
1025 | byte* buf, /*!< in: start address of the |
1026 | physical record */ |
1027 | const dict_index_t* index, /*!< in: record descriptor */ |
1028 | const dtuple_t* dtuple, /*!< in: data tuple */ |
1029 | ulint n_ext) /*!< in: number of |
1030 | externally stored columns */ |
1031 | MY_ATTRIBUTE((warn_unused_result)); |
1032 | /**********************************************************//** |
1033 | Returns the extra size of an old-style physical record if we know its |
1034 | data size and number of fields. |
1035 | @return extra size */ |
1036 | UNIV_INLINE |
1037 | ulint |
1038 | rec_get_converted_extra_size( |
1039 | /*=========================*/ |
1040 | ulint data_size, /*!< in: data size */ |
1041 | ulint n_fields, /*!< in: number of fields */ |
1042 | ulint n_ext) /*!< in: number of externally stored columns */ |
1043 | MY_ATTRIBUTE((const)); |
1044 | /**********************************************************//** |
1045 | Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT. |
1046 | @return total size */ |
1047 | ulint |
1048 | rec_get_converted_size_comp_prefix( |
1049 | /*===============================*/ |
1050 | const dict_index_t* index, /*!< in: record descriptor */ |
1051 | const dfield_t* fields, /*!< in: array of data fields */ |
1052 | ulint n_fields,/*!< in: number of data fields */ |
1053 | ulint* extra) /*!< out: extra size */ |
1054 | MY_ATTRIBUTE((warn_unused_result, nonnull(1,2))); |
1055 | /**********************************************************//** |
1056 | Determines the size of a data tuple in ROW_FORMAT=COMPACT. |
1057 | @return total size */ |
1058 | ulint |
1059 | rec_get_converted_size_comp( |
1060 | /*========================*/ |
1061 | const dict_index_t* index, /*!< in: record descriptor; |
1062 | dict_table_is_comp() is |
1063 | assumed to hold, even if |
1064 | it does not */ |
1065 | rec_comp_status_t status, /*!< in: status bits of the record */ |
1066 | const dfield_t* fields, /*!< in: array of data fields */ |
1067 | ulint n_fields,/*!< in: number of data fields */ |
1068 | ulint* extra) /*!< out: extra size */ |
1069 | MY_ATTRIBUTE((nonnull(1,3))); |
1070 | /**********************************************************//** |
1071 | The following function returns the size of a data tuple when converted to |
1072 | a physical record. |
1073 | @return size */ |
1074 | UNIV_INLINE |
1075 | ulint |
1076 | rec_get_converted_size( |
1077 | /*===================*/ |
1078 | dict_index_t* index, /*!< in: record descriptor */ |
1079 | const dtuple_t* dtuple, /*!< in: data tuple */ |
1080 | ulint n_ext) /*!< in: number of externally stored columns */ |
1081 | MY_ATTRIBUTE((warn_unused_result, nonnull)); |
1082 | /** Copy the first n fields of a (copy of a) physical record to a data tuple. |
1083 | The fields are copied into the memory heap. |
1084 | @param[out] tuple data tuple |
1085 | @param[in] rec index record, or a copy thereof |
1086 | @param[in] is_leaf whether rec is a leaf page record |
1087 | @param[in] n_fields number of fields to copy |
1088 | @param[in,out] heap memory heap */ |
1089 | void |
1090 | rec_copy_prefix_to_dtuple( |
1091 | dtuple_t* tuple, |
1092 | const rec_t* rec, |
1093 | const dict_index_t* index, |
1094 | bool is_leaf, |
1095 | ulint n_fields, |
1096 | mem_heap_t* heap) |
1097 | MY_ATTRIBUTE((nonnull)); |
1098 | /***************************************************************//** |
1099 | Validates the consistency of a physical record. |
1100 | @return TRUE if ok */ |
1101 | ibool |
1102 | rec_validate( |
1103 | /*=========*/ |
1104 | const rec_t* rec, /*!< in: physical record */ |
1105 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
1106 | MY_ATTRIBUTE((nonnull)); |
1107 | /***************************************************************//** |
1108 | Prints an old-style physical record. */ |
1109 | void |
1110 | rec_print_old( |
1111 | /*==========*/ |
1112 | FILE* file, /*!< in: file where to print */ |
1113 | const rec_t* rec) /*!< in: physical record */ |
1114 | MY_ATTRIBUTE((nonnull)); |
1115 | /***************************************************************//** |
1116 | Prints a spatial index record. */ |
1117 | void |
1118 | rec_print_mbr_rec( |
1119 | /*==========*/ |
1120 | FILE* file, /*!< in: file where to print */ |
1121 | const rec_t* rec, /*!< in: physical record */ |
1122 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
1123 | MY_ATTRIBUTE((nonnull)); |
1124 | /***************************************************************//** |
1125 | Prints a physical record. */ |
1126 | void |
1127 | rec_print_new( |
1128 | /*==========*/ |
1129 | FILE* file, /*!< in: file where to print */ |
1130 | const rec_t* rec, /*!< in: physical record */ |
1131 | const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ |
1132 | MY_ATTRIBUTE((nonnull)); |
1133 | /***************************************************************//** |
1134 | Prints a physical record. */ |
1135 | void |
1136 | rec_print( |
1137 | /*======*/ |
1138 | FILE* file, /*!< in: file where to print */ |
1139 | const rec_t* rec, /*!< in: physical record */ |
1140 | const dict_index_t* index) /*!< in: record descriptor */ |
1141 | MY_ATTRIBUTE((nonnull)); |
1142 | |
1143 | /** Pretty-print a record. |
1144 | @param[in,out] o output stream |
1145 | @param[in] rec physical record |
1146 | @param[in] info rec_get_info_bits(rec) |
1147 | @param[in] offsets rec_get_offsets(rec) */ |
1148 | void |
1149 | rec_print( |
1150 | std::ostream& o, |
1151 | const rec_t* rec, |
1152 | ulint info, |
1153 | const ulint* offsets); |
1154 | |
1155 | /** Wrapper for pretty-printing a record */ |
1156 | struct rec_index_print |
1157 | { |
1158 | /** Constructor */ |
1159 | rec_index_print(const rec_t* rec, const dict_index_t* index) : |
1160 | m_rec(rec), m_index(index) |
1161 | {} |
1162 | |
1163 | /** Record */ |
1164 | const rec_t* m_rec; |
1165 | /** Index */ |
1166 | const dict_index_t* m_index; |
1167 | }; |
1168 | |
1169 | /** Display a record. |
1170 | @param[in,out] o output stream |
1171 | @param[in] r record to display |
1172 | @return the output stream */ |
1173 | std::ostream& |
1174 | operator<<(std::ostream& o, const rec_index_print& r); |
1175 | |
1176 | /** Wrapper for pretty-printing a record */ |
1177 | struct rec_offsets_print |
1178 | { |
1179 | /** Constructor */ |
1180 | rec_offsets_print(const rec_t* rec, const ulint* offsets) : |
1181 | m_rec(rec), m_offsets(offsets) |
1182 | {} |
1183 | |
1184 | /** Record */ |
1185 | const rec_t* m_rec; |
1186 | /** Offsets to each field */ |
1187 | const ulint* m_offsets; |
1188 | }; |
1189 | |
1190 | /** Display a record. |
1191 | @param[in,out] o output stream |
1192 | @param[in] r record to display |
1193 | @return the output stream */ |
1194 | std::ostream& |
1195 | operator<<(std::ostream& o, const rec_offsets_print& r); |
1196 | |
1197 | # ifndef DBUG_OFF |
1198 | /** Pretty-printer of records and tuples */ |
1199 | class rec_printer : public std::ostringstream { |
1200 | public: |
1201 | /** Construct a pretty-printed record. |
1202 | @param rec record with header |
1203 | @param offsets rec_get_offsets(rec, ...) */ |
1204 | rec_printer(const rec_t* rec, const ulint* offsets) |
1205 | : |
1206 | std::ostringstream () |
1207 | { |
1208 | rec_print(*this, rec, |
1209 | rec_get_info_bits(rec, rec_offs_comp(offsets)), |
1210 | offsets); |
1211 | } |
1212 | |
1213 | /** Construct a pretty-printed record. |
1214 | @param rec record, possibly lacking header |
1215 | @param info rec_get_info_bits(rec) |
1216 | @param offsets rec_get_offsets(rec, ...) */ |
1217 | rec_printer(const rec_t* rec, ulint info, const ulint* offsets) |
1218 | : |
1219 | std::ostringstream () |
1220 | { |
1221 | rec_print(*this, rec, info, offsets); |
1222 | } |
1223 | |
1224 | /** Construct a pretty-printed tuple. |
1225 | @param tuple data tuple */ |
1226 | rec_printer(const dtuple_t* tuple) |
1227 | : |
1228 | std::ostringstream () |
1229 | { |
1230 | dtuple_print(*this, tuple); |
1231 | } |
1232 | |
1233 | /** Construct a pretty-printed tuple. |
1234 | @param field array of data tuple fields |
1235 | @param n number of fields */ |
1236 | rec_printer(const dfield_t* field, ulint n) |
1237 | : |
1238 | std::ostringstream () |
1239 | { |
1240 | dfield_print(*this, field, n); |
1241 | } |
1242 | |
1243 | /** Destructor */ |
1244 | virtual ~rec_printer() {} |
1245 | |
1246 | private: |
1247 | /** Copy constructor */ |
1248 | rec_printer(const rec_printer& other); |
1249 | /** Assignment operator */ |
1250 | rec_printer& operator=(const rec_printer& other); |
1251 | }; |
1252 | # endif /* !DBUG_OFF */ |
1253 | |
1254 | # ifdef UNIV_DEBUG |
1255 | /** Read the DB_TRX_ID of a clustered index record. |
1256 | @param[in] rec clustered index record |
1257 | @param[in] index clustered index |
1258 | @return the value of DB_TRX_ID */ |
1259 | trx_id_t |
1260 | rec_get_trx_id( |
1261 | const rec_t* rec, |
1262 | const dict_index_t* index) |
1263 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
1264 | # endif /* UNIV_DEBUG */ |
1265 | |
1266 | /* Maximum lengths for the data in a physical record if the offsets |
1267 | are given in one byte (resp. two byte) format. */ |
1268 | #define REC_1BYTE_OFFS_LIMIT 0x7FUL |
1269 | #define REC_2BYTE_OFFS_LIMIT 0x7FFFUL |
1270 | |
1271 | /* The data size of record must not be larger than this on |
1272 | REDUNDANT row format because we reserve two upmost bits in a |
1273 | two byte offset for special purposes */ |
1274 | #define REDUNDANT_REC_MAX_DATA_SIZE (16383) |
1275 | |
1276 | /* The data size of record must be smaller than this on |
1277 | COMPRESSED row format because we reserve two upmost bits in a |
1278 | two byte offset for special purposes */ |
1279 | #define COMPRESSED_REC_MAX_DATA_SIZE (16384) |
1280 | |
1281 | #ifdef WITH_WSREP |
1282 | int wsrep_rec_get_foreign_key( |
1283 | byte *buf, /* out: extracted key */ |
1284 | ulint *buf_len, /* in/out: length of buf */ |
1285 | const rec_t* rec, /* in: physical record */ |
1286 | dict_index_t* index_for, /* in: index for foreign table */ |
1287 | dict_index_t* index_ref, /* in: index for referenced table */ |
1288 | ibool new_protocol); /* in: protocol > 1 */ |
1289 | #endif /* WITH_WSREP */ |
1290 | |
1291 | #include "rem0rec.ic" |
1292 | |
1293 | #endif /* !UNIV_INNOCHECKSUM */ |
1294 | #endif /* rem0rec_h */ |
1295 | |