~stewart/haildb/trunk

« back to all changes in this revision

Viewing changes to data/data0data.c

  • Committer: Stewart Smith
  • Date: 2010-04-09 07:57:43 UTC
  • Revision ID: stewart@flamingspork.com-20100409075743-jfh1oml3el1uouvh
Embedded InnoDB 1.0.0 released

2009-04-21      The InnoDB Team

        Embedded InnoDB 1.0.0 released

Show diffs side-by-side

added added

removed removed

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