1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2021, Oracle and/or its affiliates.
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 rem/rem0rec.cc
29 Record manager
30 
31 Created 5/30/1994 Heikki Tuuri
32 *************************************************************************/
33 
34 #include "rem0rec.h"
35 
36 #ifdef UNIV_NONINL
37 #include "rem0rec.ic"
38 #endif
39 
40 #include "page0page.h"
41 #include "mtr0mtr.h"
42 #include "mtr0log.h"
43 #include "fts0fts.h"
44 #include "gis0geo.h"
45 #include "trx0sys.h"
46 #ifdef WITH_WSREP
47 #include <ha_prototypes.h>
48 #endif /* WITH_WSREP */
49 #include "mach0data.h"
50 
51 /*			PHYSICAL RECORD (OLD STYLE)
52 			===========================
53 
54 The physical record, which is the data type of all the records
55 found in index pages of the database, has the following format
56 (lower addresses and more significant bits inside a byte are below
57 represented on a higher text line):
58 
59 | offset of the end of the last field of data, the most significant
60   bit is set to 1 if and only if the field is SQL-null,
61   if the offset is 2-byte, then the second most significant
62   bit is set to 1 if the field is stored on another page:
63   mostly this will occur in the case of big BLOB fields |
64 ...
65 | offset of the end of the first field of data + the SQL-null bit |
66 | 4 bits used to delete mark a record, and mark a predefined
67   minimum record in alphabetical order |
68 | 4 bits giving the number of records owned by this record
69   (this term is explained in page0page.h) |
70 | 13 bits giving the order number of this record in the
71   heap of the index page |
72 | 10 bits giving the number of fields in this record |
73 | 1 bit which is set to 1 if the offsets above are given in
74   one byte format, 0 if in two byte format |
75 | two bytes giving an absolute pointer to the next record in the page |
76 ORIGIN of the record
77 | first field of data |
78 ...
79 | last field of data |
80 
81 The origin of the record is the start address of the first field
82 of data. The offsets are given relative to the origin.
83 The offsets of the data fields are stored in an inverted
84 order because then the offset of the first fields are near the
85 origin, giving maybe a better processor cache hit rate in searches.
86 
87 The offsets of the data fields are given as one-byte
88 (if there are less than 127 bytes of data in the record)
89 or two-byte unsigned integers. The most significant bit
90 is not part of the offset, instead it indicates the SQL-null
91 if the bit is set to 1. */
92 
93 /*			PHYSICAL RECORD (NEW STYLE)
94 			===========================
95 
96 The physical record, which is the data type of all the records
97 found in index pages of the database, has the following format
98 (lower addresses and more significant bits inside a byte are below
99 represented on a higher text line):
100 
101 | length of the last non-null variable-length field of data:
102   if the maximum length is 255, one byte; otherwise,
103   0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
104   length=128..16383, extern storage flag) |
105 ...
106 | length of first variable-length field of data |
107 | SQL-null flags (1 bit per nullable field), padded to full bytes |
108 | 4 bits used to delete mark a record, and mark a predefined
109   minimum record in alphabetical order |
110 | 4 bits giving the number of records owned by this record
111   (this term is explained in page0page.h) |
112 | 13 bits giving the order number of this record in the
113   heap of the index page |
114 | 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
115   010=infimum, 011=supremum, 1xx=reserved |
116 | two bytes giving a relative pointer to the next record in the page |
117 ORIGIN of the record
118 | first field of data |
119 ...
120 | last field of data |
121 
122 The origin of the record is the start address of the first field
123 of data. The offsets are given relative to the origin.
124 The offsets of the data fields are stored in an inverted
125 order because then the offset of the first fields are near the
126 origin, giving maybe a better processor cache hit rate in searches.
127 
128 The offsets of the data fields are given as one-byte
129 (if there are less than 127 bytes of data in the record)
130 or two-byte unsigned integers. The most significant bit
131 is not part of the offset, instead it indicates the SQL-null
132 if the bit is set to 1. */
133 
134 /* CANONICAL COORDINATES. A record can be seen as a single
135 string of 'characters' in the following way: catenate the bytes
136 in each field, in the order of fields. An SQL-null field
137 is taken to be an empty sequence of bytes. Then after
138 the position of each field insert in the string
139 the 'character' <FIELD-END>, except that after an SQL-null field
140 insert <NULL-FIELD-END>. Now the ordinal position of each
141 byte in this canonical string is its canonical coordinate.
142 So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
143 string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
144 We identify prefixes (= initial segments) of a record
145 with prefixes of the canonical string. The canonical
146 length of the prefix is the length of the corresponding
147 prefix of the canonical string. The canonical length of
148 a record is the length of its canonical string.
149 
150 For example, the maximal common prefix of records
151 ("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
152 is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
153 length is 5.
154 
155 A complete-field prefix of a record is a prefix which ends at the
156 end of some field (containing also <FIELD-END>).
157 A record is a complete-field prefix of another record, if
158 the corresponding canonical strings have the same property. */
159 
160 /* this is used to fool compiler in rec_validate */
161 ulint	rec_dummy;
162 
163 /***************************************************************//**
164 Validates the consistency of an old-style physical record.
165 @return TRUE if ok */
166 static
167 ibool
168 rec_validate_old(
169 /*=============*/
170 	const rec_t*	rec);	/*!< in: physical record */
171 
172 /******************************************************//**
173 Determine how many of the first n columns in a compact
174 physical record are stored externally.
175 @return number of externally stored columns */
176 ulint
rec_get_n_extern_new(const rec_t * rec,const dict_index_t * index,ulint n)177 rec_get_n_extern_new(
178 /*=================*/
179 	const rec_t*		rec,	/*!< in: compact physical record */
180 	const dict_index_t*	index,	/*!< in: record descriptor */
181 	ulint			n)	/*!< in: number of columns to scan */
182 {
183 	const byte*	nulls;
184 	const byte*	lens;
185 	ulint		null_mask;
186 	ulint		n_extern;
187 	ulint		i;
188 
189 	ut_ad(dict_table_is_comp(index->table));
190 	ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
191 	ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
192 
193 	if (n == ULINT_UNDEFINED) {
194 		n = dict_index_get_n_fields(index);
195 	}
196 
197 	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
198 	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
199 	null_mask = 1;
200 	n_extern = 0;
201 	i = 0;
202 
203 	/* read the lengths of fields 0..n */
204 	do {
205 		const dict_field_t*	field
206 			= dict_index_get_nth_field(index, i);
207 		const dict_col_t*	col
208 			= dict_field_get_col(field);
209 		ulint			len;
210 
211 		if (!(col->prtype & DATA_NOT_NULL)) {
212 			/* nullable field => read the null flag */
213 
214 			if (UNIV_UNLIKELY(!(byte) null_mask)) {
215 				nulls--;
216 				null_mask = 1;
217 			}
218 
219 			if (*nulls & null_mask) {
220 				null_mask <<= 1;
221 				/* No length is stored for NULL fields. */
222 				continue;
223 			}
224 			null_mask <<= 1;
225 		}
226 
227 		if (UNIV_UNLIKELY(!field->fixed_len)) {
228 			/* Variable-length field: read the length */
229 			len = *lens--;
230 			/* If the maximum length of the field is up
231 			to 255 bytes, the actual length is always
232 			stored in one byte. If the maximum length is
233 			more than 255 bytes, the actual length is
234 			stored in one byte for 0..127.  The length
235 			will be encoded in two bytes when it is 128 or
236 			more, or when the field is stored externally. */
237 			if (DATA_BIG_COL(col)) {
238 				if (len & 0x80) {
239 					/* 1exxxxxxx xxxxxxxx */
240 					if (len & 0x40) {
241 						n_extern++;
242 					}
243 					lens--;
244 				}
245 			}
246 		}
247 	} while (++i < n);
248 
249 	return(n_extern);
250 }
251 
252 /******************************************************//**
253 Determine the offset to each field in a leaf-page record
254 in ROW_FORMAT=COMPACT.  This is a special case of
255 rec_init_offsets() and rec_get_offsets_func(). */
UNIV_INLINE(nonnull)256 UNIV_INLINE MY_ATTRIBUTE((nonnull))
257 void
258 rec_init_offsets_comp_ordinary(
259 /*===========================*/
260 	const rec_t*		rec,	/*!< in: physical record in
261 					ROW_FORMAT=COMPACT */
262 	bool			temp,	/*!< in: whether to use the
263 					format for temporary files in
264 					index creation */
265 	const dict_index_t*	index,	/*!< in: record descriptor */
266 	ulint*			offsets)/*!< in/out: array of offsets;
267 					in: n=rec_offs_n_fields(offsets) */
268 {
269 	ulint		i		= 0;
270 	ulint		offs		= 0;
271 	ulint		any_ext		= 0;
272 	ulint		n_null		= index->n_nullable;
273 	const byte*	nulls		= temp
274 		? rec - 1
275 		: rec - (1 + REC_N_NEW_EXTRA_BYTES);
276 	const byte*	lens		= nulls - UT_BITS_IN_BYTES(n_null);
277 	ulint		null_mask	= 1;
278 
279 #ifdef UNIV_DEBUG
280 	/* We cannot invoke rec_offs_make_valid() here if temp=true.
281 	Similarly, rec_offs_validate() will fail in that case, because
282 	it invokes rec_get_status(). */
283 	offsets[2] = (ulint) rec;
284 	offsets[3] = (ulint) index;
285 #endif /* UNIV_DEBUG */
286 
287 	ut_ad(temp || dict_table_is_comp(index->table));
288 
289 	if (temp && dict_table_is_comp(index->table)) {
290 		/* No need to do adjust fixed_len=0. We only need to
291 		adjust it for ROW_FORMAT=REDUNDANT. */
292 		temp = false;
293 	}
294 
295 	/* read the lengths of fields 0..n */
296 	do {
297 		const dict_field_t*	field
298 			= dict_index_get_nth_field(index, i);
299 		const dict_col_t*	col
300 			= dict_field_get_col(field);
301 		ulint			len;
302 
303 		if (!(col->prtype & DATA_NOT_NULL)) {
304 			/* nullable field => read the null flag */
305 			ut_ad(n_null--);
306 
307 			if (UNIV_UNLIKELY(!(byte) null_mask)) {
308 				nulls--;
309 				null_mask = 1;
310 			}
311 
312 			if (*nulls & null_mask) {
313 				null_mask <<= 1;
314 				/* No length is stored for NULL fields.
315 				We do not advance offs, and we set
316 				the length to zero and enable the
317 				SQL NULL flag in offsets[]. */
318 				len = offs | REC_OFFS_SQL_NULL;
319 				goto resolved;
320 			}
321 			null_mask <<= 1;
322 		}
323 
324 		if (!field->fixed_len
325 		    || (temp && !dict_col_get_fixed_size(col, temp))) {
326 			ut_ad(col->mtype != DATA_POINT);
327 			/* Variable-length field: read the length */
328 			len = *lens--;
329 			/* If the maximum length of the field is up
330 			to 255 bytes, the actual length is always
331 			stored in one byte. If the maximum length is
332 			more than 255 bytes, the actual length is
333 			stored in one byte for 0..127.  The length
334 			will be encoded in two bytes when it is 128 or
335 			more, or when the field is stored externally. */
336 			if (DATA_BIG_COL(col)) {
337 				if (len & 0x80) {
338 					/* 1exxxxxxx xxxxxxxx */
339 					len <<= 8;
340 					len |= *lens--;
341 
342 					offs += len & 0x3fff;
343 					if (UNIV_UNLIKELY(len
344 							  & 0x4000)) {
345 						ut_ad(dict_index_is_clust
346 						      (index));
347 						any_ext = REC_OFFS_EXTERNAL;
348 						len = offs
349 							| REC_OFFS_EXTERNAL;
350 					} else {
351 						len = offs;
352 					}
353 
354 					goto resolved;
355 				}
356 			}
357 
358 			len = offs += len;
359 		} else {
360 			len = offs += field->fixed_len;
361 		}
362 resolved:
363 		rec_offs_base(offsets)[i + 1] = len;
364 	} while (++i < rec_offs_n_fields(offsets));
365 
366 	*rec_offs_base(offsets)
367 		= (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
368 }
369 
370 /******************************************************//**
371 The following function determines the offsets to each field in the
372 record.	 The offsets are written to a previously allocated array of
373 ulint, where rec_offs_n_fields(offsets) has been initialized to the
374 number of fields in the record.	 The rest of the array will be
375 initialized by this function.  rec_offs_base(offsets)[0] will be set
376 to the extra size (if REC_OFFS_COMPACT is set, the record is in the
377 new format; if REC_OFFS_EXTERNAL is set, the record contains externally
378 stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
379 offsets past the end of fields 0..n_fields, or to the beginning of
380 fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
381 is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
382 high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
383 field i is being stored externally. */
384 static
385 void
rec_init_offsets(const rec_t * rec,const dict_index_t * index,ulint * offsets)386 rec_init_offsets(
387 /*=============*/
388 	const rec_t*		rec,	/*!< in: physical record */
389 	const dict_index_t*	index,	/*!< in: record descriptor */
390 	ulint*			offsets)/*!< in/out: array of offsets;
391 					in: n=rec_offs_n_fields(offsets) */
392 {
393 	ulint	i	= 0;
394 	ulint	offs;
395 
396 	rec_offs_make_valid(rec, index, offsets);
397 
398 	if (dict_table_is_comp(index->table)) {
399 		const byte*	nulls;
400 		const byte*	lens;
401 		dict_field_t*	field;
402 		ulint		null_mask;
403 		ulint		status = rec_get_status(rec);
404 		ulint		n_node_ptr_field = ULINT_UNDEFINED;
405 
406 		switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
407 		case REC_STATUS_INFIMUM:
408 		case REC_STATUS_SUPREMUM:
409 			/* the field is 8 bytes long */
410 			rec_offs_base(offsets)[0]
411 				= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
412 			rec_offs_base(offsets)[1] = 8;
413 			return;
414 		case REC_STATUS_NODE_PTR:
415 			n_node_ptr_field
416 				= dict_index_get_n_unique_in_tree_nonleaf(
417 					index);
418 			break;
419 		case REC_STATUS_ORDINARY:
420 			rec_init_offsets_comp_ordinary(
421 				rec, false, index, offsets);
422 			return;
423 		}
424 
425 		nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
426 		lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
427 		offs = 0;
428 		null_mask = 1;
429 
430 		/* read the lengths of fields 0..n */
431 		do {
432 			ulint	len;
433 			if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
434 				len = offs += REC_NODE_PTR_SIZE;
435 				goto resolved;
436 			}
437 
438 			field = dict_index_get_nth_field(index, i);
439 			if (!(dict_field_get_col(field)->prtype
440 			      & DATA_NOT_NULL)) {
441 				/* nullable field => read the null flag */
442 
443 				if (UNIV_UNLIKELY(!(byte) null_mask)) {
444 					nulls--;
445 					null_mask = 1;
446 				}
447 
448 				if (*nulls & null_mask) {
449 					null_mask <<= 1;
450 					/* No length is stored for NULL fields.
451 					We do not advance offs, and we set
452 					the length to zero and enable the
453 					SQL NULL flag in offsets[]. */
454 					len = offs | REC_OFFS_SQL_NULL;
455 					goto resolved;
456 				}
457 				null_mask <<= 1;
458 			}
459 
460 			if (UNIV_UNLIKELY(!field->fixed_len)) {
461 				const dict_col_t*	col
462 					= dict_field_get_col(field);
463 				/* DATA_POINT should always be a fixed
464 				length column. */
465 				ut_ad(col->mtype != DATA_POINT);
466 				/* Variable-length field: read the length */
467 				len = *lens--;
468 				/* If the maximum length of the field
469 				is up to 255 bytes, the actual length
470 				is always stored in one byte. If the
471 				maximum length is more than 255 bytes,
472 				the actual length is stored in one
473 				byte for 0..127.  The length will be
474 				encoded in two bytes when it is 128 or
475 				more, or when the field is stored
476 				externally. */
477 				if (DATA_BIG_COL(col)) {
478 					if (len & 0x80) {
479 						/* 1exxxxxxx xxxxxxxx */
480 
481 						len <<= 8;
482 						len |= *lens--;
483 
484 						/* B-tree node pointers
485 						must not contain externally
486 						stored columns.  Thus
487 						the "e" flag must be 0. */
488 						ut_a(!(len & 0x4000));
489 						offs += len & 0x3fff;
490 						len = offs;
491 
492 						goto resolved;
493 					}
494 				}
495 
496 				len = offs += len;
497 			} else {
498 				len = offs += field->fixed_len;
499 			}
500 resolved:
501 			rec_offs_base(offsets)[i + 1] = len;
502 		} while (++i < rec_offs_n_fields(offsets));
503 
504 		*rec_offs_base(offsets)
505 			= (rec - (lens + 1)) | REC_OFFS_COMPACT;
506 	} else {
507 		/* Old-style record: determine extra size and end offsets */
508 		offs = REC_N_OLD_EXTRA_BYTES;
509 		if (rec_get_1byte_offs_flag(rec)) {
510 			offs += rec_offs_n_fields(offsets);
511 			*rec_offs_base(offsets) = offs;
512 			/* Determine offsets to fields */
513 			do {
514 				offs = rec_1_get_field_end_info(rec, i);
515 				if (offs & REC_1BYTE_SQL_NULL_MASK) {
516 					offs &= ~REC_1BYTE_SQL_NULL_MASK;
517 					offs |= REC_OFFS_SQL_NULL;
518 				}
519 				rec_offs_base(offsets)[1 + i] = offs;
520 			} while (++i < rec_offs_n_fields(offsets));
521 		} else {
522 			offs += 2 * rec_offs_n_fields(offsets);
523 			*rec_offs_base(offsets) = offs;
524 			/* Determine offsets to fields */
525 			do {
526 				offs = rec_2_get_field_end_info(rec, i);
527 				if (offs & REC_2BYTE_SQL_NULL_MASK) {
528 					offs &= ~REC_2BYTE_SQL_NULL_MASK;
529 					offs |= REC_OFFS_SQL_NULL;
530 				}
531 				if (offs & REC_2BYTE_EXTERN_MASK) {
532 					offs &= ~REC_2BYTE_EXTERN_MASK;
533 					offs |= REC_OFFS_EXTERNAL;
534 					*rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
535 				}
536 				rec_offs_base(offsets)[1 + i] = offs;
537 			} while (++i < rec_offs_n_fields(offsets));
538 		}
539 	}
540 }
541 
542 /******************************************************//**
543 The following function determines the offsets to each field
544 in the record.	It can reuse a previously returned array.
545 @return the new offsets */
546 ulint*
rec_get_offsets_func(const rec_t * rec,const dict_index_t * index,ulint * offsets,ulint n_fields,const char * file,ulint line,mem_heap_t ** heap)547 rec_get_offsets_func(
548 /*=================*/
549 	const rec_t*		rec,	/*!< in: physical record */
550 	const dict_index_t*	index,	/*!< in: record descriptor */
551 	ulint*			offsets,/*!< in/out: array consisting of
552 					offsets[0] allocated elements,
553 					or an array from rec_get_offsets(),
554 					or NULL */
555 	ulint			n_fields,/*!< in: maximum number of
556 					initialized fields
557 					 (ULINT_UNDEFINED if all fields) */
558 #ifdef UNIV_DEBUG
559 	const char*		file,	/*!< in: file name where called */
560 	ulint			line,	/*!< in: line number where called */
561 #endif /* UNIV_DEBUG */
562 	mem_heap_t**		heap)	/*!< in/out: memory heap */
563 {
564 	ulint	n;
565 	ulint	size;
566 
567 	ut_ad(rec);
568 	ut_ad(index);
569 	ut_ad(heap);
570 
571 	if (dict_table_is_comp(index->table)) {
572 		switch (UNIV_EXPECT(rec_get_status(rec),
573 				    REC_STATUS_ORDINARY)) {
574 		case REC_STATUS_ORDINARY:
575 			n = dict_index_get_n_fields(index);
576 			break;
577 		case REC_STATUS_NODE_PTR:
578 			/* Node pointer records consist of the
579 			uniquely identifying fields of the record
580 			followed by a child page number field. */
581 			n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1;
582 			break;
583 		case REC_STATUS_INFIMUM:
584 		case REC_STATUS_SUPREMUM:
585 			/* infimum or supremum record */
586 			n = 1;
587 			break;
588 		default:
589 			ut_error;
590 			return(NULL);
591 		}
592 	} else {
593 		n = rec_get_n_fields_old(rec);
594 	}
595 
596 	if (UNIV_UNLIKELY(n_fields < n)) {
597 		n = n_fields;
598 	}
599 
600 	/* The offsets header consists of the allocation size at
601 	offsets[0] and the REC_OFFS_HEADER_SIZE bytes. */
602 	size = n + (1 + REC_OFFS_HEADER_SIZE);
603 
604 	if (UNIV_UNLIKELY(!offsets)
605 	    || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
606 		if (UNIV_UNLIKELY(!*heap)) {
607 			*heap = mem_heap_create_at(size * sizeof(ulint),
608 						   file, line);
609 		}
610 		offsets = static_cast<ulint*>(
611 			mem_heap_alloc(*heap, size * sizeof(ulint)));
612 
613 		rec_offs_set_n_alloc(offsets, size);
614 	}
615 
616 	rec_offs_set_n_fields(offsets, n);
617 	rec_init_offsets(rec, index, offsets);
618 	return(offsets);
619 }
620 
621 /******************************************************//**
622 The following function determines the offsets to each field
623 in the record.  It can reuse a previously allocated array. */
624 void
rec_get_offsets_reverse(const byte * extra,const dict_index_t * index,ulint node_ptr,ulint * offsets)625 rec_get_offsets_reverse(
626 /*====================*/
627 	const byte*		extra,	/*!< in: the extra bytes of a
628 					compact record in reverse order,
629 					excluding the fixed-size
630 					REC_N_NEW_EXTRA_BYTES */
631 	const dict_index_t*	index,	/*!< in: record descriptor */
632 	ulint			node_ptr,/*!< in: nonzero=node pointer,
633 					0=leaf node */
634 	ulint*			offsets)/*!< in/out: array consisting of
635 					offsets[0] allocated elements */
636 {
637 	ulint		n;
638 	ulint		i;
639 	ulint		offs;
640 	ulint		any_ext;
641 	const byte*	nulls;
642 	const byte*	lens;
643 	dict_field_t*	field;
644 	ulint		null_mask;
645 	ulint		n_node_ptr_field;
646 
647 	ut_ad(extra);
648 	ut_ad(index);
649 	ut_ad(offsets);
650 	ut_ad(dict_table_is_comp(index->table));
651 
652 	if (UNIV_UNLIKELY(node_ptr)) {
653 		n_node_ptr_field =
654 			dict_index_get_n_unique_in_tree_nonleaf(index);
655 		n = n_node_ptr_field + 1;
656 	} else {
657 		n_node_ptr_field = ULINT_UNDEFINED;
658 		n = dict_index_get_n_fields(index);
659 	}
660 
661 	ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
662 	rec_offs_set_n_fields(offsets, n);
663 
664 	nulls = extra;
665 	lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
666 	i = offs = 0;
667 	null_mask = 1;
668 	any_ext = 0;
669 
670 	/* read the lengths of fields 0..n */
671 	do {
672 		ulint	len;
673 		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
674 			len = offs += REC_NODE_PTR_SIZE;
675 			goto resolved;
676 		}
677 
678 		field = dict_index_get_nth_field(index, i);
679 		if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
680 			/* nullable field => read the null flag */
681 
682 			if (UNIV_UNLIKELY(!(byte) null_mask)) {
683 				nulls++;
684 				null_mask = 1;
685 			}
686 
687 			if (*nulls & null_mask) {
688 				null_mask <<= 1;
689 				/* No length is stored for NULL fields.
690 				We do not advance offs, and we set
691 				the length to zero and enable the
692 				SQL NULL flag in offsets[]. */
693 				len = offs | REC_OFFS_SQL_NULL;
694 				goto resolved;
695 			}
696 			null_mask <<= 1;
697 		}
698 
699 		if (UNIV_UNLIKELY(!field->fixed_len)) {
700 			/* Variable-length field: read the length */
701 			const dict_col_t*	col
702 				= dict_field_get_col(field);
703 			len = *lens++;
704 			/* If the maximum length of the field is up
705 			to 255 bytes, the actual length is always
706 			stored in one byte. If the maximum length is
707 			more than 255 bytes, the actual length is
708 			stored in one byte for 0..127.  The length
709 			will be encoded in two bytes when it is 128 or
710 			more, or when the field is stored externally. */
711 			if (DATA_BIG_COL(col)) {
712 				if (len & 0x80) {
713 					/* 1exxxxxxx xxxxxxxx */
714 					len <<= 8;
715 					len |= *lens++;
716 
717 					offs += len & 0x3fff;
718 					if (UNIV_UNLIKELY(len & 0x4000)) {
719 						any_ext = REC_OFFS_EXTERNAL;
720 						len = offs | REC_OFFS_EXTERNAL;
721 					} else {
722 						len = offs;
723 					}
724 
725 					goto resolved;
726 				}
727 			}
728 
729 			len = offs += len;
730 		} else {
731 			len = offs += field->fixed_len;
732 		}
733 resolved:
734 		rec_offs_base(offsets)[i + 1] = len;
735 	} while (++i < rec_offs_n_fields(offsets));
736 
737 	ut_ad(lens >= extra);
738 	*rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
739 		| REC_OFFS_COMPACT | any_ext;
740 }
741 
742 /************************************************************//**
743 The following function is used to get the offset to the nth
744 data field in an old-style record.
745 @return offset to the field */
746 ulint
rec_get_nth_field_offs_old(const rec_t * rec,ulint n,ulint * len)747 rec_get_nth_field_offs_old(
748 /*=======================*/
749 	const rec_t*	rec,	/*!< in: record */
750 	ulint		n,	/*!< in: index of the field */
751 	ulint*		len)	/*!< out: length of the field;
752 				UNIV_SQL_NULL if SQL null */
753 {
754 	ulint	os;
755 	ulint	next_os;
756 
757 	ut_ad(len);
758 	ut_a(rec);
759 	ut_a(n < rec_get_n_fields_old(rec));
760 
761 	if (rec_get_1byte_offs_flag(rec)) {
762 		os = rec_1_get_field_start_offs(rec, n);
763 
764 		next_os = rec_1_get_field_end_info(rec, n);
765 
766 		if (next_os & REC_1BYTE_SQL_NULL_MASK) {
767 			*len = UNIV_SQL_NULL;
768 
769 			return(os);
770 		}
771 
772 		next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
773 	} else {
774 		os = rec_2_get_field_start_offs(rec, n);
775 
776 		next_os = rec_2_get_field_end_info(rec, n);
777 
778 		if (next_os & REC_2BYTE_SQL_NULL_MASK) {
779 			*len = UNIV_SQL_NULL;
780 
781 			return(os);
782 		}
783 
784 		next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
785 				      | REC_2BYTE_EXTERN_MASK);
786 	}
787 
788 	*len = next_os - os;
789 
790 	ut_ad(*len < UNIV_PAGE_SIZE);
791 
792 	return(os);
793 }
794 
795 /**********************************************************//**
796 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
797 @return total size */
798 UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(1,2)))
799 ulint
rec_get_converted_size_comp_prefix_low(const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint * extra,bool temp)800 rec_get_converted_size_comp_prefix_low(
801 /*===================================*/
802 	const dict_index_t*	index,	/*!< in: record descriptor;
803 					dict_table_is_comp() is
804 					assumed to hold, even if
805 					it does not */
806 	const dfield_t*		fields,	/*!< in: array of data fields */
807 	ulint			n_fields,/*!< in: number of data fields */
808 	const dtuple_t*		v_entry,/*!< in: dtuple contains virtual column
809 					data */
810 	ulint*			extra,	/*!< out: extra size */
811 	bool			temp)	/*!< in: whether this is a
812 					temporary file record */
813 {
814 	ulint	extra_size;
815 	ulint	data_size;
816 	ulint	i;
817 	ulint	n_null	= (n_fields > 0) ? index->n_nullable : 0;
818 	ulint	n_v_fields;
819 	ut_ad(n_fields <= dict_index_get_n_fields(index));
820 	ut_ad(!temp || extra);
821 
822 	/* At the time being, only temp file record could possible
823 	store virtual columns */
824 	ut_ad(!v_entry || (dict_index_is_clust(index) && temp));
825 	n_v_fields = v_entry ? dtuple_get_n_v_fields(v_entry) : 0;
826 
827 	extra_size = temp
828 		? UT_BITS_IN_BYTES(n_null)
829 		: REC_N_NEW_EXTRA_BYTES
830 		+ UT_BITS_IN_BYTES(n_null);
831 	data_size = 0;
832 
833 	if (temp && dict_table_is_comp(index->table)) {
834 		/* No need to do adjust fixed_len=0. We only need to
835 		adjust it for ROW_FORMAT=REDUNDANT. */
836 		temp = false;
837 	}
838 
839 	/* read the lengths of fields 0..n */
840 	for (i = 0; i < n_fields; i++) {
841 		const dict_field_t*	field;
842 		ulint			len;
843 		ulint			fixed_len;
844 		const dict_col_t*	col;
845 
846 		field = dict_index_get_nth_field(index, i);
847 		len = dfield_get_len(&fields[i]);
848 		col = dict_field_get_col(field);
849 
850 #ifdef UNIV_DEBUG
851 		dtype_t*	type;
852 
853 		type = dfield_get_type(&fields[i]);
854 		if (dict_index_is_spatial(index)) {
855 			if (DATA_GEOMETRY_MTYPE(col->mtype) && i == 0) {
856 				ut_ad(type->prtype & DATA_GIS_MBR);
857 			} else {
858 				ut_ad(type->mtype == DATA_SYS_CHILD
859 				      || dict_col_type_assert_equal(col, type));
860 			}
861 		} else {
862 			ut_ad(dict_col_type_assert_equal(col, type));
863 		}
864 #endif
865 
866 		/* All NULLable fields must be included in the n_null count. */
867 		ut_ad((col->prtype & DATA_NOT_NULL) || n_null--);
868 
869 		if (dfield_is_null(&fields[i])) {
870 			/* No length is stored for NULL fields. */
871 			ut_ad(!(col->prtype & DATA_NOT_NULL));
872 			continue;
873 		}
874 
875 		ut_ad(len <= col->len || DATA_LARGE_MTYPE(col->mtype)
876                       || (DATA_POINT_MTYPE(col->mtype)
877 			  && len == DATA_MBR_LEN)
878 		      || (col->len == 0 && col->mtype == DATA_VARCHAR));
879 
880 		fixed_len = field->fixed_len;
881 		if (temp && fixed_len
882 		    && !dict_col_get_fixed_size(col, temp)) {
883 			fixed_len = 0;
884 		}
885 		/* If the maximum length of a variable-length field
886 		is up to 255 bytes, the actual length is always stored
887 		in one byte. If the maximum length is more than 255
888 		bytes, the actual length is stored in one byte for
889 		0..127.  The length will be encoded in two bytes when
890 		it is 128 or more, or when the field is stored externally. */
891 
892 		if (fixed_len) {
893 #ifdef UNIV_DEBUG
894 			ulint	mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
895 			ulint	mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
896 
897 			ut_ad(len <= fixed_len);
898 
899 			if (dict_index_is_spatial(index)) {
900 				ut_ad(type->mtype == DATA_SYS_CHILD
901 				      || !mbmaxlen
902 				      || len >= mbminlen * (fixed_len
903 							    / mbmaxlen));
904 			} else {
905 				ut_ad(type->mtype != DATA_SYS_CHILD);
906 				ut_ad(!mbmaxlen
907 				      || len >= mbminlen * (fixed_len
908 							    / mbmaxlen));
909 			}
910 
911 			/* dict_index_add_col() should guarantee this */
912 			ut_ad(!field->prefix_len
913 			      || fixed_len == field->prefix_len);
914 #endif /* UNIV_DEBUG */
915 		} else if (dfield_is_ext(&fields[i])) {
916 			ut_ad(DATA_BIG_COL(col));
917 			extra_size += 2;
918 		} else if (len < 128 || !DATA_BIG_COL(col)) {
919 			extra_size++;
920 		} else {
921 			/* For variable-length columns, we look up the
922 			maximum length from the column itself.  If this
923 			is a prefix index column shorter than 256 bytes,
924 			this will waste one byte. */
925 			extra_size += 2;
926 		}
927 		data_size += len;
928 	}
929 
930 	if (extra) {
931 		*extra = extra_size;
932 	}
933 
934 	/* Log virtual columns */
935 	if (n_v_fields != 0) {
936 		/* length marker */
937 		data_size += 2;
938 
939 		for (i = 0; i < n_v_fields; i++) {
940 			dfield_t*       vfield;
941 			ulint		flen;
942 
943                         const dict_v_col_t*     col
944                                 = dict_table_get_nth_v_col(index->table, i);
945 
946 			/* Only those indexed needs to be logged */
947                         if (col->m_col.ord_part) {
948 				data_size += mach_get_compressed_size(
949 					i + REC_MAX_N_FIELDS);
950 				vfield = dtuple_get_nth_v_field(
951                                                 v_entry, col->v_pos);
952 
953                                 flen = vfield->len;
954 
955 				if (flen != UNIV_SQL_NULL) {
956                                         flen = ut_min(
957                                                 flen,
958                                                 static_cast<ulint>(
959                                                 DICT_MAX_FIELD_LEN_BY_FORMAT(
960                                                         index->table)));
961 					data_size += flen;
962                                 }
963 
964 				data_size += mach_get_compressed_size(flen);
965 			}
966 		}
967 	}
968 
969 	return(extra_size + data_size);
970 }
971 
972 /**********************************************************//**
973 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
974 @return total size */
975 ulint
rec_get_converted_size_comp_prefix(const dict_index_t * index,const dfield_t * fields,ulint n_fields,ulint * extra)976 rec_get_converted_size_comp_prefix(
977 /*===============================*/
978 	const dict_index_t*	index,	/*!< in: record descriptor */
979 	const dfield_t*		fields,	/*!< in: array of data fields */
980 	ulint			n_fields,/*!< in: number of data fields */
981 	ulint*			extra)	/*!< out: extra size */
982 {
983 	ut_ad(dict_table_is_comp(index->table));
984 	return(rec_get_converted_size_comp_prefix_low(
985 		       index, fields, n_fields, NULL, extra, false));
986 }
987 
988 /**********************************************************//**
989 Determines the size of a data tuple in ROW_FORMAT=COMPACT.
990 @return total size */
991 ulint
rec_get_converted_size_comp(const dict_index_t * index,ulint status,const dfield_t * fields,ulint n_fields,ulint * extra)992 rec_get_converted_size_comp(
993 /*========================*/
994 	const dict_index_t*	index,	/*!< in: record descriptor;
995 					dict_table_is_comp() is
996 					assumed to hold, even if
997 					it does not */
998 	ulint			status,	/*!< in: status bits of the record */
999 	const dfield_t*		fields,	/*!< in: array of data fields */
1000 	ulint			n_fields,/*!< in: number of data fields */
1001 	ulint*			extra)	/*!< out: extra size */
1002 {
1003 	ulint	size;
1004 	ut_ad(n_fields > 0);
1005 
1006 	switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1007 	case REC_STATUS_ORDINARY:
1008 		ut_ad(n_fields == dict_index_get_n_fields(index));
1009 		size = 0;
1010 		break;
1011 	case REC_STATUS_NODE_PTR:
1012 		n_fields--;
1013 		ut_ad(n_fields == dict_index_get_n_unique_in_tree_nonleaf(
1014 					index));
1015 		ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
1016 		size = REC_NODE_PTR_SIZE; /* child page number */
1017 		break;
1018 	case REC_STATUS_INFIMUM:
1019 	case REC_STATUS_SUPREMUM:
1020 		/* infimum or supremum record, 8 data bytes */
1021 		if (UNIV_LIKELY_NULL(extra)) {
1022 			*extra = REC_N_NEW_EXTRA_BYTES;
1023 		}
1024 		return(REC_N_NEW_EXTRA_BYTES + 8);
1025 	default:
1026 		ut_error;
1027 		return(ULINT_UNDEFINED);
1028 	}
1029 
1030 	return(size + rec_get_converted_size_comp_prefix_low(
1031 		       index, fields, n_fields, NULL, extra, false));
1032 }
1033 
1034 /***********************************************************//**
1035 Sets the value of the ith field SQL null bit of an old-style record. */
1036 void
rec_set_nth_field_null_bit(rec_t * rec,ulint i,ibool val)1037 rec_set_nth_field_null_bit(
1038 /*=======================*/
1039 	rec_t*	rec,	/*!< in: record */
1040 	ulint	i,	/*!< in: ith field */
1041 	ibool	val)	/*!< in: value to set */
1042 {
1043 	ulint	info;
1044 
1045 	if (rec_get_1byte_offs_flag(rec)) {
1046 
1047 		info = rec_1_get_field_end_info(rec, i);
1048 
1049 		if (val) {
1050 			info = info | REC_1BYTE_SQL_NULL_MASK;
1051 		} else {
1052 			info = info & ~REC_1BYTE_SQL_NULL_MASK;
1053 		}
1054 
1055 		rec_1_set_field_end_info(rec, i, info);
1056 
1057 		return;
1058 	}
1059 
1060 	info = rec_2_get_field_end_info(rec, i);
1061 
1062 	if (val) {
1063 		info = info | REC_2BYTE_SQL_NULL_MASK;
1064 	} else {
1065 		info = info & ~REC_2BYTE_SQL_NULL_MASK;
1066 	}
1067 
1068 	rec_2_set_field_end_info(rec, i, info);
1069 }
1070 
1071 /***********************************************************//**
1072 Sets an old-style record field to SQL null.
1073 The physical size of the field is not changed. */
1074 void
rec_set_nth_field_sql_null(rec_t * rec,ulint n)1075 rec_set_nth_field_sql_null(
1076 /*=======================*/
1077 	rec_t*	rec,	/*!< in: record */
1078 	ulint	n)	/*!< in: index of the field */
1079 {
1080 	ulint	offset;
1081 
1082 	offset = rec_get_field_start_offs(rec, n);
1083 
1084 	data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
1085 
1086 	rec_set_nth_field_null_bit(rec, n, TRUE);
1087 }
1088 
1089 /*********************************************************//**
1090 Builds an old-style physical record out of a data tuple and
1091 stores it beginning from the start of the given buffer.
1092 @return pointer to the origin of physical record */
1093 static
1094 rec_t*
rec_convert_dtuple_to_rec_old(byte * buf,const dtuple_t * dtuple,ulint n_ext)1095 rec_convert_dtuple_to_rec_old(
1096 /*==========================*/
1097 	byte*		buf,	/*!< in: start address of the physical record */
1098 	const dtuple_t*	dtuple,	/*!< in: data tuple */
1099 	ulint		n_ext)	/*!< in: number of externally stored columns */
1100 {
1101 	const dfield_t*	field;
1102 	ulint		n_fields;
1103 	ulint		data_size;
1104 	rec_t*		rec;
1105 	ulint		end_offset;
1106 	ulint		ored_offset;
1107 	ulint		len;
1108 	ulint		i;
1109 
1110 	ut_ad(buf && dtuple);
1111 	ut_ad(dtuple_validate(dtuple));
1112 	ut_ad(dtuple_check_typed(dtuple));
1113 
1114 	n_fields = dtuple_get_n_fields(dtuple);
1115 	data_size = dtuple_get_data_size(dtuple, 0);
1116 
1117 	ut_ad(n_fields > 0);
1118 
1119 	/* Calculate the offset of the origin in the physical record */
1120 
1121 	rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
1122 #ifdef UNIV_DEBUG
1123 	/* Suppress Valgrind warnings of ut_ad()
1124 	in mach_write_to_1(), mach_write_to_2() et al. */
1125 	memset(buf, 0xff, rec - buf + data_size);
1126 #endif /* UNIV_DEBUG */
1127 	/* Store the number of fields */
1128 	rec_set_n_fields_old(rec, n_fields);
1129 
1130 	/* Set the info bits of the record */
1131 	rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
1132 			      & REC_INFO_BITS_MASK);
1133 
1134 	/* Store the data and the offsets */
1135 
1136 	end_offset = 0;
1137 
1138 	if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1139 
1140 		rec_set_1byte_offs_flag(rec, TRUE);
1141 
1142 		for (i = 0; i < n_fields; i++) {
1143 
1144 			field = dtuple_get_nth_field(dtuple, i);
1145 
1146 			if (dfield_is_null(field)) {
1147 				len = dtype_get_sql_null_size(
1148 					dfield_get_type(field), 0);
1149 				data_write_sql_null(rec + end_offset, len);
1150 
1151 				end_offset += len;
1152 				ored_offset = end_offset
1153 					| REC_1BYTE_SQL_NULL_MASK;
1154 			} else {
1155 				/* If the data is not SQL null, store it */
1156 				len = dfield_get_len(field);
1157 
1158 				memcpy(rec + end_offset,
1159 				       dfield_get_data(field), len);
1160 
1161 				end_offset += len;
1162 				ored_offset = end_offset;
1163 			}
1164 
1165 			rec_1_set_field_end_info(rec, i, ored_offset);
1166 		}
1167 	} else {
1168 		rec_set_1byte_offs_flag(rec, FALSE);
1169 
1170 		for (i = 0; i < n_fields; i++) {
1171 
1172 			field = dtuple_get_nth_field(dtuple, i);
1173 
1174 			if (dfield_is_null(field)) {
1175 				len = dtype_get_sql_null_size(
1176 					dfield_get_type(field), 0);
1177 				data_write_sql_null(rec + end_offset, len);
1178 
1179 				end_offset += len;
1180 				ored_offset = end_offset
1181 					| REC_2BYTE_SQL_NULL_MASK;
1182 			} else {
1183 				/* If the data is not SQL null, store it */
1184 				len = dfield_get_len(field);
1185 
1186 				memcpy(rec + end_offset,
1187 				       dfield_get_data(field), len);
1188 
1189 				end_offset += len;
1190 				ored_offset = end_offset;
1191 
1192 				if (dfield_is_ext(field)) {
1193 					ored_offset |= REC_2BYTE_EXTERN_MASK;
1194 				}
1195 			}
1196 
1197 			rec_2_set_field_end_info(rec, i, ored_offset);
1198 		}
1199 	}
1200 
1201 	return(rec);
1202 }
1203 
1204 /*********************************************************//**
1205 Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1206 UNIV_INLINE
1207 void
rec_convert_dtuple_to_rec_comp(rec_t * rec,const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint status,bool temp)1208 rec_convert_dtuple_to_rec_comp(
1209 /*===========================*/
1210 	rec_t*			rec,	/*!< in: origin of record */
1211 	const dict_index_t*	index,	/*!< in: record descriptor */
1212 	const dfield_t*		fields,	/*!< in: array of data fields */
1213 	ulint			n_fields,/*!< in: number of data fields */
1214 	const dtuple_t*		v_entry,/*!< in: dtuple contains
1215 					virtual column data */
1216 	ulint			status,	/*!< in: status bits of the record */
1217 	bool			temp)	/*!< in: whether to use the
1218 					format for temporary files in
1219 					index creation */
1220 {
1221 	const dfield_t*	field;
1222 	const dtype_t*	type;
1223 	byte*		end;
1224 	byte*		nulls;
1225 	byte*		lens;
1226 	ulint		len;
1227 	ulint		i;
1228 	ulint		n_node_ptr_field;
1229 	ulint		fixed_len;
1230 	ulint		null_mask	= 1;
1231 	ulint		n_null;
1232 	ulint		num_v = v_entry ? dtuple_get_n_v_fields(v_entry) : 0;
1233 
1234 	ut_ad(temp || dict_table_is_comp(index->table));
1235 
1236 	if (temp) {
1237 		ut_ad(status == REC_STATUS_ORDINARY);
1238 		ut_ad(n_fields <= dict_index_get_n_fields(index));
1239 		n_node_ptr_field = ULINT_UNDEFINED;
1240 		nulls = rec - 1;
1241 		if (dict_table_is_comp(index->table)) {
1242 			/* No need to do adjust fixed_len=0. We only
1243 			need to adjust it for ROW_FORMAT=REDUNDANT. */
1244 			temp = false;
1245 		}
1246 	} else {
1247 		ut_ad(v_entry == NULL);
1248 		ut_ad(num_v == 0);
1249 		nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1250 
1251 		switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1252 		case REC_STATUS_ORDINARY:
1253 			ut_ad(n_fields <= dict_index_get_n_fields(index));
1254 			n_node_ptr_field = ULINT_UNDEFINED;
1255 			break;
1256 		case REC_STATUS_NODE_PTR:
1257 			ut_ad(n_fields
1258 			      == dict_index_get_n_unique_in_tree_nonleaf(index)
1259 				 + 1);
1260 			n_node_ptr_field = n_fields - 1;
1261 			break;
1262 		case REC_STATUS_INFIMUM:
1263 		case REC_STATUS_SUPREMUM:
1264 			ut_ad(n_fields == 1);
1265 			n_node_ptr_field = ULINT_UNDEFINED;
1266 			break;
1267 		default:
1268 			ut_error;
1269 			return;
1270 		}
1271 	}
1272 
1273 	end = rec;
1274 
1275 	if (n_fields != 0) {
1276 		n_null = index->n_nullable;
1277 		lens = nulls - UT_BITS_IN_BYTES(n_null);
1278 		/* clear the SQL-null flags */
1279 		memset(lens + 1, 0, nulls - lens);
1280 	}
1281 
1282 	/* Store the data and the offsets */
1283 
1284 	for (i = 0; i < n_fields; i++) {
1285 		const dict_field_t*	ifield;
1286 		dict_col_t*		col = NULL;
1287 
1288 		field = &fields[i];
1289 
1290 		type = dfield_get_type(field);
1291 		len = dfield_get_len(field);
1292 
1293 		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1294 			ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1295 			ut_ad(len == REC_NODE_PTR_SIZE);
1296 			memcpy(end, dfield_get_data(field), len);
1297 			end += REC_NODE_PTR_SIZE;
1298 			break;
1299 		}
1300 
1301 		if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1302 			/* nullable field */
1303 			ut_ad(n_null--);
1304 
1305 			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1306 				nulls--;
1307 				null_mask = 1;
1308 			}
1309 
1310 			ut_ad(*nulls < null_mask);
1311 
1312 			/* set the null flag if necessary */
1313 			if (dfield_is_null(field)) {
1314 				*nulls |= null_mask;
1315 				null_mask <<= 1;
1316 				continue;
1317 			}
1318 
1319 			null_mask <<= 1;
1320 		}
1321 		/* only nullable fields can be null */
1322 		ut_ad(!dfield_is_null(field));
1323 
1324 		ifield = dict_index_get_nth_field(index, i);
1325 		fixed_len = ifield->fixed_len;
1326 		col = ifield->col;
1327 		if (temp && fixed_len
1328 		    && !dict_col_get_fixed_size(col, temp)) {
1329 			fixed_len = 0;
1330 		}
1331 
1332 		/* If the maximum length of a variable-length field
1333 		is up to 255 bytes, the actual length is always stored
1334 		in one byte. If the maximum length is more than 255
1335 		bytes, the actual length is stored in one byte for
1336 		0..127.  The length will be encoded in two bytes when
1337 		it is 128 or more, or when the field is stored externally. */
1338 		if (fixed_len) {
1339 #ifdef UNIV_DEBUG
1340 			ulint	mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
1341 			ulint	mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
1342 
1343 			ut_ad(len <= fixed_len);
1344 			ut_ad(!mbmaxlen || len >= mbminlen
1345 			      * (fixed_len / mbmaxlen));
1346 			ut_ad(!dfield_is_ext(field));
1347 #endif /* UNIV_DEBUG */
1348 		} else if (dfield_is_ext(field)) {
1349 			ut_ad(DATA_BIG_COL(col));
1350 			ut_ad(len <= REC_ANTELOPE_MAX_INDEX_COL_LEN
1351 			      + BTR_EXTERN_FIELD_REF_SIZE);
1352 			*lens-- = (byte) (len >> 8) | 0xc0;
1353 			*lens-- = (byte) len;
1354 		} else {
1355 			/* DATA_POINT would have a fixed_len */
1356 			ut_ad(dtype_get_mtype(type) != DATA_POINT);
1357 			ut_ad(len <= dtype_get_len(type)
1358 			      || DATA_LARGE_MTYPE(dtype_get_mtype(type))
1359 			      || !strcmp(index->name,
1360 					 FTS_INDEX_TABLE_IND_NAME));
1361 			if (len < 128 || !DATA_BIG_LEN_MTYPE(
1362 				dtype_get_len(type), dtype_get_mtype(type))) {
1363 
1364 				*lens-- = (byte) len;
1365 			} else {
1366 				ut_ad(len < 16384);
1367 				*lens-- = (byte) (len >> 8) | 0x80;
1368 				*lens-- = (byte) len;
1369 			}
1370 		}
1371 
1372 		memcpy(end, dfield_get_data(field), len);
1373 		end += len;
1374 	}
1375 
1376 	if (!num_v) {
1377 		return;
1378 	}
1379 
1380 	/* reserve 2 bytes for writing length */
1381 	byte*	ptr = end;
1382 	ptr += 2;
1383 
1384 	/* Now log information on indexed virtual columns */
1385 	for (ulint col_no = 0; col_no < num_v; col_no++) {
1386 		dfield_t*       vfield;
1387 		ulint		flen;
1388 
1389 		const dict_v_col_t*     col
1390 			= dict_table_get_nth_v_col(index->table, col_no);
1391 
1392 		if (col->m_col.ord_part) {
1393 			ulint   pos = col_no;
1394 
1395 			pos += REC_MAX_N_FIELDS;
1396 
1397 			ptr += mach_write_compressed(ptr, pos);
1398 
1399 			vfield = dtuple_get_nth_v_field(
1400 				v_entry, col->v_pos);
1401 
1402 			flen = vfield->len;
1403 
1404 			if (flen != UNIV_SQL_NULL) {
1405 				/* The virtual column can only be in sec
1406 				index, and index key length is bound by
1407 				DICT_MAX_FIELD_LEN_BY_FORMAT */
1408 				flen = ut_min(
1409 					flen,
1410 					static_cast<ulint>(
1411 					DICT_MAX_FIELD_LEN_BY_FORMAT(
1412 						index->table)));
1413 			}
1414 
1415 			ptr += mach_write_compressed(ptr, flen);
1416 
1417 			if (flen != UNIV_SQL_NULL) {
1418 				ut_memcpy(ptr, dfield_get_data(vfield), flen);
1419 				ptr += flen;
1420 			}
1421 		}
1422 	}
1423 
1424 	mach_write_to_2(end, ptr - end);
1425 }
1426 
1427 /*********************************************************//**
1428 Builds a new-style physical record out of a data tuple and
1429 stores it beginning from the start of the given buffer.
1430 @return pointer to the origin of physical record */
1431 static
1432 rec_t*
rec_convert_dtuple_to_rec_new(byte * buf,const dict_index_t * index,const dtuple_t * dtuple)1433 rec_convert_dtuple_to_rec_new(
1434 /*==========================*/
1435 	byte*			buf,	/*!< in: start address of
1436 					the physical record */
1437 	const dict_index_t*	index,	/*!< in: record descriptor */
1438 	const dtuple_t*		dtuple)	/*!< in: data tuple */
1439 {
1440 	ulint	extra_size;
1441 	ulint	status;
1442 	rec_t*	rec;
1443 
1444 	status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1445 	rec_get_converted_size_comp(
1446 		index, status, dtuple->fields, dtuple->n_fields, &extra_size);
1447 	rec = buf + extra_size;
1448 
1449 	rec_convert_dtuple_to_rec_comp(
1450 		rec, index, dtuple->fields, dtuple->n_fields, NULL,
1451 		status, false);
1452 
1453 	/* Set the info bits of the record */
1454 	rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1455 
1456 	return(rec);
1457 }
1458 
1459 /*********************************************************//**
1460 Builds a physical record out of a data tuple and
1461 stores it beginning from the start of the given buffer.
1462 @return pointer to the origin of physical record */
1463 rec_t*
rec_convert_dtuple_to_rec(byte * buf,const dict_index_t * index,const dtuple_t * dtuple,ulint n_ext)1464 rec_convert_dtuple_to_rec(
1465 /*======================*/
1466 	byte*			buf,	/*!< in: start address of the
1467 					physical record */
1468 	const dict_index_t*	index,	/*!< in: record descriptor */
1469 	const dtuple_t*		dtuple,	/*!< in: data tuple */
1470 	ulint			n_ext)	/*!< in: number of
1471 					externally stored columns */
1472 {
1473 	rec_t*	rec;
1474 
1475 	ut_ad(buf != NULL);
1476 	ut_ad(index != NULL);
1477 	ut_ad(dtuple != NULL);
1478 	ut_ad(dtuple_validate(dtuple));
1479 	ut_ad(dtuple_check_typed(dtuple));
1480 
1481 	if (dict_table_is_comp(index->table)) {
1482 		rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1483 	} else {
1484 		rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1485 	}
1486 
1487 #ifdef UNIV_DEBUG
1488 	{
1489 		mem_heap_t*	heap	= NULL;
1490 		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
1491 		const ulint*	offsets;
1492 		ulint		i;
1493 		rec_offs_init(offsets_);
1494 
1495 		offsets = rec_get_offsets(rec, index,
1496 					  offsets_, ULINT_UNDEFINED, &heap);
1497 		ut_ad(rec_validate(rec, offsets));
1498 		ut_ad(dtuple_get_n_fields(dtuple)
1499 		      == rec_offs_n_fields(offsets));
1500 
1501 		for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1502 			ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
1503 			      == !rec_offs_nth_extern(offsets, i));
1504 		}
1505 
1506 		if (UNIV_LIKELY_NULL(heap)) {
1507 			mem_heap_free(heap);
1508 		}
1509 	}
1510 #endif /* UNIV_DEBUG */
1511 	return(rec);
1512 }
1513 
1514 #ifndef UNIV_HOTBACKUP
1515 /**********************************************************//**
1516 Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
1517 @return total size */
1518 ulint
rec_get_converted_size_temp(const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry,ulint * extra)1519 rec_get_converted_size_temp(
1520 /*========================*/
1521 	const dict_index_t*	index,	/*!< in: record descriptor */
1522 	const dfield_t*		fields,	/*!< in: array of data fields */
1523 	ulint			n_fields,/*!< in: number of data fields */
1524 	const dtuple_t*		v_entry,/*!< in: dtuple contains virtual column
1525 					data */
1526 	ulint*			extra)	/*!< out: extra size */
1527 {
1528 	return(rec_get_converted_size_comp_prefix_low(
1529 		       index, fields, n_fields, v_entry, extra, true));
1530 }
1531 
1532 /******************************************************//**
1533 Determine the offset to each field in temporary file.
1534 @see rec_convert_dtuple_to_temp() */
1535 void
rec_init_offsets_temp(const rec_t * rec,const dict_index_t * index,ulint * offsets)1536 rec_init_offsets_temp(
1537 /*==================*/
1538 	const rec_t*		rec,	/*!< in: temporary file record */
1539 	const dict_index_t*	index,	/*!< in: record descriptor */
1540 	ulint*			offsets)/*!< in/out: array of offsets;
1541 					in: n=rec_offs_n_fields(offsets) */
1542 {
1543 	rec_init_offsets_comp_ordinary(rec, true, index, offsets);
1544 }
1545 
1546 /*********************************************************//**
1547 Builds a temporary file record out of a data tuple.
1548 @see rec_init_offsets_temp() */
1549 void
rec_convert_dtuple_to_temp(rec_t * rec,const dict_index_t * index,const dfield_t * fields,ulint n_fields,const dtuple_t * v_entry)1550 rec_convert_dtuple_to_temp(
1551 /*=======================*/
1552 	rec_t*			rec,		/*!< out: record */
1553 	const dict_index_t*	index,		/*!< in: record descriptor */
1554 	const dfield_t*		fields,		/*!< in: array of data fields */
1555 	ulint			n_fields,	/*!< in: number of fields */
1556 	const dtuple_t*		v_entry)	/*!< in: dtuple contains
1557 						virtual column data */
1558 {
1559 	rec_convert_dtuple_to_rec_comp(rec, index, fields, n_fields, v_entry,
1560 				       REC_STATUS_ORDINARY, true);
1561 }
1562 
1563 /**************************************************************//**
1564 Copies the first n fields of a physical record to a data tuple. The fields
1565 are copied to the memory heap. */
1566 void
rec_copy_prefix_to_dtuple(dtuple_t * tuple,const rec_t * rec,const dict_index_t * index,ulint n_fields,mem_heap_t * heap)1567 rec_copy_prefix_to_dtuple(
1568 /*======================*/
1569 	dtuple_t*		tuple,		/*!< out: data tuple */
1570 	const rec_t*		rec,		/*!< in: physical record */
1571 	const dict_index_t*	index,		/*!< in: record descriptor */
1572 	ulint			n_fields,	/*!< in: number of fields
1573 						to copy */
1574 	mem_heap_t*		heap)		/*!< in: memory heap */
1575 {
1576 	ulint	i;
1577 	ulint	offsets_[REC_OFFS_NORMAL_SIZE];
1578 	ulint*	offsets	= offsets_;
1579 	rec_offs_init(offsets_);
1580 
1581 	offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1582 
1583 	ut_ad(rec_validate(rec, offsets));
1584 	ut_ad(dtuple_check_typed(tuple));
1585 
1586 	dtuple_set_info_bits(tuple, rec_get_info_bits(
1587 				     rec, dict_table_is_comp(index->table)));
1588 
1589 	for (i = 0; i < n_fields; i++) {
1590 		dfield_t*	field;
1591 		const byte*	data;
1592 		ulint		len;
1593 
1594 		field = dtuple_get_nth_field(tuple, i);
1595 		data = rec_get_nth_field(rec, offsets, i, &len);
1596 
1597 		if (len != UNIV_SQL_NULL) {
1598 			dfield_set_data(field,
1599 					mem_heap_dup(heap, data, len), len);
1600 			ut_ad(!rec_offs_nth_extern(offsets, i));
1601 		} else {
1602 			dfield_set_null(field);
1603 		}
1604 	}
1605 }
1606 
1607 /**************************************************************//**
1608 Copies the first n fields of an old-style physical record
1609 to a new physical record in a buffer.
1610 @return own: copied record */
1611 static
1612 rec_t*
rec_copy_prefix_to_buf_old(const rec_t * rec,ulint n_fields,ulint area_end,byte ** buf,ulint * buf_size)1613 rec_copy_prefix_to_buf_old(
1614 /*=======================*/
1615 	const rec_t*	rec,		/*!< in: physical record */
1616 	ulint		n_fields,	/*!< in: number of fields to copy */
1617 	ulint		area_end,	/*!< in: end of the prefix data */
1618 	byte**		buf,		/*!< in/out: memory buffer for
1619 					the copied prefix, or NULL */
1620 	ulint*		buf_size)	/*!< in/out: buffer size */
1621 {
1622 	rec_t*	copy_rec;
1623 	ulint	area_start;
1624 	ulint	prefix_len;
1625 
1626 	if (rec_get_1byte_offs_flag(rec)) {
1627 		area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1628 	} else {
1629 		area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1630 	}
1631 
1632 	prefix_len = area_start + area_end;
1633 
1634 	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1635 		ut_free(*buf);
1636 		*buf_size = prefix_len;
1637 		*buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
1638 	}
1639 
1640 	ut_memcpy(*buf, rec - area_start, prefix_len);
1641 
1642 	copy_rec = *buf + area_start;
1643 
1644 	rec_set_n_fields_old(copy_rec, n_fields);
1645 
1646 	return(copy_rec);
1647 }
1648 
1649 /**************************************************************//**
1650 Copies the first n fields of a physical record to a new physical record in
1651 a buffer.
1652 @return own: copied record */
1653 rec_t*
rec_copy_prefix_to_buf(const rec_t * rec,const dict_index_t * index,ulint n_fields,byte ** buf,ulint * buf_size)1654 rec_copy_prefix_to_buf(
1655 /*===================*/
1656 	const rec_t*		rec,		/*!< in: physical record */
1657 	const dict_index_t*	index,		/*!< in: record descriptor */
1658 	ulint			n_fields,	/*!< in: number of fields
1659 						to copy */
1660 	byte**			buf,		/*!< in/out: memory buffer
1661 						for the copied prefix,
1662 						or NULL */
1663 	ulint*			buf_size)	/*!< in/out: buffer size */
1664 {
1665 	const byte*	nulls;
1666 	const byte*	lens;
1667 	ulint		i;
1668 	ulint		prefix_len;
1669 	ulint		null_mask;
1670 	ulint		status;
1671 	bool		is_rtr_node_ptr = false;
1672 
1673 	UNIV_PREFETCH_RW(*buf);
1674 
1675 	if (!dict_table_is_comp(index->table)) {
1676 		ut_ad(rec_validate_old(rec));
1677 		return(rec_copy_prefix_to_buf_old(
1678 			       rec, n_fields,
1679 			       rec_get_field_start_offs(rec, n_fields),
1680 			       buf, buf_size));
1681 	}
1682 
1683 	status = rec_get_status(rec);
1684 
1685 	switch (status) {
1686 	case REC_STATUS_ORDINARY:
1687 		ut_ad(n_fields <= dict_index_get_n_fields(index));
1688 		break;
1689 	case REC_STATUS_NODE_PTR:
1690 		/* For R-tree, we need to copy the child page number field. */
1691 		if (dict_index_is_spatial(index)) {
1692 			ut_ad(n_fields == DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1);
1693 			is_rtr_node_ptr = true;
1694 		} else {
1695 			/* it doesn't make sense to copy the child page number
1696 			field */
1697 			ut_ad(n_fields <=
1698 			      dict_index_get_n_unique_in_tree_nonleaf(index));
1699 		}
1700 		break;
1701 	case REC_STATUS_INFIMUM:
1702 	case REC_STATUS_SUPREMUM:
1703 		/* infimum or supremum record: no sense to copy anything */
1704 	default:
1705 		ut_error;
1706 		return(NULL);
1707 	}
1708 
1709 	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1710 	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1711 	UNIV_PREFETCH_R(lens);
1712 	prefix_len = 0;
1713 	null_mask = 1;
1714 
1715 	/* read the lengths of fields 0..n */
1716 	for (i = 0; i < n_fields; i++) {
1717 		const dict_field_t*	field;
1718 		const dict_col_t*	col;
1719 
1720 		field = dict_index_get_nth_field(index, i);
1721 		col = dict_field_get_col(field);
1722 
1723 		if (!(col->prtype & DATA_NOT_NULL)) {
1724 			/* nullable field => read the null flag */
1725 			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1726 				nulls--;
1727 				null_mask = 1;
1728 			}
1729 
1730 			if (*nulls & null_mask) {
1731 				null_mask <<= 1;
1732 				continue;
1733 			}
1734 
1735 			null_mask <<= 1;
1736 		}
1737 
1738 		if (is_rtr_node_ptr && i == 1) {
1739 			/* For rtree node ptr rec, we need to
1740 			copy the page no field with 4 bytes len. */
1741 			prefix_len += 4;
1742 		} else if (field->fixed_len) {
1743 			prefix_len += field->fixed_len;
1744 		} else {
1745 			ulint	len = *lens--;
1746 			/* If the maximum length of the column is up
1747 			to 255 bytes, the actual length is always
1748 			stored in one byte. If the maximum length is
1749 			more than 255 bytes, the actual length is
1750 			stored in one byte for 0..127.  The length
1751 			will be encoded in two bytes when it is 128 or
1752 			more, or when the column is stored externally. */
1753 			if (DATA_BIG_COL(col)) {
1754 				if (len & 0x80) {
1755 					/* 1exxxxxx */
1756 					len &= 0x3f;
1757 					len <<= 8;
1758 					len |= *lens--;
1759 					UNIV_PREFETCH_R(lens);
1760 				}
1761 			}
1762 			prefix_len += len;
1763 		}
1764 	}
1765 
1766 	UNIV_PREFETCH_R(rec + prefix_len);
1767 
1768 	prefix_len += rec - (lens + 1);
1769 
1770 	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1771 		ut_free(*buf);
1772 		*buf_size = prefix_len;
1773 		*buf = static_cast<byte*>(ut_malloc_nokey(prefix_len));
1774 	}
1775 
1776 	memcpy(*buf, lens + 1, prefix_len);
1777 
1778 	return(*buf + (rec - (lens + 1)));
1779 }
1780 #endif /* UNIV_HOTBACKUP */
1781 
1782 /***************************************************************//**
1783 Validates the consistency of an old-style physical record.
1784 @return TRUE if ok */
1785 static
1786 ibool
rec_validate_old(const rec_t * rec)1787 rec_validate_old(
1788 /*=============*/
1789 	const rec_t*	rec)	/*!< in: physical record */
1790 {
1791 	const byte*	data;
1792 	ulint		len;
1793 	ulint		n_fields;
1794 	ulint		len_sum		= 0;
1795 	ulint		sum		= 0;
1796 	ulint		i;
1797 
1798 	ut_a(rec);
1799 	n_fields = rec_get_n_fields_old(rec);
1800 
1801 	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1802 		ib::error() << "Record has " << n_fields << " fields";
1803 		return(FALSE);
1804 	}
1805 
1806 	for (i = 0; i < n_fields; i++) {
1807 		data = rec_get_nth_field_old(rec, i, &len);
1808 
1809 		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1810 			ib::error() << "Record field " << i << " len " << len;
1811 			return(FALSE);
1812 		}
1813 
1814 		if (len != UNIV_SQL_NULL) {
1815 			len_sum += len;
1816 			sum += *(data + len -1); /* dereference the
1817 						 end of the field to
1818 						 cause a memory trap
1819 						 if possible */
1820 		} else {
1821 			len_sum += rec_get_nth_field_size(rec, i);
1822 		}
1823 	}
1824 
1825 	if (len_sum != rec_get_data_size_old(rec)) {
1826 		ib::error() << "Record len should be " << len_sum << ", len "
1827 			<< rec_get_data_size_old(rec);
1828 		return(FALSE);
1829 	}
1830 
1831 	rec_dummy = sum; /* This is here only to fool the compiler */
1832 
1833 	return(TRUE);
1834 }
1835 
1836 /***************************************************************//**
1837 Validates the consistency of a physical record.
1838 @return TRUE if ok */
1839 ibool
rec_validate(const rec_t * rec,const ulint * offsets)1840 rec_validate(
1841 /*=========*/
1842 	const rec_t*	rec,	/*!< in: physical record */
1843 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
1844 {
1845 	const byte*	data;
1846 	ulint		len;
1847 	ulint		n_fields;
1848 	ulint		len_sum		= 0;
1849 	ulint		sum		= 0;
1850 	ulint		i;
1851 
1852 	ut_a(rec);
1853 	n_fields = rec_offs_n_fields(offsets);
1854 
1855 	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1856 		ib::error() << "Record has " << n_fields << " fields";
1857 		return(FALSE);
1858 	}
1859 
1860 	ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1861 
1862 	for (i = 0; i < n_fields; i++) {
1863 		data = rec_get_nth_field(rec, offsets, i, &len);
1864 
1865 		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1866 			ib::error() << "Record field " << i << " len " << len;
1867 			return(FALSE);
1868 		}
1869 
1870 		if (len != UNIV_SQL_NULL) {
1871 			len_sum += len;
1872 			sum += *(data + len -1); /* dereference the
1873 						 end of the field to
1874 						 cause a memory trap
1875 						 if possible */
1876 		} else if (!rec_offs_comp(offsets)) {
1877 			len_sum += rec_get_nth_field_size(rec, i);
1878 		}
1879 	}
1880 
1881 	if (len_sum != rec_offs_data_size(offsets)) {
1882 		ib::error() << "Record len should be " << len_sum << ", len "
1883 			<< rec_offs_data_size(offsets);
1884 		return(FALSE);
1885 	}
1886 
1887 	rec_dummy = sum; /* This is here only to fool the compiler */
1888 
1889 	if (!rec_offs_comp(offsets)) {
1890 		ut_a(rec_validate_old(rec));
1891 	}
1892 
1893 	return(TRUE);
1894 }
1895 
1896 /***************************************************************//**
1897 Prints an old-style physical record. */
1898 void
rec_print_old(FILE * file,const rec_t * rec)1899 rec_print_old(
1900 /*==========*/
1901 	FILE*		file,	/*!< in: file where to print */
1902 	const rec_t*	rec)	/*!< in: physical record */
1903 {
1904 	const byte*	data;
1905 	ulint		len;
1906 	ulint		n;
1907 	ulint		i;
1908 
1909 	ut_ad(rec);
1910 
1911 	n = rec_get_n_fields_old(rec);
1912 
1913 	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1914 		" %u-byte offsets; info bits %lu\n",
1915 		(ulong) n,
1916 		rec_get_1byte_offs_flag(rec) ? 1 : 2,
1917 		(ulong) rec_get_info_bits(rec, FALSE));
1918 
1919 	for (i = 0; i < n; i++) {
1920 
1921 		data = rec_get_nth_field_old(rec, i, &len);
1922 
1923 		fprintf(file, " %lu:", (ulong) i);
1924 
1925 		if (len != UNIV_SQL_NULL) {
1926 			if (len <= 30) {
1927 
1928 				ut_print_buf(file, data, len);
1929 			} else {
1930 				ut_print_buf(file, data, 30);
1931 
1932 				fprintf(file, " (total %lu bytes)",
1933 					(ulong) len);
1934 			}
1935 		} else {
1936 			fprintf(file, " SQL NULL, size " ULINTPF " ",
1937 				rec_get_nth_field_size(rec, i));
1938 		}
1939 
1940 		putc(';', file);
1941 		putc('\n', file);
1942 	}
1943 
1944 	rec_validate_old(rec);
1945 }
1946 
1947 #ifndef UNIV_HOTBACKUP
1948 /***************************************************************//**
1949 Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
1950 record header. */
1951 void
rec_print_comp(FILE * file,const rec_t * rec,const ulint * offsets)1952 rec_print_comp(
1953 /*===========*/
1954 	FILE*		file,	/*!< in: file where to print */
1955 	const rec_t*	rec,	/*!< in: physical record */
1956 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
1957 {
1958 	ulint	i;
1959 
1960 	for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1961 		const byte*	data;
1962 		ulint		len;
1963 
1964 		data = rec_get_nth_field(rec, offsets, i, &len);
1965 
1966 		fprintf(file, " %lu:", (ulong) i);
1967 
1968 		if (len != UNIV_SQL_NULL) {
1969 			if (len <= 30) {
1970 
1971 				ut_print_buf(file, data, len);
1972 			} else if (rec_offs_nth_extern(offsets, i)) {
1973 				ut_print_buf(file, data, 30);
1974 				fprintf(file, " (total %lu bytes, external)",
1975 					(ulong) len);
1976 				ut_print_buf(file, data + len
1977 					     - BTR_EXTERN_FIELD_REF_SIZE,
1978 					     BTR_EXTERN_FIELD_REF_SIZE);
1979 			} else {
1980 				ut_print_buf(file, data, 30);
1981 
1982 				fprintf(file, " (total %lu bytes)",
1983 					(ulong) len);
1984 			}
1985 		} else {
1986 			fputs(" SQL NULL", file);
1987 		}
1988 		putc(';', file);
1989 		putc('\n', file);
1990 	}
1991 }
1992 
1993 /***************************************************************//**
1994 Prints an old-style spatial index record. */
1995 void
rec_print_mbr_old(FILE * file,const rec_t * rec)1996 rec_print_mbr_old(
1997 /*==============*/
1998 	FILE*		file,	/*!< in: file where to print */
1999 	const rec_t*	rec)	/*!< in: physical record */
2000 {
2001 	const byte*	data;
2002 	ulint		len;
2003 	ulint		n;
2004 	ulint		i;
2005 
2006 	ut_ad(rec);
2007 
2008 	n = rec_get_n_fields_old(rec);
2009 
2010 	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
2011 		" %u-byte offsets; info bits %lu\n",
2012 		(ulong) n,
2013 		rec_get_1byte_offs_flag(rec) ? 1 : 2,
2014 		(ulong) rec_get_info_bits(rec, FALSE));
2015 
2016 	for (i = 0; i < n; i++) {
2017 
2018 		data = rec_get_nth_field_old(rec, i, &len);
2019 
2020 		fprintf(file, " %lu:", (ulong) i);
2021 
2022 		if (len != UNIV_SQL_NULL) {
2023 			if (i == 0) {
2024 				fprintf(file, " MBR:");
2025 				for (; len > 0; len -= sizeof(double)) {
2026 					double	d = mach_double_read(data);
2027 
2028 					if (len != sizeof(double)) {
2029 						fprintf(file, "%.2lf,", d);
2030 					} else {
2031 						fprintf(file, "%.2lf", d);
2032 					}
2033 
2034 					data += sizeof(double);
2035 				}
2036 			} else {
2037 				if (len <= 30) {
2038 
2039 					ut_print_buf(file, data, len);
2040 				} else {
2041 					ut_print_buf(file, data, 30);
2042 
2043 					fprintf(file, " (total %lu bytes)",
2044 						(ulong) len);
2045 				}
2046 			}
2047 		} else {
2048 			fprintf(file, " SQL NULL, size " ULINTPF " ",
2049 				rec_get_nth_field_size(rec, i));
2050 		}
2051 
2052 		putc(';', file);
2053 		putc('\n', file);
2054 	}
2055 
2056 	if (rec_get_deleted_flag(rec, false)) {
2057 		fprintf(file, " Deleted");
2058 	}
2059 
2060 	if (rec_get_info_bits(rec, true) & REC_INFO_MIN_REC_FLAG) {
2061 		fprintf(file, " First rec");
2062 	}
2063 
2064 	rec_validate_old(rec);
2065 }
2066 
2067 /***************************************************************//**
2068 Prints a spatial index record. */
2069 void
rec_print_mbr_rec(FILE * file,const rec_t * rec,const ulint * offsets)2070 rec_print_mbr_rec(
2071 /*==============*/
2072 	FILE*		file,	/*!< in: file where to print */
2073 	const rec_t*	rec,	/*!< in: physical record */
2074 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
2075 {
2076 	ut_ad(rec);
2077 	ut_ad(offsets);
2078 	ut_ad(rec_offs_validate(rec, NULL, offsets));
2079 
2080 	if (!rec_offs_comp(offsets)) {
2081 		rec_print_mbr_old(file, rec);
2082 		return;
2083 	}
2084 
2085 	for (ulint i = 0; i < rec_offs_n_fields(offsets); i++) {
2086 		const byte*	data;
2087 		ulint		len;
2088 
2089 		data = rec_get_nth_field(rec, offsets, i, &len);
2090 
2091 		if (i == 0) {
2092 			fprintf(file, " MBR:");
2093 			for (; len > 0; len -= sizeof(double)) {
2094 				double	d = mach_double_read(data);
2095 
2096 				if (len != sizeof(double)) {
2097 					fprintf(file, "%.2lf,", d);
2098 				} else {
2099 					fprintf(file, "%.2lf", d);
2100 				}
2101 
2102 				data += sizeof(double);
2103 			}
2104 		} else {
2105 			fprintf(file, " %lu:", (ulong) i);
2106 
2107 			if (len != UNIV_SQL_NULL) {
2108 				if (len <= 30) {
2109 
2110 					ut_print_buf(file, data, len);
2111 				} else {
2112 					ut_print_buf(file, data, 30);
2113 
2114 					fprintf(file, " (total %lu bytes)",
2115 						(ulong) len);
2116 				}
2117 			} else {
2118 				fputs(" SQL NULL", file);
2119 			}
2120 		}
2121 		putc(';', file);
2122 	}
2123 
2124 	if (rec_get_info_bits(rec, true) & REC_INFO_DELETED_FLAG) {
2125 		fprintf(file, " Deleted");
2126 	}
2127 
2128 	if (rec_get_info_bits(rec, true) & REC_INFO_MIN_REC_FLAG) {
2129 		fprintf(file, " First rec");
2130 	}
2131 
2132 
2133 	rec_validate(rec, offsets);
2134 }
2135 
2136 /***************************************************************//**
2137 Prints a physical record. */
2138 /***************************************************************//**
2139 Prints a physical record. */
2140 void
rec_print_new(FILE * file,const rec_t * rec,const ulint * offsets)2141 rec_print_new(
2142 /*==========*/
2143 	FILE*		file,	/*!< in: file where to print */
2144 	const rec_t*	rec,	/*!< in: physical record */
2145 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
2146 {
2147 	ut_ad(rec);
2148 	ut_ad(offsets);
2149 	ut_ad(rec_offs_validate(rec, NULL, offsets));
2150 
2151 #ifdef UNIV_DEBUG
2152 	if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
2153 		DBUG_PRINT("info", ("deleted "));
2154 	} else {
2155 		DBUG_PRINT("info", ("not-deleted "));
2156 	}
2157 #endif /* UNIV_DEBUG */
2158 
2159 	if (!rec_offs_comp(offsets)) {
2160 		rec_print_old(file, rec);
2161 		return;
2162 	}
2163 
2164 	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
2165 		" compact format; info bits %lu\n",
2166 		(ulong) rec_offs_n_fields(offsets),
2167 		(ulong) rec_get_info_bits(rec, TRUE));
2168 
2169 	rec_print_comp(file, rec, offsets);
2170 	rec_validate(rec, offsets);
2171 }
2172 
2173 /***************************************************************//**
2174 Prints a physical record. */
2175 void
rec_print(FILE * file,const rec_t * rec,const dict_index_t * index)2176 rec_print(
2177 /*======*/
2178 	FILE*			file,	/*!< in: file where to print */
2179 	const rec_t*		rec,	/*!< in: physical record */
2180 	const dict_index_t*	index)	/*!< in: record descriptor */
2181 {
2182 	ut_ad(index);
2183 
2184 	if (!dict_table_is_comp(index->table)) {
2185 		rec_print_old(file, rec);
2186 		return;
2187 	} else {
2188 		mem_heap_t*	heap	= NULL;
2189 		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
2190 		rec_offs_init(offsets_);
2191 
2192 		rec_print_new(file, rec,
2193 			      rec_get_offsets(rec, index, offsets_,
2194 					      ULINT_UNDEFINED, &heap));
2195 		if (UNIV_LIKELY_NULL(heap)) {
2196 			mem_heap_free(heap);
2197 		}
2198 	}
2199 }
2200 
2201 /** Pretty-print a record.
2202 @param[in,out]	o	output stream
2203 @param[in]	rec	physical record
2204 @param[in]	info	rec_get_info_bits(rec)
2205 @param[in]	offsets	rec_get_offsets(rec) */
2206 void
rec_print(std::ostream & o,const rec_t * rec,ulint info,const ulint * offsets)2207 rec_print(
2208 	std::ostream&	o,
2209 	const rec_t*	rec,
2210 	ulint		info,
2211 	const ulint*	offsets)
2212 {
2213 	const ulint	comp	= rec_offs_comp(offsets);
2214 	const ulint	n	= rec_offs_n_fields(offsets);
2215 
2216 	ut_ad(rec_offs_validate(rec, NULL, offsets));
2217 
2218 	o << (comp ? "COMPACT RECORD" : "RECORD")
2219 	  << "(info_bits=" << info << ", " << n << " fields): {";
2220 
2221 	for (ulint i = 0; i < n; i++) {
2222 		const byte*	data;
2223 		ulint		len;
2224 
2225 		if (i) {
2226 			o << ',';
2227 		}
2228 
2229 		data = rec_get_nth_field(rec, offsets, i, &len);
2230 
2231 		if (len == UNIV_SQL_NULL) {
2232 			o << "NULL";
2233 			continue;
2234 		}
2235 
2236 		if (rec_offs_nth_extern(offsets, i)) {
2237 			ulint	local_len = len - BTR_EXTERN_FIELD_REF_SIZE;
2238 			ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
2239 
2240 			o << '['
2241 			  << local_len
2242 			  << '+' << BTR_EXTERN_FIELD_REF_SIZE << ']';
2243 			ut_print_buf(o, data, local_len);
2244 			ut_print_buf_hex(o, data + local_len,
2245 					 BTR_EXTERN_FIELD_REF_SIZE);
2246 		} else {
2247 			o << '[' << len << ']';
2248 			ut_print_buf(o, data, len);
2249 		}
2250 	}
2251 
2252 	o << "}";
2253 }
2254 
2255 /** Display a record.
2256 @param[in,out]	o	output stream
2257 @param[in]	r	record to display
2258 @return	the output stream */
2259 std::ostream&
operator <<(std::ostream & o,const rec_index_print & r)2260 operator<<(std::ostream& o, const rec_index_print& r)
2261 {
2262 	mem_heap_t*	heap	= NULL;
2263 	ulint*		offsets	= rec_get_offsets(
2264 		r.m_rec, r.m_index, NULL, ULINT_UNDEFINED, &heap);
2265 	rec_print(o, r.m_rec,
2266 		  rec_get_info_bits(r.m_rec, rec_offs_comp(offsets)),
2267 		  offsets);
2268 	mem_heap_free(heap);
2269 	return(o);
2270 }
2271 
2272 /** Display a record.
2273 @param[in,out]	o	output stream
2274 @param[in]	r	record to display
2275 @return	the output stream */
2276 std::ostream&
operator <<(std::ostream & o,const rec_offsets_print & r)2277 operator<<(std::ostream& o, const rec_offsets_print& r)
2278 {
2279 	rec_print(o, r.m_rec,
2280 		  rec_get_info_bits(r.m_rec, rec_offs_comp(r.m_offsets)),
2281 		  r.m_offsets);
2282 	return(o);
2283 }
2284 
2285 # ifdef UNIV_DEBUG
2286 /************************************************************//**
2287 Reads the DB_TRX_ID of a clustered index record.
2288 @return the value of DB_TRX_ID */
2289 trx_id_t
rec_get_trx_id(const rec_t * rec,const dict_index_t * index)2290 rec_get_trx_id(
2291 /*===========*/
2292 	const rec_t*		rec,	/*!< in: record */
2293 	const dict_index_t*	index)	/*!< in: clustered index */
2294 {
2295 	const page_t*	page
2296 		= page_align(rec);
2297 	ulint		trx_id_col
2298 		= dict_index_get_sys_col_pos(index, DATA_TRX_ID);
2299 	const byte*	trx_id;
2300 	ulint		len;
2301 	mem_heap_t*	heap		= NULL;
2302 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
2303 	ulint*		offsets		= offsets_;
2304 	rec_offs_init(offsets_);
2305 
2306 	ut_ad(fil_page_index_page_check(page));
2307 	ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID)
2308 	      == index->id);
2309 	ut_ad(dict_index_is_clust(index));
2310 	ut_ad(trx_id_col > 0);
2311 	ut_ad(trx_id_col != ULINT_UNDEFINED);
2312 
2313 	offsets = rec_get_offsets(rec, index, offsets, trx_id_col + 1, &heap);
2314 
2315 	trx_id = rec_get_nth_field(rec, offsets, trx_id_col, &len);
2316 
2317 	ut_ad(len == DATA_TRX_ID_LEN);
2318 
2319 	if (heap) {
2320 		mem_heap_free(heap);
2321 	}
2322 
2323 	return(trx_read_trx_id(trx_id));
2324 }
2325 # endif /* UNIV_DEBUG */
2326 #endif /* !UNIV_HOTBACKUP */
2327 
2328 /** Mark the nth field as externally stored.
2329 @param[in]	offsets		array returned by rec_get_offsets()
2330 @param[in]	n		nth field */
2331 void
rec_offs_make_nth_extern(ulint * offsets,const ulint n)2332 rec_offs_make_nth_extern(
2333 	ulint*		offsets,
2334 	const ulint	n)
2335 {
2336 	ut_ad(!rec_offs_nth_sql_null(offsets, n));
2337 	rec_offs_base(offsets)[1 + n] |= REC_OFFS_EXTERNAL;
2338 }
2339 #ifdef WITH_WSREP
2340 dberr_t
wsrep_rec_get_foreign_key(byte * buf,ulint * buf_len,const rec_t * rec,dict_index_t * index_for,dict_index_t * index_ref,ibool new_protocol)2341 wsrep_rec_get_foreign_key(
2342 	byte 		*buf,     /* out: extracted key */
2343 	ulint 		*buf_len, /* in/out: length of buf */
2344 	const rec_t*	rec,	  /* in: physical record */
2345 	dict_index_t*	index_for,  /* in: index in foreign table */
2346 	dict_index_t*	index_ref,  /* in: index in referenced table */
2347 	ibool		new_protocol) /* in: protocol > 1 */
2348 {
2349 	const byte*	data;
2350 	ulint		len;
2351 	ulint		key_len = 0;
2352 	ulint		i;
2353 	uint            key_parts;
2354 	mem_heap_t*	heap	= NULL;
2355 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
2356         const ulint*    offsets;
2357 
2358 	ut_ad(index_for);
2359 	ut_ad(index_ref);
2360 
2361         rec_offs_init(offsets_);
2362 	offsets = rec_get_offsets(rec, index_for, offsets_,
2363 				  ULINT_UNDEFINED, &heap);
2364 
2365 	ut_ad(rec_offs_validate(rec, NULL, offsets));
2366 
2367 	ut_ad(rec);
2368 
2369 	key_parts = dict_index_get_n_unique_in_tree(index_for);
2370 	for (i = 0;
2371 	     i < key_parts &&
2372 	       (index_for->type & DICT_CLUSTERED || i < key_parts - 1);
2373 	     i++) {
2374 		dict_field_t*	  field_f =
2375 			dict_index_get_nth_field(index_for, i);
2376 		const dict_col_t* col_f = dict_field_get_col(field_f);
2377                 dict_field_t*	  field_r =
2378 			dict_index_get_nth_field(index_ref, i);
2379 		const dict_col_t* col_r = dict_field_get_col(field_r);
2380 
2381 		data = rec_get_nth_field(rec, offsets, i, &len);
2382 		if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) >
2383 		    *buf_len) {
2384 			fprintf (stderr,
2385 				 "WSREP: FK key len exceeded %lu %lu %lu\n",
2386 				 key_len, len, *buf_len);
2387 			goto err_out;
2388 		}
2389 
2390 		if (len == UNIV_SQL_NULL) {
2391 			ut_a(!(col_f->prtype & DATA_NOT_NULL));
2392 			*buf++ = 1;
2393 			key_len++;
2394 		} else if (!new_protocol) {
2395 			if (!(col_r->prtype & DATA_NOT_NULL)) {
2396 				*buf++ = 0;
2397 				key_len++;
2398 			}
2399 			memcpy(buf, data, len);
2400 			*buf_len = wsrep_innobase_mysql_sort(
2401 				(int)(col_f->prtype & DATA_MYSQL_TYPE_MASK),
2402 				(uint)dtype_get_charset_coll(col_f->prtype),
2403 				buf, len, *buf_len);
2404 		} else { /* new protocol */
2405 			if (!(col_r->prtype & DATA_NOT_NULL)) {
2406 				*buf++ = 0;
2407 				key_len++;
2408 			}
2409 			switch (col_f->mtype) {
2410 			case DATA_INT: {
2411 				byte* ptr = buf+len;
2412 				for (;;) {
2413 					ptr--;
2414 					*ptr = *data;
2415 					if (ptr == buf) {
2416 						break;
2417 					}
2418 					data++;
2419 				}
2420 
2421 				if (!(col_f->prtype & DATA_UNSIGNED)) {
2422 					buf[len-1] = (byte) (buf[len-1] ^ 128);
2423 				}
2424 
2425 				break;
2426 			}
2427 			case DATA_VARCHAR:
2428 			case DATA_VARMYSQL:
2429 			case DATA_CHAR:
2430 			case DATA_MYSQL:
2431 				/* Copy the actual data */
2432 				ut_memcpy(buf, data, len);
2433 				len = wsrep_innobase_mysql_sort(
2434 					(int)
2435 					(col_f->prtype & DATA_MYSQL_TYPE_MASK),
2436 					(uint)
2437 					dtype_get_charset_coll(col_f->prtype),
2438 					buf, len, *buf_len);
2439 				break;
2440 			case DATA_BLOB:
2441 			case DATA_BINARY:
2442 				memcpy(buf, data, len);
2443 				break;
2444 			default:
2445 				break;
2446 			}
2447 
2448 			key_len += len;
2449 			buf 	+= len;
2450 		}
2451 	}
2452 
2453 	rec_validate(rec, offsets);
2454 
2455 	if (UNIV_LIKELY_NULL(heap)) {
2456 		mem_heap_free(heap);
2457 	}
2458 
2459 	*buf_len = key_len;
2460 	return DB_SUCCESS;
2461 
2462  err_out:
2463 	if (UNIV_LIKELY_NULL(heap)) {
2464 		mem_heap_free(heap);
2465 	}
2466 	return DB_ERROR;
2467 }
2468 #endif // WITH_WSREP
2469