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