~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/data/data0data.c

Merged in latest plugin-slot-reorg.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/************************************************************************
2
 
SQL data field and tuple
3
 
 
4
 
(c) 1994-1996 Innobase Oy
5
 
 
6
 
Created 5/30/1994 Heikki Tuuri
7
 
*************************************************************************/
8
 
 
9
 
#include "data0data.h"
10
 
 
11
 
#ifdef UNIV_NONINL
12
 
#include "data0data.ic"
13
 
#endif
14
 
 
15
 
#include "rem0rec.h"
16
 
#include "rem0cmp.h"
17
 
#include "page0page.h"
18
 
#include "dict0dict.h"
19
 
#include "btr0cur.h"
20
 
 
21
 
#include <ctype.h>
22
 
 
23
 
#ifdef UNIV_DEBUG
24
 
byte    data_error;     /* data pointers of tuple fields are initialized
25
 
                        to point here for error checking */
26
 
 
27
 
ulint   data_dummy;     /* this is used to fool the compiler in
28
 
                        dtuple_validate */
29
 
#endif /* UNIV_DEBUG */
30
 
 
31
 
/* Some non-inlined functions used in the MySQL interface: */
32
 
void
33
 
dfield_set_data_noninline(
34
 
        dfield_t*       field,  /* in: field */
35
 
        void*           data,   /* in: data */
36
 
        ulint           len)    /* in: length or UNIV_SQL_NULL */
37
 
{
38
 
        dfield_set_data(field, data, len);
39
 
}
40
 
void*
41
 
dfield_get_data_noninline(
42
 
        dfield_t* field)        /* in: field */
43
 
{
44
 
        return(dfield_get_data(field));
45
 
}
46
 
ulint
47
 
dfield_get_len_noninline(
48
 
        dfield_t* field)        /* in: field */
49
 
{
50
 
        return(dfield_get_len(field));
51
 
}
52
 
ulint
53
 
dtuple_get_n_fields_noninline(
54
 
        dtuple_t*       tuple)  /* in: tuple */
55
 
{
56
 
        return(dtuple_get_n_fields(tuple));
57
 
}
58
 
dfield_t*
59
 
dtuple_get_nth_field_noninline(
60
 
        dtuple_t*       tuple,  /* in: tuple */
61
 
        ulint           n)      /* in: index of field */
62
 
{
63
 
        return(dtuple_get_nth_field(tuple, n));
64
 
}
65
 
 
66
 
/*************************************************************************
67
 
Tests if dfield data length and content is equal to the given. */
68
 
 
69
 
ibool
70
 
dfield_data_is_binary_equal(
71
 
/*========================*/
72
 
                                /* out: TRUE if equal */
73
 
        dfield_t*       field,  /* in: field */
74
 
        ulint           len,    /* in: data length or UNIV_SQL_NULL */
75
 
        byte*           data)   /* in: data */
76
 
{
77
 
        if (len != field->len) {
78
 
 
79
 
                return(FALSE);
80
 
        }
81
 
 
82
 
        if (len == UNIV_SQL_NULL) {
83
 
 
84
 
                return(TRUE);
85
 
        }
86
 
 
87
 
        if (0 != ut_memcmp(field->data, data, len)) {
88
 
 
89
 
                return(FALSE);
90
 
        }
91
 
 
92
 
        return(TRUE);
93
 
}
94
 
 
95
 
/****************************************************************
96
 
Returns TRUE if lengths of two dtuples are equal and respective data fields
97
 
in them are equal when compared with collation in char fields (not as binary
98
 
strings). */
99
 
 
100
 
ibool
101
 
dtuple_datas_are_ordering_equal(
102
 
/*============================*/
103
 
                                /* out: TRUE if length and fieds are equal
104
 
                                when compared with cmp_data_data:
105
 
                                NOTE: in character type fields some letters
106
 
                                are identified with others! (collation) */
107
 
        dtuple_t*       tuple1, /* in: tuple 1 */
108
 
        dtuple_t*       tuple2) /* in: tuple 2 */
109
 
{
110
 
        dfield_t*       field1;
111
 
        dfield_t*       field2;
112
 
        ulint           n_fields;
113
 
        ulint           i;
114
 
 
115
 
        ut_ad(tuple1 && tuple2);
116
 
        ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
117
 
        ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
118
 
        ut_ad(dtuple_check_typed(tuple1));
119
 
        ut_ad(dtuple_check_typed(tuple2));
120
 
 
121
 
        n_fields = dtuple_get_n_fields(tuple1);
122
 
 
123
 
        if (n_fields != dtuple_get_n_fields(tuple2)) {
124
 
 
125
 
                return(FALSE);
126
 
        }
127
 
 
128
 
        for (i = 0; i < n_fields; i++) {
129
 
 
130
 
                field1 = dtuple_get_nth_field(tuple1, i);
131
 
                field2 = dtuple_get_nth_field(tuple2, i);
132
 
 
133
 
                if (0 != cmp_dfield_dfield(field1, field2)) {
134
 
 
135
 
                        return(FALSE);
136
 
                }
137
 
        }
138
 
 
139
 
        return(TRUE);
140
 
}
141
 
 
142
 
/*************************************************************************
143
 
Creates a dtuple for use in MySQL. */
144
 
 
145
 
dtuple_t*
146
 
dtuple_create_for_mysql(
147
 
/*====================*/
148
 
                                /* out, own created dtuple */
149
 
        void**  heap,           /* out: created memory heap */
150
 
        ulint   n_fields)       /* in: number of fields */
151
 
{
152
 
        *heap = (void*)mem_heap_create(500);
153
 
 
154
 
        return(dtuple_create(*((mem_heap_t**)heap), n_fields));
155
 
}
156
 
 
157
 
/*************************************************************************
158
 
Frees a dtuple used in MySQL. */
159
 
 
160
 
void
161
 
dtuple_free_for_mysql(
162
 
/*==================*/
163
 
        void*   heap) /* in: memory heap where tuple was created */
164
 
{
165
 
        mem_heap_free((mem_heap_t*)heap);
166
 
}
167
 
 
168
 
/*************************************************************************
169
 
Sets number of fields used in a tuple. Normally this is set in
170
 
dtuple_create, but if you want later to set it smaller, you can use this. */
171
 
 
172
 
void
173
 
dtuple_set_n_fields(
174
 
/*================*/
175
 
        dtuple_t*       tuple,          /* in: tuple */
176
 
        ulint           n_fields)       /* in: number of fields */
177
 
{
178
 
        ut_ad(tuple);
179
 
 
180
 
        tuple->n_fields = n_fields;
181
 
        tuple->n_fields_cmp = n_fields;
182
 
}
183
 
 
184
 
/**************************************************************
185
 
Checks that a data field is typed. */
186
 
static
187
 
ibool
188
 
dfield_check_typed_no_assert(
189
 
/*=========================*/
190
 
                                /* out: TRUE if ok */
191
 
        dfield_t*       field)  /* in: data field */
192
 
{
193
 
        if (dfield_get_type(field)->mtype > DATA_MYSQL
194
 
            || dfield_get_type(field)->mtype < DATA_VARCHAR) {
195
 
 
196
 
                fprintf(stderr,
197
 
                        "InnoDB: Error: data field type %lu, len %lu\n",
198
 
                        (ulong) dfield_get_type(field)->mtype,
199
 
                        (ulong) dfield_get_len(field));
200
 
                return(FALSE);
201
 
        }
202
 
 
203
 
        return(TRUE);
204
 
}
205
 
 
206
 
/**************************************************************
207
 
Checks that a data tuple is typed. */
208
 
 
209
 
ibool
210
 
dtuple_check_typed_no_assert(
211
 
/*=========================*/
212
 
                                /* out: TRUE if ok */
213
 
        dtuple_t*       tuple)  /* in: tuple */
214
 
{
215
 
        dfield_t*       field;
216
 
        ulint           i;
217
 
 
218
 
        if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
219
 
                fprintf(stderr,
220
 
                        "InnoDB: Error: index entry has %lu fields\n",
221
 
                        (ulong) dtuple_get_n_fields(tuple));
222
 
dump:
223
 
                fputs("InnoDB: Tuple contents: ", stderr);
224
 
                dtuple_print(stderr, tuple);
225
 
                putc('\n', stderr);
226
 
 
227
 
                return(FALSE);
228
 
        }
229
 
 
230
 
        for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
231
 
 
232
 
                field = dtuple_get_nth_field(tuple, i);
233
 
 
234
 
                if (!dfield_check_typed_no_assert(field)) {
235
 
                        goto dump;
236
 
                }
237
 
        }
238
 
 
239
 
        return(TRUE);
240
 
}
241
 
 
242
 
/**************************************************************
243
 
Checks that a data field is typed. Asserts an error if not. */
244
 
 
245
 
ibool
246
 
dfield_check_typed(
247
 
/*===============*/
248
 
                                /* out: TRUE if ok */
249
 
        dfield_t*       field)  /* in: data field */
250
 
{
251
 
        if (dfield_get_type(field)->mtype > DATA_MYSQL
252
 
            || dfield_get_type(field)->mtype < DATA_VARCHAR) {
253
 
 
254
 
                fprintf(stderr,
255
 
                        "InnoDB: Error: data field type %lu, len %lu\n",
256
 
                        (ulong) dfield_get_type(field)->mtype,
257
 
                        (ulong) dfield_get_len(field));
258
 
 
259
 
                ut_error;
260
 
        }
261
 
 
262
 
        return(TRUE);
263
 
}
264
 
 
265
 
/**************************************************************
266
 
Checks that a data tuple is typed. Asserts an error if not. */
267
 
 
268
 
ibool
269
 
dtuple_check_typed(
270
 
/*===============*/
271
 
                                /* out: TRUE if ok */
272
 
        dtuple_t*       tuple)  /* in: tuple */
273
 
{
274
 
        dfield_t*       field;
275
 
        ulint           i;
276
 
 
277
 
        for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
278
 
 
279
 
                field = dtuple_get_nth_field(tuple, i);
280
 
 
281
 
                ut_a(dfield_check_typed(field));
282
 
        }
283
 
 
284
 
        return(TRUE);
285
 
}
286
 
 
287
 
#ifdef UNIV_DEBUG
288
 
/**************************************************************
289
 
Validates the consistency of a tuple which must be complete, i.e,
290
 
all fields must have been set. */
291
 
 
292
 
ibool
293
 
dtuple_validate(
294
 
/*============*/
295
 
                                /* out: TRUE if ok */
296
 
        dtuple_t*       tuple)  /* in: tuple */
297
 
{
298
 
        dfield_t*       field;
299
 
        byte*           data;
300
 
        ulint           n_fields;
301
 
        ulint           len;
302
 
        ulint           i;
303
 
        ulint           j;
304
 
 
305
 
        ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
306
 
 
307
 
        n_fields = dtuple_get_n_fields(tuple);
308
 
 
309
 
        /* We dereference all the data of each field to test
310
 
        for memory traps */
311
 
 
312
 
        for (i = 0; i < n_fields; i++) {
313
 
 
314
 
                field = dtuple_get_nth_field(tuple, i);
315
 
                len = dfield_get_len(field);
316
 
 
317
 
                if (len != UNIV_SQL_NULL) {
318
 
 
319
 
                        data = field->data;
320
 
 
321
 
                        for (j = 0; j < len; j++) {
322
 
 
323
 
                                data_dummy  += *data; /* fool the compiler not
324
 
                                                      to optimize out this
325
 
                                                      code */
326
 
                                data++;
327
 
                        }
328
 
                }
329
 
        }
330
 
 
331
 
        ut_a(dtuple_check_typed(tuple));
332
 
 
333
 
        return(TRUE);
334
 
}
335
 
#endif /* UNIV_DEBUG */
336
 
 
337
 
/*****************************************************************
338
 
Pretty prints a dfield value according to its data type. */
339
 
 
340
 
void
341
 
dfield_print(
342
 
/*=========*/
343
 
        dfield_t*       dfield)  /* in: dfield */
344
 
{
345
 
        byte*   data;
346
 
        ulint   len;
347
 
        ulint   mtype;
348
 
        ulint   i;
349
 
 
350
 
        len = dfield_get_len(dfield);
351
 
        data = dfield_get_data(dfield);
352
 
 
353
 
        if (len == UNIV_SQL_NULL) {
354
 
                fputs("NULL", stderr);
355
 
 
356
 
                return;
357
 
        }
358
 
 
359
 
        mtype = dtype_get_mtype(dfield_get_type(dfield));
360
 
 
361
 
        if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
362
 
 
363
 
                for (i = 0; i < len; i++) {
364
 
                        int     c = *data++;
365
 
                        putc(isprint(c) ? c : ' ', stderr);
366
 
                }
367
 
        } else if (mtype == DATA_INT) {
368
 
                ut_a(len == 4); /* only works for 32-bit integers */
369
 
                fprintf(stderr, "%d", (int)mach_read_from_4(data));
370
 
        } else {
371
 
                ut_error;
372
 
        }
373
 
}
374
 
 
375
 
/*****************************************************************
376
 
Pretty prints a dfield value according to its data type. Also the hex string
377
 
is printed if a string contains non-printable characters. */
378
 
 
379
 
void
380
 
dfield_print_also_hex(
381
 
/*==================*/
382
 
        dfield_t*       dfield)  /* in: dfield */
383
 
{
384
 
        byte*   data;
385
 
        ulint   len;
386
 
        ulint   mtype;
387
 
        ulint   i;
388
 
        ibool   print_also_hex;
389
 
 
390
 
        len = dfield_get_len(dfield);
391
 
        data = dfield_get_data(dfield);
392
 
 
393
 
        if (len == UNIV_SQL_NULL) {
394
 
                fputs("NULL", stderr);
395
 
 
396
 
                return;
397
 
        }
398
 
 
399
 
        mtype = dtype_get_mtype(dfield_get_type(dfield));
400
 
 
401
 
        if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
402
 
 
403
 
                print_also_hex = FALSE;
404
 
 
405
 
                for (i = 0; i < len; i++) {
406
 
                        int c = *data++;
407
 
                        if (!isprint(c)) {
408
 
                                print_also_hex = TRUE;
409
 
                                c = ' ';
410
 
                        }
411
 
                        putc(c, stderr);
412
 
                }
413
 
 
414
 
                if (!print_also_hex) {
415
 
 
416
 
                        return;
417
 
                }
418
 
 
419
 
                fputs(" Hex: ", stderr);
420
 
 
421
 
                data = dfield_get_data(dfield);
422
 
 
423
 
                for (i = 0; i < len; i++) {
424
 
                        fprintf(stderr, "%02lx", (ulint)*data);
425
 
 
426
 
                        data++;
427
 
                }
428
 
        } else if (mtype == DATA_INT) {
429
 
                ut_a(len == 4); /* only works for 32-bit integers */
430
 
                fprintf(stderr, "%d", (int)mach_read_from_4(data));
431
 
        } else {
432
 
                ut_error;
433
 
        }
434
 
}
435
 
 
436
 
/*****************************************************************
437
 
Print a dfield value using ut_print_buf. */
438
 
static
439
 
void
440
 
dfield_print_raw(
441
 
/*=============*/
442
 
        FILE*           f,              /* in: output stream */
443
 
        dfield_t*       dfield)         /* in: dfield */
444
 
{
445
 
        ulint   len     = dfield->len;
446
 
        if (len != UNIV_SQL_NULL) {
447
 
                ulint   print_len = ut_min(len, 1000);
448
 
                ut_print_buf(f, dfield->data, print_len);
449
 
                if (len != print_len) {
450
 
                        fprintf(f, "(total %lu bytes)", (ulong) len);
451
 
                }
452
 
        } else {
453
 
                fputs(" SQL NULL", f);
454
 
        }
455
 
}
456
 
 
457
 
/**************************************************************
458
 
The following function prints the contents of a tuple. */
459
 
 
460
 
void
461
 
dtuple_print(
462
 
/*=========*/
463
 
        FILE*           f,      /* in: output stream */
464
 
        dtuple_t*       tuple)  /* in: tuple */
465
 
{
466
 
        ulint           n_fields;
467
 
        ulint           i;
468
 
 
469
 
        n_fields = dtuple_get_n_fields(tuple);
470
 
 
471
 
        fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
472
 
 
473
 
        for (i = 0; i < n_fields; i++) {
474
 
                fprintf(f, " %lu:", (ulong) i);
475
 
 
476
 
                dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
477
 
 
478
 
                putc(';', f);
479
 
        }
480
 
 
481
 
        putc('\n', f);
482
 
        ut_ad(dtuple_validate(tuple));
483
 
}
484
 
 
485
 
/******************************************************************
486
 
Moves parts of long fields in entry to the big record vector so that
487
 
the size of tuple drops below the maximum record size allowed in the
488
 
database. Moves data only from those fields which are not necessary
489
 
to determine uniquely the insertion place of the tuple in the index. */
490
 
 
491
 
big_rec_t*
492
 
dtuple_convert_big_rec(
493
 
/*===================*/
494
 
                                /* out, own: created big record vector,
495
 
                                NULL if we are not able to shorten
496
 
                                the entry enough, i.e., if there are
497
 
                                too many short fields in entry */
498
 
        dict_index_t*   index,  /* in: index */
499
 
        dtuple_t*       entry,  /* in: index entry */
500
 
        ulint*          ext_vec,/* in: array of externally stored fields,
501
 
                                or NULL: if a field already is externally
502
 
                                stored, then we cannot move it to the vector
503
 
                                this function returns */
504
 
        ulint           n_ext_vec)/* in: number of elements is ext_vec */
505
 
{
506
 
        mem_heap_t*     heap;
507
 
        big_rec_t*      vector;
508
 
        dfield_t*       dfield;
509
 
        ulint           size;
510
 
        ulint           n_fields;
511
 
        ulint           longest;
512
 
        ulint           longest_i               = ULINT_MAX;
513
 
        ibool           is_externally_stored;
514
 
        ulint           i;
515
 
        ulint           j;
516
 
 
517
 
        ut_a(dtuple_check_typed_no_assert(entry));
518
 
 
519
 
        size = rec_get_converted_size(index, entry);
520
 
 
521
 
        if (UNIV_UNLIKELY(size > 1000000000)) {
522
 
                fprintf(stderr,
523
 
                        "InnoDB: Warning: tuple size very big: %lu\n",
524
 
                        (ulong) size);
525
 
                fputs("InnoDB: Tuple contents: ", stderr);
526
 
                dtuple_print(stderr, entry);
527
 
                putc('\n', stderr);
528
 
        }
529
 
 
530
 
        heap = mem_heap_create(size + dtuple_get_n_fields(entry)
531
 
                               * sizeof(big_rec_field_t) + 1000);
532
 
 
533
 
        vector = mem_heap_alloc(heap, sizeof(big_rec_t));
534
 
 
535
 
        vector->heap = heap;
536
 
        vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
537
 
                                        * sizeof(big_rec_field_t));
538
 
 
539
 
        /* Decide which fields to shorten: the algorithm is to look for
540
 
        the longest field whose type is DATA_BLOB */
541
 
 
542
 
        n_fields = 0;
543
 
 
544
 
        while (rec_get_converted_size(index, entry)
545
 
               >= ut_min(page_get_free_space_of_empty(
546
 
                                 dict_table_is_comp(index->table)) / 2,
547
 
                         REC_MAX_DATA_SIZE)) {
548
 
 
549
 
                longest = 0;
550
 
                for (i = dict_index_get_n_unique_in_tree(index);
551
 
                     i < dtuple_get_n_fields(entry); i++) {
552
 
 
553
 
                        /* Skip over fields which already are externally
554
 
                        stored */
555
 
 
556
 
                        is_externally_stored = FALSE;
557
 
 
558
 
                        if (ext_vec) {
559
 
                                for (j = 0; j < n_ext_vec; j++) {
560
 
                                        if (ext_vec[j] == i) {
561
 
                                                is_externally_stored = TRUE;
562
 
                                        }
563
 
                                }
564
 
                        }
565
 
 
566
 
                        if (!is_externally_stored) {
567
 
 
568
 
                                dfield = dtuple_get_nth_field(entry, i);
569
 
 
570
 
                                if (dfield->len != UNIV_SQL_NULL
571
 
                                    && dfield->len > longest) {
572
 
 
573
 
                                        longest = dfield->len;
574
 
 
575
 
                                        longest_i = i;
576
 
                                }
577
 
                        }
578
 
                }
579
 
 
580
 
                /* We do not store externally fields which are smaller than
581
 
                DICT_MAX_INDEX_COL_LEN */
582
 
 
583
 
#if DICT_MAX_INDEX_COL_LEN <= REC_1BYTE_OFFS_LIMIT
584
 
# error "DICT_MAX_INDEX_COL_LEN <= REC_1BYTE_OFFS_LIMIT"
585
 
#endif
586
 
 
587
 
                if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
588
 
                    + DICT_MAX_INDEX_COL_LEN) {
589
 
                        /* Cannot shorten more */
590
 
 
591
 
                        mem_heap_free(heap);
592
 
 
593
 
                        return(NULL);
594
 
                }
595
 
 
596
 
                /* Move data from field longest_i to big rec vector;
597
 
                we do not let data size of the remaining entry
598
 
                drop below 128 which is the limit for the 2-byte
599
 
                offset storage format in a physical record. This
600
 
                we accomplish by storing 128 bytes of data in entry
601
 
                itself, and only the remaining part to big rec vec.
602
 
 
603
 
                We store the first bytes locally to the record. Then
604
 
                we can calculate all ordering fields in all indexes
605
 
                from locally stored data. */
606
 
 
607
 
                dfield = dtuple_get_nth_field(entry, longest_i);
608
 
                vector->fields[n_fields].field_no = longest_i;
609
 
 
610
 
                ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
611
 
 
612
 
                vector->fields[n_fields].len = dfield->len
613
 
                        - DICT_MAX_INDEX_COL_LEN;
614
 
 
615
 
                vector->fields[n_fields].data = mem_heap_alloc(
616
 
                        heap, vector->fields[n_fields].len);
617
 
 
618
 
                /* Copy data (from the end of field) to big rec vector */
619
 
 
620
 
                ut_memcpy(vector->fields[n_fields].data,
621
 
                          ((byte*)dfield->data) + dfield->len
622
 
                          - vector->fields[n_fields].len,
623
 
                          vector->fields[n_fields].len);
624
 
                dfield->len = dfield->len - vector->fields[n_fields].len
625
 
                        + BTR_EXTERN_FIELD_REF_SIZE;
626
 
 
627
 
                /* Set the extern field reference in dfield to zero */
628
 
                memset(((byte*)dfield->data)
629
 
                       + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
630
 
                       0, BTR_EXTERN_FIELD_REF_SIZE);
631
 
                n_fields++;
632
 
        }
633
 
 
634
 
        vector->n_fields = n_fields;
635
 
        return(vector);
636
 
}
637
 
 
638
 
/******************************************************************
639
 
Puts back to entry the data stored in vector. Note that to ensure the
640
 
fields in entry can accommodate the data, vector must have been created
641
 
from entry with dtuple_convert_big_rec. */
642
 
 
643
 
void
644
 
dtuple_convert_back_big_rec(
645
 
/*========================*/
646
 
        dict_index_t*   index __attribute__((unused)),  /* in: index */
647
 
        dtuple_t*       entry,  /* in: entry whose data was put to vector */
648
 
        big_rec_t*      vector) /* in, own: big rec vector; it is
649
 
                                freed in this function */
650
 
{
651
 
        dfield_t*       dfield;
652
 
        ulint           i;
653
 
 
654
 
        for (i = 0; i < vector->n_fields; i++) {
655
 
 
656
 
                dfield = dtuple_get_nth_field(entry,
657
 
                                              vector->fields[i].field_no);
658
 
                /* Copy data from big rec vector */
659
 
 
660
 
                ut_memcpy(((byte*)dfield->data)
661
 
                          + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
662
 
                          vector->fields[i].data,
663
 
                          vector->fields[i].len);
664
 
                dfield->len = dfield->len + vector->fields[i].len
665
 
                        - BTR_EXTERN_FIELD_REF_SIZE;
666
 
        }
667
 
 
668
 
        mem_heap_free(vector->heap);
669
 
}
670
 
 
671
 
/******************************************************************
672
 
Frees the memory in a big rec vector. */
673
 
 
674
 
void
675
 
dtuple_big_rec_free(
676
 
/*================*/
677
 
        big_rec_t*      vector) /* in, own: big rec vector; it is
678
 
                                freed in this function */
679
 
{
680
 
        mem_heap_free(vector->heap);
681
 
}