1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2017, 2020, MariaDB Corporation.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /********************************************************************//**
21 @file data/data0data.cc
22 SQL data field and tuple
23 
24 Created 5/30/1994 Heikki Tuuri
25 *************************************************************************/
26 
27 #include "data0data.h"
28 #include "rem0rec.h"
29 #include "rem0cmp.h"
30 #include "page0page.h"
31 #include "page0zip.h"
32 #include "dict0dict.h"
33 #include "btr0cur.h"
34 #include "row0upd.h"
35 
36 #ifdef UNIV_DEBUG
37 /** Dummy variable to catch access to uninitialized fields.  In the
38 debug version, dtuple_create() will make all fields of dtuple_t point
39 to data_error. */
40 ut_d(byte data_error);
41 #endif /* UNIV_DEBUG */
42 
43 /** Trim the tail of an index tuple before insert or update.
44 After instant ADD COLUMN, if the last fields of a clustered index tuple
45 match the default values that were explicitly specified or implied during
46 ADD COLUMN, there will be no need to store them.
47 NOTE: A page latch in the index must be held, so that the index
48 may not lose 'instantness' before the trimmed tuple has been
49 inserted or updated.
50 @param[in]	index	index possibly with instantly added columns */
51 void dtuple_t::trim(const dict_index_t& index)
52 {
53 	ut_ad(n_fields >= index.n_core_fields);
54 	ut_ad(n_fields <= index.n_fields);
55 	ut_ad(index.is_instant());
56 
57 	ulint i = n_fields;
58 	for (; i > index.n_core_fields; i--) {
59 		const dfield_t* dfield = dtuple_get_nth_field(this, i - 1);
60 		const dict_col_t* col = dict_index_get_nth_col(&index, i - 1);
61 		ut_ad(col->is_instant());
62 		ulint len = dfield_get_len(dfield);
63 		if (len != col->def_val.len) {
64 			break;
65 		}
66 
67 		if (len != 0 && len != UNIV_SQL_NULL
68 		    && dfield->data != col->def_val.data
69 		    && memcmp(dfield->data, col->def_val.data, len)) {
70 			break;
71 		}
72 	}
73 
74 	n_fields = i;
75 }
76 
77 /** Compare two data tuples.
78 @param[in] tuple1 first data tuple
79 @param[in] tuple2 second data tuple
80 @return positive, 0, negative if tuple1 is greater, equal, less, than tuple2,
81 respectively */
82 int
83 dtuple_coll_cmp(
84 	const dtuple_t*	tuple1,
85 	const dtuple_t*	tuple2)
86 {
87 	ulint	n_fields;
88 	ulint	i;
89 	int	cmp;
90 
91 	ut_ad(tuple1 != NULL);
92 	ut_ad(tuple2 != NULL);
93 	ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
94 	ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
95 	ut_ad(dtuple_check_typed(tuple1));
96 	ut_ad(dtuple_check_typed(tuple2));
97 
98 	n_fields = dtuple_get_n_fields(tuple1);
99 
100 	cmp = (int) n_fields - (int) dtuple_get_n_fields(tuple2);
101 
102 	for (i = 0; cmp == 0 && i < n_fields; i++) {
103 		const dfield_t*	field1	= dtuple_get_nth_field(tuple1, i);
104 		const dfield_t*	field2	= dtuple_get_nth_field(tuple2, i);
105 		cmp = cmp_dfield_dfield(field1, field2);
106 	}
107 
108 	return(cmp);
109 }
110 
111 /*********************************************************************//**
112 Sets number of fields used in a tuple. Normally this is set in
113 dtuple_create, but if you want later to set it smaller, you can use this. */
114 void
115 dtuple_set_n_fields(
116 /*================*/
117 	dtuple_t*	tuple,		/*!< in: tuple */
118 	ulint		n_fields)	/*!< in: number of fields */
119 {
120 	tuple->n_fields = n_fields;
121 	tuple->n_fields_cmp = n_fields;
122 }
123 
124 /**********************************************************//**
125 Checks that a data field is typed.
126 @return TRUE if ok */
127 static
128 ibool
129 dfield_check_typed_no_assert(
130 /*=========================*/
131 	const dfield_t*	field)	/*!< in: data field */
132 {
133 	if (dfield_get_type(field)->mtype > DATA_MTYPE_CURRENT_MAX
134 	    || dfield_get_type(field)->mtype < DATA_MTYPE_CURRENT_MIN) {
135 
136 		ib::error() << "Data field type "
137 			<< dfield_get_type(field)->mtype
138 			<< ", len " << dfield_get_len(field);
139 
140 		return(FALSE);
141 	}
142 
143 	return(TRUE);
144 }
145 
146 /**********************************************************//**
147 Checks that a data tuple is typed.
148 @return TRUE if ok */
149 static
150 ibool
151 dtuple_check_typed_no_assert(
152 /*=========================*/
153 	const dtuple_t*	tuple)	/*!< in: tuple */
154 {
155 	const dfield_t*	field;
156 	ulint		i;
157 
158 	if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
159 		ib::error() << "Index entry has "
160 			<< dtuple_get_n_fields(tuple) << " fields";
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 
181 #ifdef UNIV_DEBUG
182 /**********************************************************//**
183 Checks that a data field is typed. Asserts an error if not.
184 @return TRUE if ok */
185 ibool
186 dfield_check_typed(
187 /*===============*/
188 	const dfield_t*	field)	/*!< in: data field */
189 {
190 	if (dfield_get_type(field)->mtype > DATA_MTYPE_CURRENT_MAX
191 	    || dfield_get_type(field)->mtype < DATA_MTYPE_CURRENT_MIN) {
192 
193 		ib::fatal() << "Data field type "
194 			<< dfield_get_type(field)->mtype
195 			<< ", len " << dfield_get_len(field);
196 	}
197 
198 	return(TRUE);
199 }
200 
201 /**********************************************************//**
202 Checks that a data tuple is typed. Asserts an error if not.
203 @return TRUE if ok */
204 ibool
205 dtuple_check_typed(
206 /*===============*/
207 	const dtuple_t*	tuple)	/*!< in: tuple */
208 {
209 	const dfield_t*	field;
210 	ulint		i;
211 
212 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
213 
214 		field = dtuple_get_nth_field(tuple, i);
215 
216 		ut_a(dfield_check_typed(field));
217 	}
218 
219 	return(TRUE);
220 }
221 
222 /**********************************************************//**
223 Validates the consistency of a tuple which must be complete, i.e,
224 all fields must have been set.
225 @return TRUE if ok */
226 ibool
227 dtuple_validate(
228 /*============*/
229 	const dtuple_t*	tuple)	/*!< in: tuple */
230 {
231 	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
232 #ifdef HAVE_valgrind
233 	const ulint n_fields = dtuple_get_n_fields(tuple);
234 
235 	for (ulint i = 0; i < n_fields; i++) {
236 		const dfield_t*	field = dtuple_get_nth_field(tuple, i);
237 
238 		if (!dfield_is_null(field)) {
239 			MEM_CHECK_DEFINED(dfield_get_data(field),
240 					  dfield_get_len(field));
241 		}
242 	}
243 #endif /* HAVE_valgrind */
244 	ut_ad(dtuple_check_typed(tuple));
245 
246 	return(TRUE);
247 }
248 #endif /* UNIV_DEBUG */
249 
250 /*************************************************************//**
251 Pretty prints a dfield value according to its data type. */
252 void
253 dfield_print(
254 /*=========*/
255 	const dfield_t*	dfield)	/*!< in: dfield */
256 {
257 	const byte*	data;
258 	ulint		len;
259 	ulint		i;
260 
261 	len = dfield_get_len(dfield);
262 	data = static_cast<const byte*>(dfield_get_data(dfield));
263 
264 	if (dfield_is_null(dfield)) {
265 		fputs("NULL", stderr);
266 
267 		return;
268 	}
269 
270 	switch (dtype_get_mtype(dfield_get_type(dfield))) {
271 	case DATA_CHAR:
272 	case DATA_VARCHAR:
273 		for (i = 0; i < len; i++) {
274 			int	c = *data++;
275 			putc(isprint(c) ? c : ' ', stderr);
276 		}
277 
278 		if (dfield_is_ext(dfield)) {
279 			fputs("(external)", stderr);
280 		}
281 		break;
282 	case DATA_INT:
283 		ut_a(len == 4); /* only works for 32-bit integers */
284 		fprintf(stderr, "%d", (int) mach_read_from_4(data));
285 		break;
286 	default:
287 		ut_error;
288 	}
289 }
290 
291 /*************************************************************//**
292 Pretty prints a dfield value according to its data type. Also the hex string
293 is printed if a string contains non-printable characters. */
294 void
295 dfield_print_also_hex(
296 /*==================*/
297 	const dfield_t*	dfield)	/*!< in: dfield */
298 {
299 	const byte*	data;
300 	ulint		len;
301 	ulint		prtype;
302 	ulint		i;
303 	ibool		print_also_hex;
304 
305 	len = dfield_get_len(dfield);
306 	data = static_cast<const byte*>(dfield_get_data(dfield));
307 
308 	if (dfield_is_null(dfield)) {
309 		fputs("NULL", stderr);
310 
311 		return;
312 	}
313 
314 	prtype = dtype_get_prtype(dfield_get_type(dfield));
315 
316 	switch (dtype_get_mtype(dfield_get_type(dfield))) {
317 		ib_id_t	id;
318 	case DATA_INT:
319 		switch (len) {
320 			ulint	val;
321 		case 1:
322 			val = mach_read_from_1(data);
323 
324 			if (!(prtype & DATA_UNSIGNED)) {
325 				val &= ~0x80U;
326 				fprintf(stderr, "%ld", (long) val);
327 			} else {
328 				fprintf(stderr, "%lu", (ulong) val);
329 			}
330 			break;
331 
332 		case 2:
333 			val = mach_read_from_2(data);
334 
335 			if (!(prtype & DATA_UNSIGNED)) {
336 				val &= ~0x8000U;
337 				fprintf(stderr, "%ld", (long) val);
338 			} else {
check()339 				fprintf(stderr, "%lu", (ulong) val);
340 			}
341 			break;
342 
343 		case 3:
344 			val = mach_read_from_3(data);
345 
check()346 			if (!(prtype & DATA_UNSIGNED)) {
347 				val &= ~0x800000U;
348 				fprintf(stderr, "%ld", (long) val);
349 			} else {
logHistogram()350 				fprintf(stderr, "%lu", (ulong) val);
351 			}
logHistogram(logHistogram const & o)352 			break;
353 
354 		case 4:
355 			val = mach_read_from_4(data);
356 
357 			if (!(prtype & DATA_UNSIGNED)) {
358 				val &= ~0x80000000;
359 				fprintf(stderr, "%ld", (long) val);
reset()360 			} else {
361 				fprintf(stderr, "%lu", (ulong) val);
362 			}
363 			break;
364 
365 		case 6:
366 			id = mach_read_from_6(data);
367 			fprintf(stderr, IB_ID_FMT, id);
368 			break;
369 
370 		case 7:
count(int b)371 			id = mach_read_from_7(data);
total(int b)372 			fprintf(stderr, IB_ID_FMT, id);
373 			break;
374 		case 8:
375 			id = mach_read_from_8(data);
376 			fprintf(stderr, IB_ID_FMT, id);
377 			break;
378 		default:
379 			goto print_hex;
380 		}
381 		break;
382 
383 	case DATA_SYS:
384 		switch (prtype & DATA_SYS_PRTYPE_MASK) {
385 		case DATA_TRX_ID:
386 			id = mach_read_from_6(data);
387 
388 			fprintf(stderr, "trx_id " TRX_ID_FMT, id);
389 			break;
390 
391 		case DATA_ROLL_PTR:
392 			id = mach_read_from_7(data);
393 
394 			fprintf(stderr, "roll_ptr " TRX_ID_FMT, id);
395 			break;
396 
397 		case DATA_ROW_ID:
398 			id = mach_read_from_6(data);
399 
400 			fprintf(stderr, "row_id " TRX_ID_FMT, id);
401 			break;
402 
403 		default:
404 			goto print_hex;
405 		}
406 		break;
407 
408 	case DATA_CHAR:
409 	case DATA_VARCHAR:
410 		print_also_hex = FALSE;
statistic(statistic const & o)411 
412 		for (i = 0; i < len; i++) {
413 			int c = *data++;
414 
statistic(double minv,double maxv,double meanv,uint64_t sc,double sd)415 			if (!isprint(c)) {
416 				print_also_hex = TRUE;
417 
418 				fprintf(stderr, "\\x%02x", (unsigned char) c);
419 			} else {
getMean()420 				putc(c, stderr);
getMax()421 			}
422 		}
423 
424 		if (dfield_is_ext(dfield)) {
425 			fputs("(external)", stderr);
426 		}
427 
reset()428 		if (!print_also_hex) {
429 			break;
430 		}
431 
432 		data = static_cast<const byte*>(dfield_get_data(dfield));
433 		/* fall through */
434 
435 	case DATA_BINARY:
436 	default:
437 print_hex:
438 		fputs(" Hex: ",stderr);
scaleDown(double f)439 
440 		for (i = 0; i < len; i++) {
441 			fprintf(stderr, "%02x", *data++);
442 		}
443 
formatHist(char unit)444 		if (dfield_is_ext(dfield)) {
445 			fputs("(external)", stderr);
446 		}
447 	}
448 }
449 
450 /*************************************************************//**
451 Print a dfield value using ut_print_buf. */
452 static
453 void
454 dfield_print_raw(
455 /*=============*/
timeStat()456 	FILE*		f,		/*!< in: output stream */
457 	const dfield_t*	dfield)		/*!< in: dfield */
458 {
459 	ulint	len	= dfield_get_len(dfield);
460 	if (!dfield_is_null(dfield)) {
461 		ulint	print_len = ut_min(len, static_cast<ulint>(1000));
462 		ut_print_buf(f, dfield_get_data(dfield), print_len);
463 		if (len != print_len) {
464 			fprintf(f, "(total %lu bytes%s)",
465 				(ulong) len,
466 				dfield_is_ext(dfield) ? ", external" : "");
467 		}
468 	} else {
469 		fputs(" SQL NULL", f);
470 	}
471 }
472 
clearEventFlags()473 /**********************************************************//**
474 The following function prints the contents of a tuple. */
475 void
476 dtuple_print(
477 /*=========*/
478 	FILE*		f,	/*!< in: output stream */
479 	const dtuple_t*	tuple)	/*!< in: tuple */
480 {
481 	ulint		n_fields;
482 	ulint		i;
483 
484 	n_fields = dtuple_get_n_fields(tuple);
485 
486 	fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
487 
488 	for (i = 0; i < n_fields; i++) {
489 		fprintf(f, " %lu:", (ulong) i);
490 
491 		dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
492 
493 		putc(';', f);
494 		putc('\n', f);
495 	}
496 
497 	ut_ad(dtuple_validate(tuple));
498 }
499 
500 /** Print the contents of a tuple.
501 @param[out]	o	output stream
reset()502 @param[in]	field	array of data fields
503 @param[in]	n	number of data fields */
504 void
505 dfield_print(
506 	std::ostream&	o,
507 	const dfield_t*	field,
508 	ulint		n)
509 {
510 	for (ulint i = 0; i < n; i++, field++) {
511 		const void*	data	= dfield_get_data(field);
512 		const ulint	len	= dfield_get_len(field);
513 
514 		if (i) {
515 			o << ',';
516 		}
517 
518 		if (dfield_is_null(field)) {
519 			o << "NULL";
520 		} else if (dfield_is_ext(field)) {
521 			ulint	local_len = len - BTR_EXTERN_FIELD_REF_SIZE;
522 			ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
523 
524 			o << '['
525 			  << local_len
526 			  << '+' << BTR_EXTERN_FIELD_REF_SIZE << ']';
527 			ut_print_buf(o, data, local_len);
528 			ut_print_buf_hex(o, static_cast<const byte*>(data)
529 					 + local_len,
530 					 BTR_EXTERN_FIELD_REF_SIZE);
531 		} else {
532 			o << '[' << len << ']';
533 			ut_print_buf(o, data, len);
534 		}
535 	}
536 }
537 
538 /** Print the contents of a tuple.
~blockPartitionedTimer()539 @param[out]	o	output stream
540 @param[in]	tuple	data tuple */
541 void
542 dtuple_print(
543 	std::ostream&	o,
544 	const dtuple_t*	tuple)
545 {
546 	const ulint	n	= dtuple_get_n_fields(tuple);
547 
548 	o << "TUPLE (info_bits=" << dtuple_get_info_bits(tuple)
549 	  << ", " << n << " fields): {";
550 
551 	dfield_print(o, tuple->fields, n);
552 
553 	o << "}";
554 }
555 
556 /**************************************************************//**
557 Moves parts of long fields in entry to the big record vector so that
558 the size of tuple drops below the maximum record size allowed in the
559 database. Moves data only from those fields which are not necessary
560 to determine uniquely the insertion place of the tuple in the index.
561 @return own: created big record vector, NULL if we are not able to
562 shorten the entry enough, i.e., if there are too many fixed-length or
563 short fields in entry or the index is clustered */
564 big_rec_t*
counter()565 dtuple_convert_big_rec(
566 /*===================*/
567 	dict_index_t*	index,	/*!< in: index */
568 	upd_t*		upd,	/*!< in/out: update vector */
569 	dtuple_t*	entry,	/*!< in/out: index entry */
570 	ulint*		n_ext)	/*!< in/out: number of
571 				externally stored columns */
572 {
573 	mem_heap_t*	heap;
574 	big_rec_t*	vector;
575 	dfield_t*	dfield;
576 	dict_field_t*	ifield;
577 	ulint		size;
578 	ulint		n_fields;
579 	ulint		local_prefix_len;
580 
581 	if (!dict_index_is_clust(index)) {
582 		return(NULL);
583 	}
584 
585 	const ulint local_len = index->table->get_overflow_field_local_len();
586 
587 	ut_a(dtuple_check_typed_no_assert(entry));
588 
589 	size = rec_get_converted_size(index, entry, *n_ext);
590 
591 	if (UNIV_UNLIKELY(size > 1000000000)) {
592 		ib::warn() << "Tuple size is very big: " << size;
593 		fputs("InnoDB: Tuple contents: ", stderr);
594 		dtuple_print(stderr, entry);
595 		putc('\n', stderr);
596 	}
597 
598 	heap = mem_heap_create(size + dtuple_get_n_fields(entry)
599 			       * sizeof(big_rec_field_t) + 1000);
600 
601 	vector = big_rec_t::alloc(heap, dtuple_get_n_fields(entry));
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_page_size(index->table))) {
614 
615 		ulint			i;
616 		ulint			longest		= 0;
617 		ulint			longest_i	= ULINT_MAX;
618 		byte*			data;
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_LOCAL_STORED_MAX_SIZE) {
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 (!DATA_BIG_COL(ifield->col)) {
657 				goto skip_field;
658 			}
659 
660 			longest_i = i;
661 			longest = savings;
662 
663 skip_field:
664 			continue;
665 		}
666 
667 		if (!longest) {
668 			/* Cannot shorten more */
669 
670 			mem_heap_free(heap);
671 
672 			return(NULL);
673 		}
674 
675 		/* Move data from field longest_i to big rec vector.
676 
677 		We store the first bytes locally to the record. Then
678 		we can calculate all ordering fields in all indexes
679 		from locally stored data. */
680 
681 		dfield = dtuple_get_nth_field(entry, longest_i);
682 		ifield = dict_index_get_nth_field(index, longest_i);
683 		local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE;
684 
685 		vector->append(
686 			big_rec_field_t(
687 				longest_i,
688 				dfield_get_len(dfield) - local_prefix_len,
689 				static_cast<char*>(dfield_get_data(dfield))
690 				+ local_prefix_len));
691 
692 		/* Allocate the locally stored part of the column. */
693 		data = static_cast<byte*>(mem_heap_alloc(heap, local_len));
694 
695 		/* Copy the local prefix. */
696 		memcpy(data, dfield_get_data(dfield), local_prefix_len);
697 		/* Clear the extern field reference (BLOB pointer). */
698 		memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE);
699 
700 		dfield_set_data(dfield, data, local_len);
701 		dfield_set_ext(dfield);
702 
703 		n_fields++;
704 		(*n_ext)++;
705 		ut_ad(n_fields < dtuple_get_n_fields(entry));
706 
707 		if (upd && !upd->is_modified(longest_i)) {
708 
709 			DEBUG_SYNC_C("ib_mv_nonupdated_column_offpage");
710 
711 			upd_field_t	upd_field;
712 			upd_field.field_no = unsigned(longest_i);
713 			upd_field.orig_len = 0;
714 			upd_field.exp = NULL;
715 			upd_field.old_v_val = NULL;
716 			dfield_copy(&upd_field.new_val,
717 				    dfield->clone(upd->heap));
718 			upd->append(upd_field);
719 			ut_ad(upd->is_modified(longest_i));
720 
721 			ut_ad(upd_field.new_val.len
722 			      >= BTR_EXTERN_FIELD_REF_SIZE);
723 			ut_ad(upd_field.new_val.len == local_len);
724 			ut_ad(upd_field.new_val.len == dfield_get_len(dfield));
725 		}
726 	}
727 
728 	ut_ad(n_fields == vector->n_fields);
729 
730 	return(vector);
731 }
732 
kmp_stats_list()733 /**************************************************************//**
734 Puts back to entry the data stored in vector. Note that to ensure the
735 fields in entry can accommodate the data, vector must have been created
736 from entry with dtuple_convert_big_rec. */
737 void
738 dtuple_convert_back_big_rec(
739 /*========================*/
740 	dict_index_t*	index MY_ATTRIBUTE((unused)),	/*!< in: index */
741 	dtuple_t*	entry,	/*!< in/out: entry whose data was put to vector */
742 	big_rec_t*	vector)	/*!< in, own: big rec vector; it is
743 				freed in this function */
744 {
745 	big_rec_field_t*		b	= vector->fields;
746 	const big_rec_field_t* const	end	= b + vector->n_fields;
747 
748 	for (; b < end; b++) {
749 		dfield_t*	dfield;
750 		ulint		local_len;
751 
752 		dfield = dtuple_get_nth_field(entry, b->field_no);
753 		local_len = dfield_get_len(dfield);
754 
755 		ut_ad(dfield_is_ext(dfield));
756 		ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
757 
758 		local_len -= BTR_EXTERN_FIELD_REF_SIZE;
759 
760 		/* Only in REDUNDANT and COMPACT format, we store
761 		up to DICT_ANTELOPE_MAX_INDEX_COL_LEN (768) bytes
762 		locally */
763 		ut_ad(local_len <= DICT_ANTELOPE_MAX_INDEX_COL_LEN);
764 
765 		dfield_set_data(dfield,
766 				(char*) b->data - local_len,
767 				b->len + local_len);
768 	}
769 
770 	mem_heap_free(vector->heap);
771 }
772 
773 /** Allocate a big_rec_t object in the given memory heap, and for storing
774 n_fld number of fields.
775 @param[in]	heap	memory heap in which this object is allocated
776 @param[in]	n_fld	maximum number of fields that can be stored in
777 			this object
778 
779 @return the allocated object */
780 big_rec_t*
781 big_rec_t::alloc(
782 	mem_heap_t*	heap,
783 	ulint		n_fld)
784 {
785 	big_rec_t*	rec = static_cast<big_rec_t*>(
786 		mem_heap_alloc(heap, sizeof(big_rec_t)));
787 
788 	new(rec) big_rec_t(n_fld);
789 
790 	rec->heap = heap;
791 	rec->fields = static_cast<big_rec_field_t*>(
792 		mem_heap_alloc(heap,
793 			       n_fld * sizeof(big_rec_field_t)));
794 
795 	rec->n_fields = 0;
796 	return(rec);
797 }
798 
799 /** Create a deep copy of this object.
800 @param[in,out]	heap	memory heap in which the clone will be created
801 @return	the cloned object */
802 dfield_t*
803 dfield_t::clone(mem_heap_t* heap) const
804 {
805 	const ulint size = len == UNIV_SQL_NULL ? 0 : len;
806 	dfield_t* obj = static_cast<dfield_t*>(
807 		mem_heap_alloc(heap, sizeof(dfield_t) + size));
808 
809 	ut_ad(len != UNIV_SQL_DEFAULT);
810 	obj->ext  = ext;
811 	obj->len  = len;
812 	obj->type = type;
813 	obj->spatial_status = spatial_status;
814 
815 	if (len != UNIV_SQL_NULL) {
816 		obj->data = obj + 1;
817 		memcpy(obj->data, data, len);
818 	} else {
819 		obj->data = 0;
820 	}
821 
822 	return(obj);
823 }
824