1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8 
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation.  The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License, version 2.0, for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24 
25 *****************************************************************************/
26 
27 /********************************************************************//**
28 @file include/rem0rec.h
29 Record manager
30 
31 Created 5/30/1994 Heikki Tuuri
32 *************************************************************************/
33 
34 #ifndef rem0rec_h
35 #define rem0rec_h
36 
37 #include "univ.i"
38 #include "data0data.h"
39 #include "rem0types.h"
40 #include "mtr0types.h"
41 #include "page0types.h"
42 
43 /* Info bit denoting the predefined minimum record: this bit is set
44 if and only if the record is the first user record on a non-leaf
45 B-tree page that is the leftmost page on its level
46 (PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
47 #define REC_INFO_MIN_REC_FLAG	0x10UL
48 /* The deleted flag in info bits */
49 #define REC_INFO_DELETED_FLAG	0x20UL	/* when bit is set to 1, it means the
50 					record has been delete marked */
51 
52 /* Number of extra bytes in an old-style record,
53 in addition to the data and the offsets */
54 #define REC_N_OLD_EXTRA_BYTES	6
55 /* Number of extra bytes in a new-style record,
56 in addition to the data and the offsets */
57 #define REC_N_NEW_EXTRA_BYTES	5
58 
59 /* Record status values */
60 #define REC_STATUS_ORDINARY	0
61 #define REC_STATUS_NODE_PTR	1
62 #define REC_STATUS_INFIMUM	2
63 #define REC_STATUS_SUPREMUM	3
64 
65 /* The following four constants are needed in page0zip.cc in order to
66 efficiently compress and decompress pages. */
67 
68 /* The offset of heap_no in a compact record */
69 #define REC_NEW_HEAP_NO		4
70 /* The shift of heap_no in a compact record.
71 The status is stored in the low-order bits. */
72 #define	REC_HEAP_NO_SHIFT	3
73 
74 /* Length of a B-tree node pointer, in bytes */
75 #define REC_NODE_PTR_SIZE	4
76 
77 /** SQL null flag in a 1-byte offset of ROW_FORMAT=REDUNDANT records */
78 #define REC_1BYTE_SQL_NULL_MASK	0x80UL
79 /** SQL null flag in a 2-byte offset of ROW_FORMAT=REDUNDANT records */
80 #define REC_2BYTE_SQL_NULL_MASK	0x8000UL
81 
82 /** In a 2-byte offset of ROW_FORMAT=REDUNDANT records, the second most
83 significant bit denotes that the tail of a field is stored off-page. */
84 #define REC_2BYTE_EXTERN_MASK	0x4000UL
85 
86 #ifdef UNIV_DEBUG
87 /* Length of the rec_get_offsets() header */
88 # define REC_OFFS_HEADER_SIZE	4
89 #else /* UNIV_DEBUG */
90 /* Length of the rec_get_offsets() header */
91 # define REC_OFFS_HEADER_SIZE	2
92 #endif /* UNIV_DEBUG */
93 
94 /* Number of elements that should be initially allocated for the
95 offsets[] array, first passed to rec_get_offsets() */
96 #define REC_OFFS_NORMAL_SIZE	100
97 #define REC_OFFS_SMALL_SIZE	10
98 
99 /******************************************************//**
100 The following function is used to get the pointer of the next chained record
101 on the same page.
102 @return	pointer to the next chained record, or NULL if none */
103 UNIV_INLINE
104 const rec_t*
105 rec_get_next_ptr_const(
106 /*===================*/
107 	const rec_t*	rec,	/*!< in: physical record */
108 	ulint		comp)	/*!< in: nonzero=compact page format */
109 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
110 /******************************************************//**
111 The following function is used to get the pointer of the next chained record
112 on the same page.
113 @return	pointer to the next chained record, or NULL if none */
114 UNIV_INLINE
115 rec_t*
116 rec_get_next_ptr(
117 /*=============*/
118 	rec_t*	rec,	/*!< in: physical record */
119 	ulint	comp)	/*!< in: nonzero=compact page format */
120 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
121 /******************************************************//**
122 The following function is used to get the offset of the
123 next chained record on the same page.
124 @return	the page offset of the next chained record, or 0 if none */
125 UNIV_INLINE
126 ulint
127 rec_get_next_offs(
128 /*==============*/
129 	const rec_t*	rec,	/*!< in: physical record */
130 	ulint		comp)	/*!< in: nonzero=compact page format */
131 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
132 /******************************************************//**
133 The following function is used to set the next record offset field
134 of an old-style record. */
135 UNIV_INLINE
136 void
137 rec_set_next_offs_old(
138 /*==================*/
139 	rec_t*	rec,	/*!< in: old-style physical record */
140 	ulint	next)	/*!< in: offset of the next record */
141 	MY_ATTRIBUTE((nonnull));
142 /******************************************************//**
143 The following function is used to set the next record offset field
144 of a new-style record. */
145 UNIV_INLINE
146 void
147 rec_set_next_offs_new(
148 /*==================*/
149 	rec_t*	rec,	/*!< in/out: new-style physical record */
150 	ulint	next)	/*!< in: offset of the next record */
151 	MY_ATTRIBUTE((nonnull));
152 /******************************************************//**
153 The following function is used to get the number of fields
154 in an old-style record.
155 @return	number of data fields */
156 UNIV_INLINE
157 ulint
158 rec_get_n_fields_old(
159 /*=================*/
160 	const rec_t*	rec)	/*!< in: physical record */
161 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
162 /******************************************************//**
163 The following function is used to get the number of fields
164 in a record.
165 @return	number of data fields */
166 UNIV_INLINE
167 ulint
168 rec_get_n_fields(
169 /*=============*/
170 	const rec_t*		rec,	/*!< in: physical record */
171 	const dict_index_t*	index)	/*!< in: record descriptor */
172 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
173 /******************************************************//**
174 The following function is used to get the number of records owned by the
175 previous directory record.
176 @return	number of owned records */
177 UNIV_INLINE
178 ulint
179 rec_get_n_owned_old(
180 /*================*/
181 	const rec_t*	rec)	/*!< in: old-style physical record */
182 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
183 /******************************************************//**
184 The following function is used to set the number of owned records. */
185 UNIV_INLINE
186 void
187 rec_set_n_owned_old(
188 /*================*/
189 	rec_t*	rec,		/*!< in: old-style physical record */
190 	ulint	n_owned)	/*!< in: the number of owned */
191 	MY_ATTRIBUTE((nonnull));
192 /******************************************************//**
193 The following function is used to get the number of records owned by the
194 previous directory record.
195 @return	number of owned records */
196 UNIV_INLINE
197 ulint
198 rec_get_n_owned_new(
199 /*================*/
200 	const rec_t*	rec)	/*!< in: new-style physical record */
201 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
202 /******************************************************//**
203 The following function is used to set the number of owned records. */
204 UNIV_INLINE
205 void
206 rec_set_n_owned_new(
207 /*================*/
208 	rec_t*		rec,	/*!< in/out: new-style physical record */
209 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
210 	ulint		n_owned)/*!< in: the number of owned */
211 	MY_ATTRIBUTE((nonnull(1)));
212 /******************************************************//**
213 The following function is used to retrieve the info bits of
214 a record.
215 @return	info bits */
216 UNIV_INLINE
217 ulint
218 rec_get_info_bits(
219 /*==============*/
220 	const rec_t*	rec,	/*!< in: physical record */
221 	ulint		comp)	/*!< in: nonzero=compact page format */
222 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
223 /******************************************************//**
224 The following function is used to set the info bits of a record. */
225 UNIV_INLINE
226 void
227 rec_set_info_bits_old(
228 /*==================*/
229 	rec_t*	rec,	/*!< in: old-style physical record */
230 	ulint	bits)	/*!< in: info bits */
231 	MY_ATTRIBUTE((nonnull));
232 /******************************************************//**
233 The following function is used to set the info bits of a record. */
234 UNIV_INLINE
235 void
236 rec_set_info_bits_new(
237 /*==================*/
238 	rec_t*	rec,	/*!< in/out: new-style physical record */
239 	ulint	bits)	/*!< in: info bits */
240 	MY_ATTRIBUTE((nonnull));
241 /******************************************************//**
242 The following function retrieves the status bits of a new-style record.
243 @return	status bits */
244 UNIV_INLINE
245 ulint
246 rec_get_status(
247 /*===========*/
248 	const rec_t*	rec)	/*!< in: physical record */
249 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
250 
251 /******************************************************//**
252 The following function is used to set the status bits of a new-style record. */
253 UNIV_INLINE
254 void
255 rec_set_status(
256 /*===========*/
257 	rec_t*	rec,	/*!< in/out: physical record */
258 	ulint	bits)	/*!< in: info bits */
259 	MY_ATTRIBUTE((nonnull));
260 
261 /******************************************************//**
262 The following function is used to retrieve the info and status
263 bits of a record.  (Only compact records have status bits.)
264 @return	info bits */
265 UNIV_INLINE
266 ulint
267 rec_get_info_and_status_bits(
268 /*=========================*/
269 	const rec_t*	rec,	/*!< in: physical record */
270 	ulint		comp)	/*!< in: nonzero=compact page format */
271 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
272 /******************************************************//**
273 The following function is used to set the info and status
274 bits of a record.  (Only compact records have status bits.) */
275 UNIV_INLINE
276 void
277 rec_set_info_and_status_bits(
278 /*=========================*/
279 	rec_t*	rec,	/*!< in/out: compact physical record */
280 	ulint	bits)	/*!< in: info bits */
281 	MY_ATTRIBUTE((nonnull));
282 
283 /******************************************************//**
284 The following function tells if record is delete marked.
285 @return	nonzero if delete marked */
286 UNIV_INLINE
287 ulint
288 rec_get_deleted_flag(
289 /*=================*/
290 	const rec_t*	rec,	/*!< in: physical record */
291 	ulint		comp)	/*!< in: nonzero=compact page format */
292 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
293 /******************************************************//**
294 The following function is used to set the deleted bit. */
295 UNIV_INLINE
296 void
297 rec_set_deleted_flag_old(
298 /*=====================*/
299 	rec_t*	rec,	/*!< in: old-style physical record */
300 	ulint	flag)	/*!< in: nonzero if delete marked */
301 	MY_ATTRIBUTE((nonnull));
302 /******************************************************//**
303 The following function is used to set the deleted bit. */
304 UNIV_INLINE
305 void
306 rec_set_deleted_flag_new(
307 /*=====================*/
308 	rec_t*		rec,	/*!< in/out: new-style physical record */
309 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
310 	ulint		flag)	/*!< in: nonzero if delete marked */
311 	MY_ATTRIBUTE((nonnull(1)));
312 /******************************************************//**
313 The following function tells if a new-style record is a node pointer.
314 @return	TRUE if node pointer */
315 UNIV_INLINE
316 ibool
317 rec_get_node_ptr_flag(
318 /*==================*/
319 	const rec_t*	rec)	/*!< in: physical record */
320 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
321 /******************************************************//**
322 The following function is used to get the order number
323 of an old-style record in the heap of the index page.
324 @return	heap order number */
325 UNIV_INLINE
326 ulint
327 rec_get_heap_no_old(
328 /*================*/
329 	const rec_t*	rec)	/*!< in: physical record */
330 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
331 /******************************************************//**
332 The following function is used to set the heap number
333 field in an old-style record. */
334 UNIV_INLINE
335 void
336 rec_set_heap_no_old(
337 /*================*/
338 	rec_t*	rec,	/*!< in: physical record */
339 	ulint	heap_no)/*!< in: the heap number */
340 	MY_ATTRIBUTE((nonnull));
341 /******************************************************//**
342 The following function is used to get the order number
343 of a new-style record in the heap of the index page.
344 @return	heap order number */
345 UNIV_INLINE
346 ulint
347 rec_get_heap_no_new(
348 /*================*/
349 	const rec_t*	rec)	/*!< in: physical record */
350 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
351 /******************************************************//**
352 The following function is used to set the heap number
353 field in a new-style record. */
354 UNIV_INLINE
355 void
356 rec_set_heap_no_new(
357 /*================*/
358 	rec_t*	rec,	/*!< in/out: physical record */
359 	ulint	heap_no)/*!< in: the heap number */
360 	MY_ATTRIBUTE((nonnull));
361 /******************************************************//**
362 The following function is used to test whether the data offsets
363 in the record are stored in one-byte or two-byte format.
364 @return	TRUE if 1-byte form */
365 UNIV_INLINE
366 ibool
367 rec_get_1byte_offs_flag(
368 /*====================*/
369 	const rec_t*	rec)	/*!< in: physical record */
370 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
371 
372 /******************************************************//**
373 The following function is used to set the 1-byte offsets flag. */
374 UNIV_INLINE
375 void
376 rec_set_1byte_offs_flag(
377 /*====================*/
378 	rec_t*	rec,	/*!< in: physical record */
379 	ibool	flag)	/*!< in: TRUE if 1byte form */
380 	MY_ATTRIBUTE((nonnull));
381 
382 /******************************************************//**
383 Returns the offset of nth field end if the record is stored in the 1-byte
384 offsets form. If the field is SQL null, the flag is ORed in the returned
385 value.
386 @return	offset of the start of the field, SQL null flag ORed */
387 UNIV_INLINE
388 ulint
389 rec_1_get_field_end_info(
390 /*=====================*/
391 	const rec_t*	rec,	/*!< in: record */
392 	ulint		n)	/*!< in: field index */
393 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
394 
395 /******************************************************//**
396 Returns the offset of nth field end if the record is stored in the 2-byte
397 offsets form. If the field is SQL null, the flag is ORed in the returned
398 value.
399 @return offset of the start of the field, SQL null flag and extern
400 storage flag ORed */
401 UNIV_INLINE
402 ulint
403 rec_2_get_field_end_info(
404 /*=====================*/
405 	const rec_t*	rec,	/*!< in: record */
406 	ulint		n)	/*!< in: field index */
407 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
408 
409 /******************************************************//**
410 Returns nonzero if the field is stored off-page.
411 @retval 0 if the field is stored in-page
412 @retval REC_2BYTE_EXTERN_MASK if the field is stored externally */
413 UNIV_INLINE
414 ulint
415 rec_2_is_field_extern(
416 /*==================*/
417 	const rec_t*	rec,	/*!< in: record */
418 	ulint		n)	/*!< in: field index */
419 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
420 
421 /******************************************************//**
422 Determine how many of the first n columns in a compact
423 physical record are stored externally.
424 @return	number of externally stored columns */
425 UNIV_INTERN
426 ulint
427 rec_get_n_extern_new(
428 /*=================*/
429 	const rec_t*		rec,	/*!< in: compact physical record */
430 	const dict_index_t*	index,	/*!< in: record descriptor */
431 	ulint			n)	/*!< in: number of columns to scan */
432 	MY_ATTRIBUTE((nonnull, warn_unused_result));
433 
434 /******************************************************//**
435 The following function determines the offsets to each field
436 in the record.	It can reuse a previously allocated array.
437 @return	the new offsets */
438 UNIV_INTERN
439 ulint*
440 rec_get_offsets_func(
441 /*=================*/
442 	const rec_t*		rec,	/*!< in: physical record */
443 	const dict_index_t*	index,	/*!< in: record descriptor */
444 	ulint*			offsets,/*!< in/out: array consisting of
445 					offsets[0] allocated elements,
446 					or an array from rec_get_offsets(),
447 					or NULL */
448 	ulint			n_fields,/*!< in: maximum number of
449 					initialized fields
450 					 (ULINT_UNDEFINED if all fields) */
451 #ifdef UNIV_DEBUG
452 	const char*		file,	/*!< in: file name where called */
453 	ulint			line,	/*!< in: line number where called */
454 #endif /* UNIV_DEBUG */
455 	mem_heap_t**		heap)	/*!< in/out: memory heap */
456 #ifdef UNIV_DEBUG
457 	MY_ATTRIBUTE((nonnull(1,2,5,7),warn_unused_result));
458 #else /* UNIV_DEBUG */
459 	MY_ATTRIBUTE((nonnull(1,2,5),warn_unused_result));
460 #endif /* UNIV_DEBUG */
461 
462 #ifdef UNIV_DEBUG
463 # define rec_get_offsets(rec,index,offsets,n,heap)			\
464 	rec_get_offsets_func(rec,index,offsets,n,__FILE__,__LINE__,heap)
465 #else /* UNIV_DEBUG */
466 # define rec_get_offsets(rec, index, offsets, n, heap)	\
467 	rec_get_offsets_func(rec, index, offsets, n, heap)
468 #endif /* UNIV_DEBUG */
469 
470 /******************************************************//**
471 The following function determines the offsets to each field
472 in the record.  It can reuse a previously allocated array. */
473 UNIV_INTERN
474 void
475 rec_get_offsets_reverse(
476 /*====================*/
477 	const byte*		extra,	/*!< in: the extra bytes of a
478 					compact record in reverse order,
479 					excluding the fixed-size
480 					REC_N_NEW_EXTRA_BYTES */
481 	const dict_index_t*	index,	/*!< in: record descriptor */
482 	ulint			node_ptr,/*!< in: nonzero=node pointer,
483 					0=leaf node */
484 	ulint*			offsets)/*!< in/out: array consisting of
485 					offsets[0] allocated elements */
486 	MY_ATTRIBUTE((nonnull));
487 #ifdef UNIV_DEBUG
488 /************************************************************//**
489 Validates offsets returned by rec_get_offsets().
490 @return	TRUE if valid */
491 UNIV_INLINE
492 ibool
493 rec_offs_validate(
494 /*==============*/
495 	const rec_t*		rec,	/*!< in: record or NULL */
496 	const dict_index_t*	index,	/*!< in: record descriptor or NULL */
497 	const ulint*		offsets)/*!< in: array returned by
498 					rec_get_offsets() */
499 	MY_ATTRIBUTE((nonnull(3), warn_unused_result));
500 /************************************************************//**
501 Updates debug data in offsets, in order to avoid bogus
502 rec_offs_validate() failures. */
503 UNIV_INLINE
504 void
505 rec_offs_make_valid(
506 /*================*/
507 	const rec_t*		rec,	/*!< in: record */
508 	const dict_index_t*	index,	/*!< in: record descriptor */
509 	ulint*			offsets)/*!< in: array returned by
510 					rec_get_offsets() */
511 	MY_ATTRIBUTE((nonnull));
512 #else
513 # define rec_offs_make_valid(rec, index, offsets) ((void) 0)
514 #endif /* UNIV_DEBUG */
515 
516 /************************************************************//**
517 The following function is used to get the offset to the nth
518 data field in an old-style record.
519 @return	offset to the field */
520 UNIV_INTERN
521 ulint
522 rec_get_nth_field_offs_old(
523 /*=======================*/
524 	const rec_t*	rec,	/*!< in: record */
525 	ulint		n,	/*!< in: index of the field */
526 	ulint*		len)	/*!< out: length of the field; UNIV_SQL_NULL
527 				if SQL null */
528 	MY_ATTRIBUTE((nonnull));
529 #define rec_get_nth_field_old(rec, n, len) \
530 ((rec) + rec_get_nth_field_offs_old(rec, n, len))
531 /************************************************************//**
532 Gets the physical size of an old-style field.
533 Also an SQL null may have a field of size > 0,
534 if the data type is of a fixed size.
535 @return	field size in bytes */
536 UNIV_INLINE
537 ulint
538 rec_get_nth_field_size(
539 /*===================*/
540 	const rec_t*	rec,	/*!< in: record */
541 	ulint		n)	/*!< in: index of the field */
542 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
543 /************************************************************//**
544 The following function is used to get an offset to the nth
545 data field in a record.
546 @return	offset from the origin of rec */
547 UNIV_INLINE
548 ulint
549 rec_get_nth_field_offs(
550 /*===================*/
551 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
552 	ulint		n,	/*!< in: index of the field */
553 	ulint*		len)	/*!< out: length of the field; UNIV_SQL_NULL
554 				if SQL null */
555 	MY_ATTRIBUTE((nonnull));
556 #define rec_get_nth_field(rec, offsets, n, len) \
557 ((rec) + rec_get_nth_field_offs(offsets, n, len))
558 /******************************************************//**
559 Determine if the offsets are for a record in the new
560 compact format.
561 @return	nonzero if compact format */
562 UNIV_INLINE
563 ulint
564 rec_offs_comp(
565 /*==========*/
566 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
567 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
568 /******************************************************//**
569 Determine if the offsets are for a record containing
570 externally stored columns.
571 @return	nonzero if externally stored */
572 UNIV_INLINE
573 ulint
574 rec_offs_any_extern(
575 /*================*/
576 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
577 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
578 /******************************************************//**
579 Determine if the offsets are for a record containing null BLOB pointers.
580 @return	first field containing a null BLOB pointer, or NULL if none found */
581 UNIV_INLINE
582 const byte*
583 rec_offs_any_null_extern(
584 /*=====================*/
585 	const rec_t*	rec,		/*!< in: record */
586 	const ulint*	offsets)	/*!< in: rec_get_offsets(rec) */
587 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
588 /******************************************************//**
589 Returns nonzero if the extern bit is set in nth field of rec.
590 @return	nonzero if externally stored */
591 UNIV_INLINE
592 ulint
593 rec_offs_nth_extern(
594 /*================*/
595 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
596 	ulint		n)	/*!< in: nth field */
597 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
598 /******************************************************//**
599 Returns nonzero if the SQL NULL bit is set in nth field of rec.
600 @return	nonzero if SQL NULL */
601 UNIV_INLINE
602 ulint
603 rec_offs_nth_sql_null(
604 /*==================*/
605 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
606 	ulint		n)	/*!< in: nth field */
607 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
608 /******************************************************//**
609 Gets the physical size of a field.
610 @return	length of field */
611 UNIV_INLINE
612 ulint
613 rec_offs_nth_size(
614 /*==============*/
615 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
616 	ulint		n)	/*!< in: nth field */
617 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
618 
619 /******************************************************//**
620 Returns the number of extern bits set in a record.
621 @return	number of externally stored fields */
622 UNIV_INLINE
623 ulint
624 rec_offs_n_extern(
625 /*==============*/
626 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
627 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
628 /***********************************************************//**
629 This is used to modify the value of an already existing field in a record.
630 The previous value must have exactly the same size as the new value. If len
631 is UNIV_SQL_NULL then the field is treated as an SQL null.
632 For records in ROW_FORMAT=COMPACT (new-style records), len must not be
633 UNIV_SQL_NULL unless the field already is SQL null. */
634 UNIV_INLINE
635 void
636 rec_set_nth_field(
637 /*==============*/
638 	rec_t*		rec,	/*!< in: record */
639 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
640 	ulint		n,	/*!< in: index number of the field */
641 	const void*	data,	/*!< in: pointer to the data if not SQL null */
642 	ulint		len)	/*!< in: length of the data or UNIV_SQL_NULL.
643 				If not SQL null, must have the same
644 				length as the previous value.
645 				If SQL null, previous value must be
646 				SQL null. */
647 	MY_ATTRIBUTE((nonnull(1,2)));
648 /**********************************************************//**
649 The following function returns the data size of an old-style physical
650 record, that is the sum of field lengths. SQL null fields
651 are counted as length 0 fields. The value returned by the function
652 is the distance from record origin to record end in bytes.
653 @return	size */
654 UNIV_INLINE
655 ulint
656 rec_get_data_size_old(
657 /*==================*/
658 	const rec_t*	rec)	/*!< in: physical record */
659 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
660 /**********************************************************//**
661 The following function returns the number of allocated elements
662 for an array of offsets.
663 @return	number of elements */
664 UNIV_INLINE
665 ulint
666 rec_offs_get_n_alloc(
667 /*=================*/
668 	const ulint*	offsets)/*!< in: array for rec_get_offsets() */
669 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
670 /**********************************************************//**
671 The following function sets the number of allocated elements
672 for an array of offsets. */
673 UNIV_INLINE
674 void
675 rec_offs_set_n_alloc(
676 /*=================*/
677 	ulint*	offsets,	/*!< out: array for rec_get_offsets(),
678 				must be allocated */
679 	ulint	n_alloc)	/*!< in: number of elements */
680 	MY_ATTRIBUTE((nonnull));
681 #define rec_offs_init(offsets) \
682 	rec_offs_set_n_alloc(offsets, (sizeof offsets) / sizeof *offsets)
683 /**********************************************************//**
684 The following function returns the number of fields in a record.
685 @return	number of fields */
686 UNIV_INLINE
687 ulint
688 rec_offs_n_fields(
689 /*==============*/
690 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
691 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
692 /**********************************************************//**
693 The following function returns the data size of a physical
694 record, that is the sum of field lengths. SQL null fields
695 are counted as length 0 fields. The value returned by the function
696 is the distance from record origin to record end in bytes.
697 @return	size */
698 UNIV_INLINE
699 ulint
700 rec_offs_data_size(
701 /*===============*/
702 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
703 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
704 /**********************************************************//**
705 Returns the total size of record minus data size of record.
706 The value returned by the function is the distance from record
707 start to record origin in bytes.
708 @return	size */
709 UNIV_INLINE
710 ulint
711 rec_offs_extra_size(
712 /*================*/
713 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
714 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
715 /**********************************************************//**
716 Returns the total size of a physical record.
717 @return	size */
718 UNIV_INLINE
719 ulint
720 rec_offs_size(
721 /*==========*/
722 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
723 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
724 #ifdef UNIV_DEBUG
725 /**********************************************************//**
726 Returns a pointer to the start of the record.
727 @return	pointer to start */
728 UNIV_INLINE
729 byte*
730 rec_get_start(
731 /*==========*/
732 	const rec_t*	rec,	/*!< in: pointer to record */
733 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
734 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
735 /**********************************************************//**
736 Returns a pointer to the end of the record.
737 @return	pointer to end */
738 UNIV_INLINE
739 byte*
740 rec_get_end(
741 /*========*/
742 	const rec_t*	rec,	/*!< in: pointer to record */
743 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
744 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
745 #else /* UNIV_DEBUG */
746 # define rec_get_start(rec, offsets) ((rec) - rec_offs_extra_size(offsets))
747 # define rec_get_end(rec, offsets) ((rec) + rec_offs_data_size(offsets))
748 #endif /* UNIV_DEBUG */
749 /***************************************************************//**
750 Copies a physical record to a buffer.
751 @return	pointer to the origin of the copy */
752 UNIV_INLINE
753 rec_t*
754 rec_copy(
755 /*=====*/
756 	void*		buf,	/*!< in: buffer */
757 	const rec_t*	rec,	/*!< in: physical record */
758 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
759 	MY_ATTRIBUTE((nonnull));
760 #ifndef UNIV_HOTBACKUP
761 /**********************************************************//**
762 Determines the size of a data tuple prefix in a temporary file.
763 @return	total size */
764 UNIV_INTERN
765 ulint
766 rec_get_converted_size_temp(
767 /*========================*/
768 	const dict_index_t*	index,	/*!< in: record descriptor */
769 	const dfield_t*		fields,	/*!< in: array of data fields */
770 	ulint			n_fields,/*!< in: number of data fields */
771 	ulint*			extra)	/*!< out: extra size */
772 	MY_ATTRIBUTE((warn_unused_result, nonnull));
773 
774 /******************************************************//**
775 Determine the offset to each field in temporary file.
776 @see rec_convert_dtuple_to_temp() */
777 UNIV_INTERN
778 void
779 rec_init_offsets_temp(
780 /*==================*/
781 	const rec_t*		rec,	/*!< in: temporary file record */
782 	const dict_index_t*	index,	/*!< in: record descriptor */
783 	ulint*			offsets)/*!< in/out: array of offsets;
784 					in: n=rec_offs_n_fields(offsets) */
785 	MY_ATTRIBUTE((nonnull));
786 
787 /*********************************************************//**
788 Builds a temporary file record out of a data tuple.
789 @see rec_init_offsets_temp() */
790 UNIV_INTERN
791 void
792 rec_convert_dtuple_to_temp(
793 /*=======================*/
794 	rec_t*			rec,		/*!< out: record */
795 	const dict_index_t*	index,		/*!< in: record descriptor */
796 	const dfield_t*		fields,		/*!< in: array of data fields */
797 	ulint			n_fields)	/*!< in: number of fields */
798 	MY_ATTRIBUTE((nonnull));
799 
800 /**************************************************************//**
801 Copies the first n fields of a physical record to a new physical record in
802 a buffer.
803 @return	own: copied record */
804 UNIV_INTERN
805 rec_t*
806 rec_copy_prefix_to_buf(
807 /*===================*/
808 	const rec_t*		rec,		/*!< in: physical record */
809 	const dict_index_t*	index,		/*!< in: record descriptor */
810 	ulint			n_fields,	/*!< in: number of fields
811 						to copy */
812 	byte**			buf,		/*!< in/out: memory buffer
813 						for the copied prefix,
814 						or NULL */
815 	ulint*			buf_size)	/*!< in/out: buffer size */
816 	MY_ATTRIBUTE((nonnull));
817 /************************************************************//**
818 Folds a prefix of a physical record to a ulint.
819 @return	the folded value */
820 UNIV_INLINE
821 ulint
822 rec_fold(
823 /*=====*/
824 	const rec_t*	rec,		/*!< in: the physical record */
825 	const ulint*	offsets,	/*!< in: array returned by
826 					rec_get_offsets() */
827 	ulint		n_fields,	/*!< in: number of complete
828 					fields to fold */
829 	ulint		n_bytes,	/*!< in: number of bytes to fold
830 					in an incomplete last field */
831 	index_id_t	tree_id)	/*!< in: index tree id */
832 	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
833 #endif /* !UNIV_HOTBACKUP */
834 /*********************************************************//**
835 Builds a physical record out of a data tuple and
836 stores it into the given buffer.
837 @return	pointer to the origin of physical record */
838 UNIV_INTERN
839 rec_t*
840 rec_convert_dtuple_to_rec(
841 /*======================*/
842 	byte*			buf,	/*!< in: start address of the
843 					physical record */
844 	const dict_index_t*	index,	/*!< in: record descriptor */
845 	const dtuple_t*		dtuple,	/*!< in: data tuple */
846 	ulint			n_ext)	/*!< in: number of
847 					externally stored columns */
848 	MY_ATTRIBUTE((nonnull, warn_unused_result));
849 /**********************************************************//**
850 Returns the extra size of an old-style physical record if we know its
851 data size and number of fields.
852 @return	extra size */
853 UNIV_INLINE
854 ulint
855 rec_get_converted_extra_size(
856 /*=========================*/
857 	ulint	data_size,	/*!< in: data size */
858 	ulint	n_fields,	/*!< in: number of fields */
859 	ulint	n_ext)		/*!< in: number of externally stored columns */
860 	MY_ATTRIBUTE((const));
861 /**********************************************************//**
862 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
863 @return	total size */
864 UNIV_INTERN
865 ulint
866 rec_get_converted_size_comp_prefix(
867 /*===============================*/
868 	const dict_index_t*	index,	/*!< in: record descriptor */
869 	const dfield_t*		fields,	/*!< in: array of data fields */
870 	ulint			n_fields,/*!< in: number of data fields */
871 	ulint*			extra)	/*!< out: extra size */
872 	MY_ATTRIBUTE((warn_unused_result, nonnull(1,2)));
873 /**********************************************************//**
874 Determines the size of a data tuple in ROW_FORMAT=COMPACT.
875 @return	total size */
876 UNIV_INTERN
877 ulint
878 rec_get_converted_size_comp(
879 /*========================*/
880 	const dict_index_t*	index,	/*!< in: record descriptor;
881 					dict_table_is_comp() is
882 					assumed to hold, even if
883 					it does not */
884 	ulint			status,	/*!< in: status bits of the record */
885 	const dfield_t*		fields,	/*!< in: array of data fields */
886 	ulint			n_fields,/*!< in: number of data fields */
887 	ulint*			extra)	/*!< out: extra size */
888 	MY_ATTRIBUTE((nonnull(1,3)));
889 /**********************************************************//**
890 The following function returns the size of a data tuple when converted to
891 a physical record.
892 @return	size */
893 UNIV_INLINE
894 ulint
895 rec_get_converted_size(
896 /*===================*/
897 	dict_index_t*	index,	/*!< in: record descriptor */
898 	const dtuple_t*	dtuple,	/*!< in: data tuple */
899 	ulint		n_ext)	/*!< in: number of externally stored columns */
900 	MY_ATTRIBUTE((warn_unused_result, nonnull));
901 #ifndef UNIV_HOTBACKUP
902 /**************************************************************//**
903 Copies the first n fields of a physical record to a data tuple.
904 The fields are copied to the memory heap. */
905 UNIV_INTERN
906 void
907 rec_copy_prefix_to_dtuple(
908 /*======================*/
909 	dtuple_t*		tuple,		/*!< out: data tuple */
910 	const rec_t*		rec,		/*!< in: physical record */
911 	const dict_index_t*	index,		/*!< in: record descriptor */
912 	ulint			n_fields,	/*!< in: number of fields
913 						to copy */
914 	mem_heap_t*		heap)		/*!< in: memory heap */
915 	MY_ATTRIBUTE((nonnull));
916 #endif /* !UNIV_HOTBACKUP */
917 /***************************************************************//**
918 Validates the consistency of a physical record.
919 @return	TRUE if ok */
920 UNIV_INTERN
921 ibool
922 rec_validate(
923 /*=========*/
924 	const rec_t*	rec,	/*!< in: physical record */
925 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
926 	MY_ATTRIBUTE((nonnull));
927 /***************************************************************//**
928 Prints an old-style physical record. */
929 UNIV_INTERN
930 void
931 rec_print_old(
932 /*==========*/
933 	FILE*		file,	/*!< in: file where to print */
934 	const rec_t*	rec)	/*!< in: physical record */
935 	MY_ATTRIBUTE((nonnull));
936 #ifndef UNIV_HOTBACKUP
937 /***************************************************************//**
938 Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
939 record header. */
940 UNIV_INTERN
941 void
942 rec_print_comp(
943 /*===========*/
944 	FILE*		file,	/*!< in: file where to print */
945 	const rec_t*	rec,	/*!< in: physical record */
946 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
947 	MY_ATTRIBUTE((nonnull));
948 /***************************************************************//**
949 Prints a physical record. */
950 UNIV_INTERN
951 void
952 rec_print_new(
953 /*==========*/
954 	FILE*		file,	/*!< in: file where to print */
955 	const rec_t*	rec,	/*!< in: physical record */
956 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
957 	MY_ATTRIBUTE((nonnull));
958 /***************************************************************//**
959 Prints a physical record. */
960 UNIV_INTERN
961 void
962 rec_print(
963 /*======*/
964 	FILE*			file,	/*!< in: file where to print */
965 	const rec_t*		rec,	/*!< in: physical record */
966 	const dict_index_t*	index)	/*!< in: record descriptor */
967 	MY_ATTRIBUTE((nonnull));
968 
969 # ifdef UNIV_DEBUG
970 /************************************************************//**
971 Reads the DB_TRX_ID of a clustered index record.
972 @return	the value of DB_TRX_ID */
973 UNIV_INTERN
974 trx_id_t
975 rec_get_trx_id(
976 /*===========*/
977 	const rec_t*		rec,	/*!< in: record */
978 	const dict_index_t*	index)	/*!< in: clustered index */
979 	MY_ATTRIBUTE((nonnull, warn_unused_result));
980 # endif /* UNIV_DEBUG */
981 #endif /* UNIV_HOTBACKUP */
982 
983 /* Maximum lengths for the data in a physical record if the offsets
984 are given in one byte (resp. two byte) format. */
985 #define REC_1BYTE_OFFS_LIMIT	0x7FUL
986 #define REC_2BYTE_OFFS_LIMIT	0x7FFFUL
987 
988 /* The data size of record must be smaller than this because we reserve
989 two upmost bits in a two byte offset for special purposes */
990 #define REC_MAX_DATA_SIZE	(16 * 1024)
991 
992 #ifdef WITH_WSREP
993 dberr_t wsrep_rec_get_foreign_key(
994 	byte 		*buf,     /* out: extracted key */
995 	ulint 		*buf_len, /* in/out: length of buf */
996 	const rec_t*	rec,	  /* in: physical record */
997 	dict_index_t*	index_for,  /* in: index for foreign table */
998 	dict_index_t*	index_ref,  /* in: index for referenced table */
999 	ibool		new_protocol); /* in: protocol > 1 */
1000 #endif /* WITH_WSREP */
1001 #ifndef UNIV_NONINL
1002 #include "rem0rec.ic"
1003 #endif
1004 
1005 #endif
1006