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 data/data0data.cc
29 SQL data field and tuple
30 
31 Created 5/30/1994 Heikki Tuuri
32 *************************************************************************/
33 
34 #include "data0data.h"
35 
36 #ifdef UNIV_NONINL
37 #include "data0data.ic"
38 #endif
39 
40 #ifndef UNIV_HOTBACKUP
41 #include "rem0rec.h"
42 #include "rem0cmp.h"
43 #include "page0page.h"
44 #include "page0zip.h"
45 #include "dict0dict.h"
46 #include "btr0cur.h"
47 
48 #include <ctype.h>
49 #endif /* !UNIV_HOTBACKUP */
50 
51 #ifdef UNIV_DEBUG
52 /** Dummy variable to catch access to uninitialized fields.  In the
53 debug version, dtuple_create() will make all fields of dtuple_t point
54 to data_error. */
55 UNIV_INTERN byte	data_error;
56 
57 # ifndef UNIV_DEBUG_VALGRIND
58 /** this is used to fool the compiler in dtuple_validate */
59 UNIV_INTERN ulint	data_dummy;
60 # endif /* !UNIV_DEBUG_VALGRIND */
61 #endif /* UNIV_DEBUG */
62 
63 #ifndef UNIV_HOTBACKUP
64 /************************************************************//**
65 Compare two data tuples, respecting the collation of character fields.
66 @return 1, 0 , -1 if tuple1 is greater, equal, less, respectively,
67 than tuple2 */
68 UNIV_INTERN
69 int
dtuple_coll_cmp(const dtuple_t * tuple1,const dtuple_t * tuple2)70 dtuple_coll_cmp(
71 /*============*/
72 	const dtuple_t*	tuple1,	/*!< in: tuple 1 */
73 	const dtuple_t*	tuple2)	/*!< in: tuple 2 */
74 {
75 	ulint	n_fields;
76 	ulint	i;
77 
78 	ut_ad(tuple1 != NULL);
79 	ut_ad(tuple2 != NULL);
80 	ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
81 	ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
82 	ut_ad(dtuple_check_typed(tuple1));
83 	ut_ad(dtuple_check_typed(tuple2));
84 
85 	n_fields = dtuple_get_n_fields(tuple1);
86 
87 	if (n_fields != dtuple_get_n_fields(tuple2)) {
88 
89 		return(n_fields < dtuple_get_n_fields(tuple2) ? -1 : 1);
90 	}
91 
92 	for (i = 0; i < n_fields; i++) {
93 		int		cmp;
94 		const dfield_t*	field1	= dtuple_get_nth_field(tuple1, i);
95 		const dfield_t*	field2	= dtuple_get_nth_field(tuple2, i);
96 
97 		cmp = cmp_dfield_dfield(field1, field2);
98 
99 		if (cmp) {
100 			return(cmp);
101 		}
102 	}
103 
104 	return(0);
105 }
106 
107 /*********************************************************************//**
108 Sets number of fields used in a tuple. Normally this is set in
109 dtuple_create, but if you want later to set it smaller, you can use this. */
110 UNIV_INTERN
111 void
dtuple_set_n_fields(dtuple_t * tuple,ulint n_fields)112 dtuple_set_n_fields(
113 /*================*/
114 	dtuple_t*	tuple,		/*!< in: tuple */
115 	ulint		n_fields)	/*!< in: number of fields */
116 {
117 	ut_ad(tuple);
118 
119 	tuple->n_fields = n_fields;
120 	tuple->n_fields_cmp = n_fields;
121 }
122 
123 /**********************************************************//**
124 Checks that a data field is typed.
125 @return	TRUE if ok */
126 static
127 ibool
dfield_check_typed_no_assert(const dfield_t * field)128 dfield_check_typed_no_assert(
129 /*=========================*/
130 	const dfield_t*	field)	/*!< in: data field */
131 {
132 	if (dfield_get_type(field)->mtype > DATA_MYSQL
133 	    || dfield_get_type(field)->mtype < DATA_VARCHAR) {
134 
135 		fprintf(stderr,
136 			"InnoDB: Error: data field type %lu, len %lu\n",
137 			(ulong) dfield_get_type(field)->mtype,
138 			(ulong) dfield_get_len(field));
139 		return(FALSE);
140 	}
141 
142 	return(TRUE);
143 }
144 
145 /**********************************************************//**
146 Checks that a data tuple is typed.
147 @return	TRUE if ok */
148 UNIV_INTERN
149 ibool
dtuple_check_typed_no_assert(const dtuple_t * tuple)150 dtuple_check_typed_no_assert(
151 /*=========================*/
152 	const dtuple_t*	tuple)	/*!< in: tuple */
153 {
154 	const dfield_t*	field;
155 	ulint		i;
156 
157 	if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
158 		fprintf(stderr,
159 			"InnoDB: Error: index entry has %lu fields\n",
160 			(ulong) dtuple_get_n_fields(tuple));
161 dump:
162 		fputs("InnoDB: Tuple contents: ", stderr);
163 		dtuple_print(stderr, tuple);
164 		putc('\n', stderr);
165 
166 		return(FALSE);
167 	}
168 
169 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
170 
171 		field = dtuple_get_nth_field(tuple, i);
172 
173 		if (!dfield_check_typed_no_assert(field)) {
174 			goto dump;
175 		}
176 	}
177 
178 	return(TRUE);
179 }
180 #endif /* !UNIV_HOTBACKUP */
181 
182 #ifdef UNIV_DEBUG
183 /**********************************************************//**
184 Checks that a data field is typed. Asserts an error if not.
185 @return	TRUE if ok */
186 UNIV_INTERN
187 ibool
dfield_check_typed(const dfield_t * field)188 dfield_check_typed(
189 /*===============*/
190 	const dfield_t*	field)	/*!< in: data field */
191 {
192 	if (dfield_get_type(field)->mtype > DATA_MYSQL
193 	    || dfield_get_type(field)->mtype < DATA_VARCHAR) {
194 
195 		fprintf(stderr,
196 			"InnoDB: Error: data field type %lu, len %lu\n",
197 			(ulong) dfield_get_type(field)->mtype,
198 			(ulong) dfield_get_len(field));
199 
200 		ut_error;
201 	}
202 
203 	return(TRUE);
204 }
205 
206 /**********************************************************//**
207 Checks that a data tuple is typed. Asserts an error if not.
208 @return	TRUE if ok */
209 UNIV_INTERN
210 ibool
dtuple_check_typed(const dtuple_t * tuple)211 dtuple_check_typed(
212 /*===============*/
213 	const dtuple_t*	tuple)	/*!< in: tuple */
214 {
215 	const dfield_t*	field;
216 	ulint		i;
217 
218 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
219 
220 		field = dtuple_get_nth_field(tuple, i);
221 
222 		ut_a(dfield_check_typed(field));
223 	}
224 
225 	return(TRUE);
226 }
227 
228 /**********************************************************//**
229 Validates the consistency of a tuple which must be complete, i.e,
230 all fields must have been set.
231 @return	TRUE if ok */
232 UNIV_INTERN
233 ibool
dtuple_validate(const dtuple_t * tuple)234 dtuple_validate(
235 /*============*/
236 	const dtuple_t*	tuple)	/*!< in: tuple */
237 {
238 	const dfield_t*	field;
239 	ulint		n_fields;
240 	ulint		len;
241 	ulint		i;
242 
243 	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
244 
245 	n_fields = dtuple_get_n_fields(tuple);
246 
247 	/* We dereference all the data of each field to test
248 	for memory traps */
249 
250 	for (i = 0; i < n_fields; i++) {
251 
252 		field = dtuple_get_nth_field(tuple, i);
253 		len = dfield_get_len(field);
254 
255 		if (!dfield_is_null(field)) {
256 
257 			const byte*	data;
258 
259 			data = static_cast<const byte*>(dfield_get_data(field));
260 #ifndef UNIV_DEBUG_VALGRIND
261 			ulint		j;
262 
263 			for (j = 0; j < len; j++) {
264 
265 				data_dummy  += *data; /* fool the compiler not
266 						      to optimize out this
267 						      code */
268 				data++;
269 			}
270 #endif /* !UNIV_DEBUG_VALGRIND */
271 
272 			UNIV_MEM_ASSERT_RW(data, len);
273 		}
274 	}
275 
276 	ut_a(dtuple_check_typed(tuple));
277 
278 	return(TRUE);
279 }
280 #endif /* UNIV_DEBUG */
281 
282 #ifndef UNIV_HOTBACKUP
283 /*************************************************************//**
284 Pretty prints a dfield value according to its data type. */
285 UNIV_INTERN
286 void
dfield_print(const dfield_t * dfield)287 dfield_print(
288 /*=========*/
289 	const dfield_t*	dfield)	/*!< in: dfield */
290 {
291 	const byte*	data;
292 	ulint		len;
293 	ulint		i;
294 
295 	len = dfield_get_len(dfield);
296 	data = static_cast<const byte*>(dfield_get_data(dfield));
297 
298 	if (dfield_is_null(dfield)) {
299 		fputs("NULL", stderr);
300 
301 		return;
302 	}
303 
304 	switch (dtype_get_mtype(dfield_get_type(dfield))) {
305 	case DATA_CHAR:
306 	case DATA_VARCHAR:
307 		for (i = 0; i < len; i++) {
308 			int	c = *data++;
309 			putc(isprint(c) ? c : ' ', stderr);
310 		}
311 
312 		if (dfield_is_ext(dfield)) {
313 			fputs("(external)", stderr);
314 		}
315 		break;
316 	case DATA_INT:
317 		ut_a(len == 4); /* only works for 32-bit integers */
318 		fprintf(stderr, "%d", (int) mach_read_from_4(data));
319 		break;
320 	default:
321 		ut_error;
322 	}
323 }
324 
325 /*************************************************************//**
326 Pretty prints a dfield value according to its data type. Also the hex string
327 is printed if a string contains non-printable characters. */
328 UNIV_INTERN
329 void
dfield_print_also_hex(const dfield_t * dfield)330 dfield_print_also_hex(
331 /*==================*/
332 	const dfield_t*	dfield)	/*!< in: dfield */
333 {
334 	const byte*	data;
335 	ulint		len;
336 	ulint		prtype;
337 	ulint		i;
338 	ibool		print_also_hex;
339 
340 	len = dfield_get_len(dfield);
341 	data = static_cast<const byte*>(dfield_get_data(dfield));
342 
343 	if (dfield_is_null(dfield)) {
344 		fputs("NULL", stderr);
345 
346 		return;
347 	}
348 
349 	prtype = dtype_get_prtype(dfield_get_type(dfield));
350 
351 	switch (dtype_get_mtype(dfield_get_type(dfield))) {
352 		ib_id_t	id;
353 	case DATA_INT:
354 		switch (len) {
355 			ulint	val;
356 		case 1:
357 			val = mach_read_from_1(data);
358 
359 			if (!(prtype & DATA_UNSIGNED)) {
360 				val &= ~0x80;
361 				fprintf(stderr, "%ld", (long) val);
362 			} else {
363 				fprintf(stderr, "%lu", (ulong) val);
364 			}
365 			break;
366 
367 		case 2:
368 			val = mach_read_from_2(data);
369 
370 			if (!(prtype & DATA_UNSIGNED)) {
371 				val &= ~0x8000;
372 				fprintf(stderr, "%ld", (long) val);
373 			} else {
374 				fprintf(stderr, "%lu", (ulong) val);
375 			}
376 			break;
377 
378 		case 3:
379 			val = mach_read_from_3(data);
380 
381 			if (!(prtype & DATA_UNSIGNED)) {
382 				val &= ~0x800000;
383 				fprintf(stderr, "%ld", (long) val);
384 			} else {
385 				fprintf(stderr, "%lu", (ulong) val);
386 			}
387 			break;
388 
389 		case 4:
390 			val = mach_read_from_4(data);
391 
392 			if (!(prtype & DATA_UNSIGNED)) {
393 				val &= ~0x80000000;
394 				fprintf(stderr, "%ld", (long) val);
395 			} else {
396 				fprintf(stderr, "%lu", (ulong) val);
397 			}
398 			break;
399 
400 		case 6:
401 			id = mach_read_from_6(data);
402 			fprintf(stderr, "%llu", (ullint) id);
403 			break;
404 
405 		case 7:
406 			id = mach_read_from_7(data);
407 			fprintf(stderr, "%llu", (ullint) id);
408 			break;
409 		case 8:
410 			id = mach_read_from_8(data);
411 			fprintf(stderr, "%llu", (ullint) id);
412 			break;
413 		default:
414 			goto print_hex;
415 		}
416 		break;
417 
418 	case DATA_SYS:
419 		switch (prtype & DATA_SYS_PRTYPE_MASK) {
420 		case DATA_TRX_ID:
421 			id = mach_read_from_6(data);
422 
423 			fprintf(stderr, "trx_id " TRX_ID_FMT, id);
424 			break;
425 
426 		case DATA_ROLL_PTR:
427 			id = mach_read_from_7(data);
428 
429 			fprintf(stderr, "roll_ptr " TRX_ID_FMT, id);
430 			break;
431 
432 		case DATA_ROW_ID:
433 			id = mach_read_from_6(data);
434 
435 			fprintf(stderr, "row_id " TRX_ID_FMT, id);
436 			break;
437 
438 		default:
439 			id = mach_ull_read_compressed(data);
440 
441 			fprintf(stderr, "mix_id " TRX_ID_FMT, id);
442 		}
443 		break;
444 
445 	case DATA_CHAR:
446 	case DATA_VARCHAR:
447 		print_also_hex = FALSE;
448 
449 		for (i = 0; i < len; i++) {
450 			int c = *data++;
451 
452 			if (!isprint(c)) {
453 				print_also_hex = TRUE;
454 
455 				fprintf(stderr, "\\x%02x", (unsigned char) c);
456 			} else {
457 				putc(c, stderr);
458 			}
459 		}
460 
461 		if (dfield_is_ext(dfield)) {
462 			fputs("(external)", stderr);
463 		}
464 
465 		if (!print_also_hex) {
466 			break;
467 		}
468 
469 		data = static_cast<byte*>(dfield_get_data(dfield));
470 		/* fall through */
471 
472 	case DATA_BINARY:
473 	default:
474 print_hex:
475 		fputs(" Hex: ",stderr);
476 
477 		for (i = 0; i < len; i++) {
478 			fprintf(stderr, "%02lx", (ulint) *data++);
479 		}
480 
481 		if (dfield_is_ext(dfield)) {
482 			fputs("(external)", stderr);
483 		}
484 	}
485 }
486 
487 /*************************************************************//**
488 Print a dfield value using ut_print_buf. */
489 static
490 void
dfield_print_raw(FILE * f,const dfield_t * dfield)491 dfield_print_raw(
492 /*=============*/
493 	FILE*		f,		/*!< in: output stream */
494 	const dfield_t*	dfield)		/*!< in: dfield */
495 {
496 	ulint	len	= dfield_get_len(dfield);
497 	if (!dfield_is_null(dfield)) {
498 		ulint	print_len = ut_min(len, 1000);
499 		ut_print_buf(f, dfield_get_data(dfield), print_len);
500 		if (len != print_len) {
501 			fprintf(f, "(total %lu bytes%s)",
502 				(ulong) len,
503 				dfield_is_ext(dfield) ? ", external" : "");
504 		}
505 	} else {
506 		fputs(" SQL NULL", f);
507 	}
508 }
509 
510 /**********************************************************//**
511 The following function prints the contents of a tuple. */
512 UNIV_INTERN
513 void
dtuple_print(FILE * f,const dtuple_t * tuple)514 dtuple_print(
515 /*=========*/
516 	FILE*		f,	/*!< in: output stream */
517 	const dtuple_t*	tuple)	/*!< in: tuple */
518 {
519 	ulint		n_fields;
520 	ulint		i;
521 
522 	n_fields = dtuple_get_n_fields(tuple);
523 
524 	fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
525 
526 	for (i = 0; i < n_fields; i++) {
527 		fprintf(f, " %lu:", (ulong) i);
528 
529 		dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
530 
531 		putc(';', f);
532 		putc('\n', f);
533 	}
534 
535 	ut_ad(dtuple_validate(tuple));
536 }
537 
538 /**************************************************************//**
539 Moves parts of long fields in entry to the big record vector so that
540 the size of tuple drops below the maximum record size allowed in the
541 database. Moves data only from those fields which are not necessary
542 to determine uniquely the insertion place of the tuple in the index.
543 @return own: created big record vector, NULL if we are not able to
544 shorten the entry enough, i.e., if there are too many fixed-length or
545 short fields in entry or the index is clustered */
546 UNIV_INTERN
547 big_rec_t*
dtuple_convert_big_rec(dict_index_t * index,dtuple_t * entry,ulint * n_ext)548 dtuple_convert_big_rec(
549 /*===================*/
550 	dict_index_t*	index,	/*!< in: index */
551 	dtuple_t*	entry,	/*!< in/out: index entry */
552 	ulint*		n_ext)	/*!< in/out: number of
553 				externally stored columns */
554 {
555 	mem_heap_t*	heap;
556 	big_rec_t*	vector;
557 	dfield_t*	dfield;
558 	dict_field_t*	ifield;
559 	ulint		size;
560 	ulint		n_fields;
561 	ulint		local_len;
562 	ulint		local_prefix_len;
563 
564 	if (!dict_index_is_clust(index)) {
565 		return(NULL);
566 	}
567 
568 	if (dict_table_get_format(index->table) < UNIV_FORMAT_B) {
569 		/* up to MySQL 5.1: store a 768-byte prefix locally */
570 		local_len = BTR_EXTERN_FIELD_REF_SIZE
571 			+ DICT_ANTELOPE_MAX_INDEX_COL_LEN;
572 	} else {
573 		/* new-format table: do not store any BLOB prefix locally */
574 		local_len = BTR_EXTERN_FIELD_REF_SIZE;
575 	}
576 
577 	ut_a(dtuple_check_typed_no_assert(entry));
578 
579 	size = rec_get_converted_size(index, entry, *n_ext);
580 
581 	if (UNIV_UNLIKELY(size > 1000000000)) {
582 		fprintf(stderr,
583 			"InnoDB: Warning: tuple size very big: %lu\n",
584 			(ulong) size);
585 		fputs("InnoDB: Tuple contents: ", stderr);
586 		dtuple_print(stderr, entry);
587 		putc('\n', stderr);
588 	}
589 
590 	heap = mem_heap_create(size + dtuple_get_n_fields(entry)
591 			       * sizeof(big_rec_field_t) + 1000);
592 
593 	vector = static_cast<big_rec_t*>(
594 		mem_heap_alloc(heap, sizeof(big_rec_t)));
595 
596 	vector->heap = heap;
597 
598 	vector->fields = static_cast<big_rec_field_t*>(
599 		mem_heap_alloc(
600 			heap,
601 			dtuple_get_n_fields(entry) * sizeof(big_rec_field_t)));
602 
603 	/* Decide which fields to shorten: the algorithm is to look for
604 	a variable-length field that yields the biggest savings when
605 	stored externally */
606 
607 	n_fields = 0;
608 
609 	while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry,
610 							     *n_ext),
611 				      dict_table_is_comp(index->table),
612 				      dict_index_get_n_fields(index),
613 				      dict_table_zip_size(index->table))) {
614 		ulint			i;
615 		ulint			longest		= 0;
616 		ulint			longest_i	= ULINT_MAX;
617 		byte*			data;
618 		big_rec_field_t*	b;
619 
620 		for (i = dict_index_get_n_unique_in_tree(index);
621 		     i < dtuple_get_n_fields(entry); i++) {
622 			ulint	savings;
623 
624 			dfield = dtuple_get_nth_field(entry, i);
625 			ifield = dict_index_get_nth_field(index, i);
626 
627 			/* Skip fixed-length, NULL, externally stored,
628 			or short columns */
629 
630 			if (ifield->fixed_len
631 			    || dfield_is_null(dfield)
632 			    || dfield_is_ext(dfield)
633 			    || dfield_get_len(dfield) <= local_len
634 			    || dfield_get_len(dfield)
635 			    <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
636 				goto skip_field;
637 			}
638 
639 			savings = dfield_get_len(dfield) - local_len;
640 
641 			/* Check that there would be savings */
642 			if (longest >= savings) {
643 				goto skip_field;
644 			}
645 
646 			/* In DYNAMIC and COMPRESSED format, store
647 			locally any non-BLOB columns whose maximum
648 			length does not exceed 256 bytes.  This is
649 			because there is no room for the "external
650 			storage" flag when the maximum length is 255
651 			bytes or less. This restriction trivially
652 			holds in REDUNDANT and COMPACT format, because
653 			there we always store locally columns whose
654 			length is up to local_len == 788 bytes.
655 			@see rec_init_offsets_comp_ordinary */
656 			if (ifield->col->mtype != DATA_BLOB
657 			    && ifield->col->len < 256) {
658 				goto skip_field;
659 			}
660 
661 			longest_i = i;
662 			longest = savings;
663 
664 skip_field:
665 			continue;
666 		}
667 
668 		if (!longest) {
669 			/* Cannot shorten more */
670 
671 			mem_heap_free(heap);
672 
673 			return(NULL);
674 		}
675 
676 		/* Move data from field longest_i to big rec vector.
677 
678 		We store the first bytes locally to the record. Then
679 		we can calculate all ordering fields in all indexes
680 		from locally stored data. */
681 
682 		dfield = dtuple_get_nth_field(entry, longest_i);
683 		ifield = dict_index_get_nth_field(index, longest_i);
684 		local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE;
685 
686 		b = &vector->fields[n_fields];
687 		b->field_no = longest_i;
688 		b->len = dfield_get_len(dfield) - local_prefix_len;
689 		b->data = (char*) dfield_get_data(dfield) + local_prefix_len;
690 
691 		/* Allocate the locally stored part of the column. */
692 		data = static_cast<byte*>(mem_heap_alloc(heap, local_len));
693 
694 		/* Copy the local prefix. */
695 		memcpy(data, dfield_get_data(dfield), local_prefix_len);
696 		/* Clear the extern field reference (BLOB pointer). */
697 		memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE);
698 #if 0
699 		/* The following would fail the Valgrind checks in
700 		page_cur_insert_rec_low() and page_cur_insert_rec_zip().
701 		The BLOB pointers in the record will be initialized after
702 		the record and the BLOBs have been written. */
703 		UNIV_MEM_ALLOC(data + local_prefix_len,
704 			       BTR_EXTERN_FIELD_REF_SIZE);
705 #endif
706 
707 		dfield_set_data(dfield, data, local_len);
708 		dfield_set_ext(dfield);
709 
710 		n_fields++;
711 		(*n_ext)++;
712 		ut_ad(n_fields < dtuple_get_n_fields(entry));
713 	}
714 
715 	vector->n_fields = n_fields;
716 	return(vector);
717 }
718 
719 /**************************************************************//**
720 Puts back to entry the data stored in vector. Note that to ensure the
721 fields in entry can accommodate the data, vector must have been created
722 from entry with dtuple_convert_big_rec. */
723 UNIV_INTERN
724 void
dtuple_convert_back_big_rec(dict_index_t * index MY_ATTRIBUTE ((unused)),dtuple_t * entry,big_rec_t * vector)725 dtuple_convert_back_big_rec(
726 /*========================*/
727 	dict_index_t*	index MY_ATTRIBUTE((unused)),	/*!< in: index */
728 	dtuple_t*	entry,	/*!< in: entry whose data was put to vector */
729 	big_rec_t*	vector)	/*!< in, own: big rec vector; it is
730 				freed in this function */
731 {
732 	big_rec_field_t*		b	= vector->fields;
733 	const big_rec_field_t* const	end	= b + vector->n_fields;
734 
735 	for (; b < end; b++) {
736 		dfield_t*	dfield;
737 		ulint		local_len;
738 
739 		dfield = dtuple_get_nth_field(entry, b->field_no);
740 		local_len = dfield_get_len(dfield);
741 
742 		ut_ad(dfield_is_ext(dfield));
743 		ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
744 
745 		local_len -= BTR_EXTERN_FIELD_REF_SIZE;
746 
747 		/* Only in REDUNDANT and COMPACT format, we store
748 		up to DICT_ANTELOPE_MAX_INDEX_COL_LEN (768) bytes
749 		locally */
750 		ut_ad(local_len <= DICT_ANTELOPE_MAX_INDEX_COL_LEN);
751 
752 		dfield_set_data(dfield,
753 				(char*) b->data - local_len,
754 				b->len + local_len);
755 	}
756 
757 	mem_heap_free(vector->heap);
758 }
759 #endif /* !UNIV_HOTBACKUP */
760